Qt实现Kermit协议(二)

3 实现

3.1 Kermit

该模块是Kermit协议实现类。

3.1.1 Kermit定义

/*
      |<------Included in CHECK----->|
      |                |
    +------+-----+-----+------+------+- - -+-------+
    | MARK | LEN | SEQ | TYPE | DATA | CHECK |<terminator>
    +------+-----+-----+------+------+- - -+-------+
             |            |
             |<--LEN-32 characters-->|

    MARK A real control character, usually CTRL-A.
    LEN One character, length of remainder of packet + 32, max 95
    SEQ One character, packet sequence number + 32, modulo 64
    TYPE One character, an uppercase letter
    CHECK One, two, or three characters, as negotiated.
    <terminator> Any control character required for reading the packet.
*/

class Kermit
{
public:
    Kermit();

    enum Code {
        NUL = 0x00,
        MARK = 0x01,
        END_CHAR = 0x0D
    };

    enum Type {
        S = 0x53, //Send Initiation. I’m about to send files, and here are my parameters.
        F = 0x46, //File Header, the name of the file which is about to come.
        D = 0x44, //File Data
        Z = 0x5A, //End of File.
        B = 0x42, //Break Transmission, end of transaction.
        Y = 0x59, //Acknowledgment
        N = 0x4E, //Negative Acknowledgment
        E = 0x45  //Fatal Error
    };

    enum Size {
        MinLen = 3,
        MaxLen = 94,
        MaxSize = MaxLen + 6
    };

    enum State {
        SSNUL = 0,
        SSINT = 1,
        SSFIL = 2,
        SSDAT = 3,
        SSEND = 4,
        SSBRK = 5
    };

protected:
    virtual void on_init(int seq, const char* data, int size);
    virtual void on_file_header(int seq, const char* data, int size);
    virtual void on_data(int seq, const char* data, int size);
    virtual void on_end(int seq, const char* data, int size);
    virtual void on_break(int seq, const char* data, int size);
    virtual void on_ack(int seq, const char* data, int size);
    virtual void on_nack(int seq, const char* data, int size);
    virtual void on_error(int seq, const char* data, int size);

    virtual int write(char const *data, int size) = 0;
    virtual int read(char *data, int size) = 0;
    virtual char getc() = 0;

protected:
    void send_init();
    void send_data(int n, const char* data, int len);
    void send_end(int n);
    void send_break(int n);
    void send_ack(int n);
    void send_nack(int n);

    bool recv_packet();
    void resend();

    int encode(char a, char* data);
    int decode(const char* data, char& a);
private:
    int tochar(int x) { return x + 32; }
    int unchar(int x) { return int(x - 32); }
    int ctl(int x) { return x^64; }
    int check(const char* p);
    int check(int sum, const char* begin, const char* end);
    int spack(char type, int n, const char* data, int len);
    bool send_packet(const char* data, int size);
private:
    char data_[MaxSize];
    int maxl = MaxLen;
    int time = 10;
    int npad = 0;
    int padc = 64;
    int eol = END_CHAR;
    char qctl = '#';
    int last_size = 0;
};

虚函数列表:

  • on_init 处理发送标识包(包括最大数据包size/time/npad/padc/eol/qctl)并发送出应答包。
  • on_file_header 处理文件头包
  • on_data 处理文件数据包
  • on_end 处理文件结束包
  • on_break 处理中断传输包
  • on_ack 处理应答包
  • on_nack 处理否定应答包
  • on_error 处理错误包
  • write 向串口写数据
  • read 从串口读数据
  • getc 从串口读取一个字符

函数列表:

  • send_init 发送发送标识包
  • send_data 发送文件数据包
  • send_end 发送文件结束包
  • send_break 发送中断传输包
  • send_ack 发送应答包
  • send_nack 发送否定应答包
  • recv_packet 接收数据包并分发处理
  • resend 重发数据
  • encode 编码数据
  • decode 解码数据

3.1.2 Kermit实现

  • on_init/on_file_header/on_data/on_end/on_break/on_ack/on_nack/on_error
void Kermit::on_init(int /*seq*/, const char* data, int size)
{
    if(size > 0)
        maxl  = unchar(data[0]);
    if(size > 1)
        time  = unchar(data[1]);
    if(size > 2)
        npad  = unchar(data[2]);
    if(size > 3)
        padc  = unchar(data[3]);
    if(size > 4)
        eol  = unchar(data[4]);
    if(size > 5)
        qctl  = data[5];

    char d[6];
    d[0] = tochar(maxl);
    d[1] = tochar(time);
    d[2] = tochar(npad);
    d[3] = tochar(padc);
    d[4] = tochar(eol);
    d[5] = qctl;

    spack(Y, 0, d, sizeof (d));
}

void Kermit::on_file_header(int seq, const char* data, int size) {
    std::cout << "on_file_header(" << seq << "," << std::string(data, size) << std::endl;
}

void Kermit::on_data(int seq, const char* data, int size) {
    std::cout << "on_data(" << seq << "," << std::string(data, size) << std::endl;
}

void Kermit::on_end(int seq, const char* data, int size) {
    std::cout << "on_end(" << seq << "," << std::string(data, size) << std::endl;
}

void Kermit::on_break(int seq, const char* data, int size) {
    std::cout << "on_break(" << seq << "," << std::string(data, size) << std::endl;
}

void Kermit::on_ack(int seq, const char* data, int size)
{
    if(seq != 0)
        return;

    if(size > 0)
        maxl  = unchar(data[0]);
    if(size > 1)
        time  = unchar(data[1]);
    if(size > 2)
        npad  = unchar(data[2]);
    if(size > 3)
        padc  = unchar(data[3]);
    if(size > 4)
        eol  = unchar(data[4]);
    if(size > 5)
        qctl  = data[5];
}

void Kermit::on_nack(int seq, const char* data, int size) {
    std::cout << "on_nack(" << seq << "," << std::string(data, size) << std::endl;
}

void Kermit::on_error(int seq, const char* data, int size) {
    std::cout << "on_error(" << seq << "," << std::string(data, size) << std::endl;
}
  • send_init/send_data/send_end/send_break/send_ack/send_nack/resend
void Kermit::send_init()
{
    char data[6];
    data[0] = tochar(maxl);
    data[1] = tochar(time);
    data[2] = tochar(npad);
    data[3] = tochar(padc);
    data[4] = tochar(eol);
    data[5] = qctl;
    spack(S, 0, data, sizeof (data));
}

void Kermit::send_data(int n, const char* data, int len) {
    spack(D, n, data, len);
}

void Kermit::send_end(int n) {
    spack(Z, n, nullptr, 0);
}

void Kermit::send_break(int n) {
    spack(B, n, nullptr, 0);
}
void Kermit::send_ack(int n) {
    spack(Y, n, nullptr, 0);
}

void Kermit::send_nack(int n) {
    spack(N, n, nullptr, 0);
}

void Kermit::resend() {
    send_packet(data_, last_size);
}

构造对应类型数据包并发送。

  • recv_packet
bool Kermit::recv_packet()
{
    char ch = getc();
    if(ch != MARK)
        return false;

    ch = getc();
    int length = unchar(ch);
    if(length < MinLen)
        return false;

    //SEQ  TYPE DATA CHECK <terminator>
    std::vector<char> data(length + 1, 0);
    if(read(data.data(), data.size()) != static_cast<int>(data.size()))
        return false;

    if(data.back() != eol)
        return false;

    uint16_t  old_check = unchar(data.at(data.size() - 2));
    uint16_t  new_check = check(ch, data.data(), data.data() + data.size() - 2);
    if(old_check != new_check)
        return false;

    char type = data[1];
    if(type == S)
        on_init(unchar(data[0]), data.data() + 2, data.size() - 4);
    else if(type == F)
        on_file_header(unchar(data[0]), data.data() + 2, data.size() - 4);
    else if(type == D)
        on_data(unchar(data[0]), data.data() + 2, data.size() - 4);
    else if(type == Z)
        on_end(unchar(data[0]), data.data() + 2, data.size() - 4);
    else if(type == Y)
        on_ack(unchar(data[0]), data.data() + 2, data.size() - 4);
    else if(type == N)
        on_nack(unchar(data[0]), data.data() + 2, data.size() - 4);
    else if(type == E)
        on_error(unchar(data[0]), data.data() + 2, data.size() - 4);
    return true;
}

接收数据包并校验,根据对应类型调用处理相应处理函数。

  • encode/decode
int Kermit::encode(char a, char* data)
{
    int a7 = a & 127;
    int size = 0;
    if (a7 < 32 || a7 == 127)
    {
        data[size++] = qctl;
        a = ctl(a);
    }
    else if (a7 == qctl)
    {
        data[size++] = qctl;
    }
    data[size++] = a;
    data[size] = '\0';
    return size;
}

int Kermit::decode(const char* data, char &b)
{
    const char *d = data;
    int a = *d++;
    if(a == qctl) {
        a = *d++;
        int a7 = a & 127;
        if(a7 < 62 && a7 < 96)
            a = ctl(a);
    }
    b = a;
    return d - data;
}

对数据进行编码/解码。
Qt实现Kermit协议(一)Qt实现Kermit协议(三)

相关推荐

  1. Qt实现Kermit协议()

    2024-04-02 19:12:02       17 阅读
  2. Qt实现Kermit协议(五)

    2024-04-02 19:12:02       13 阅读
  3. Qt实现Kermit协议(六)

    2024-04-02 19:12:02       23 阅读
  4. QTQT实现TCP协议

    2024-04-02 19:12:02       30 阅读
  5. Qt实现XYModem协议(三)

    2024-04-02 19:12:02       13 阅读
  6. Qt实现XYModem协议(七)

    2024-04-02 19:12:02       13 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-02 19:12:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-02 19:12:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-02 19:12:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-02 19:12:02       20 阅读

热门阅读

  1. C++中重载和重写的区别

    2024-04-02 19:12:02       12 阅读
  2. 解密SFP和QSFP:你需要知道的一切

    2024-04-02 19:12:02       16 阅读
  3. Git使用

    2024-04-02 19:12:02       15 阅读
  4. 每日一题: 为什么要使用Spring?

    2024-04-02 19:12:02       14 阅读
  5. 【数据库】[MYSQL][面试题]常见数据库知识整理

    2024-04-02 19:12:02       15 阅读
  6. C++ map 常用部分

    2024-04-02 19:12:02       14 阅读
  7. 【zml】vp9 vp8

    2024-04-02 19:12:02       11 阅读
  8. 简单的HTML

    2024-04-02 19:12:02       13 阅读
  9. 东方财富网股票数据爬虫

    2024-04-02 19:12:02       13 阅读
  10. Windows 11 中Docker的安装教程

    2024-04-02 19:12:02       18 阅读
  11. terraform读取tfvars的变量

    2024-04-02 19:12:02       14 阅读