Qt实现XYModem协议(三)

1 概述

  XMODEM协议是一种使用拨号调制解调器的个人计算机通信中广泛使用的异步文件运输协议。这种协议以128字节块的形式传输数据,并且每个块都使用一个校验和过程来进行错误检测。使用循环冗余校验的与XMODEM相应的一种协议称为XMODEM-CRC。还有一种是XMODEM-1K,它以1024字节一块来传输数据。YMODEM也是一种XMODEM的实现。它包括XMODEM-1K的所有特征,另外在一次单一会话期间为发送一组文件,增加了批处理文件传输模式。

本文利用C++实现XYModem-1K协议,并利用Qt串口类QSerialPort实现数据读写。

3 实现

3.2 XModem

该模块定义和实现了XModem协议。

3.2.1 XModem定义

class XModem : public Modem
{
public:
    XModem()
    : id_(0x0)
    {}

    enum Code {
        NUL = 0x00,
        SOH = 0x01,
        STX = 0x02,
        EOT = 0x04,
        ACK = 0x06,
        NAK = 0x15,
        CAN = 0x18,
        C   = 0x43,
        MAX = 0xff
    };
    enum Size {
        CODE = 1,
        ID = 2,
        SIZE1 = 128,
        SIZE2 = 1024,
        CRC16 = 2,
        FRAME_HEAD  = CODE + ID, //1 + 2
        FRAME_SIZE1 = FRAME_HEAD + SIZE1 + CRC16,// 3 + 128 + 2 = 133
        FRAME_SIZE2 = FRAME_HEAD + SIZE2 + CRC16, // 3 + 1024 + 2 = 1029
        DATA_SIZE1 = FRAME_SIZE1 -1,
        DATA_SIZE2 = FRAME_SIZE2 -1
    };
protected:
    virtual uint8_t get_code(bool isWait = true) = 0;

    bool tx_send(uint8_t *data, uint32_t size, int max_count = 5);
    bool tx_eot();
    bool tx_end();
    
    void tx_code(Code code);
    uint8_t wait_start(int max_count = 5);
    void tx_cancel();

    uint8_t not_id(uint8_t id) { return 0xFF - id; }
    void next_id() { id_ = next_id(id_); } 
private:
    uint8_t next_id(uint8_t id) { return (id + 1) % 0x100; }
    void do_send(uint8_t const* data, uint16_t size);
    void do_eot() { tx_code(EOT); }
    void do_c() { tx_code(C); }
private:
    uint8_t id_;
    uint8_t frame_[FRAME_SIZE2];
};

纯虚接口:

  • get_code 获取操作码Code

函数列表:

  • tx_send 发送数据
  • tx_eot 判断发送是否结束。
  • tx_code 发送操作码
  • wait_start 发送C码等待接收码SOH或STX 码
  • tx_cancel 发送取消帧
  • not_id 返回id的反码
  • next_id 返回下一id

3.2.2 XModem实现

3.2.2.1 tx_send
bool XModem::tx_send(uint8_t *data, uint32_t size, int max_count)
{
    if(size > SIZE2)
        return false;

    do_send(data, size);
    for(int i = 0; i < max_count; i++)
    {
        uint8_t code = get_code();
        if(code == MAX)
            break;
        else if(code == NAK)
            do_send(data, size);
        else if(code == ACK)
        {
            next_id();
            return true;
        }
    }
    return false;
}

函数流程:

  • 发送数据
  • 获取操作码
  • 获得无效操作码,函数返回
  • 获得重传操作码NAK,重传数据
  • 获得确认操作码ACK,说明发送成功,设置下一id
  • 如果一直返回NAK,重复max_count次后函数返回
3.2.2.2 tx_eot
bool XModem::tx_eot()
{
    do_eot();
    uint8_t code = get_code();
    if(code == NAK)
    {
        std::cout << "need next file" << std::endl;
        do_eot();
        if(get_code() == ACK)
            return true;
    }
    else if(code == ACK)
    {
        return true;
    }
    return false;
}

函数流程:

  • 发送EOT码
  • 获取操作码
  • 如果是NAK码,重新发送EOT码
  • 如何是ACK码,成功返回,否则失败返回
3.2.2.3 tx_cancel
void XModem::tx_cancel()
{
    uint8_t frame[] = { CAN, CAN, CAN, CAN, CAN };
    write(frame, sizeof(frame));
}

函数流程:

  • 构造包含5个CAN取消码帧
  • 发送取消码帧
3.2.2.4 tx_code
void XModem::tx_code(Code code)
{
    uint8_t frame = code;
    write(&frame, CODE);
}

函数流程:

  • 构造包含1个操作码帧
  • 发送操作码帧
3.2.2.5 wait_start
uint8_t XModem::wait_start(int max_count)
{
    for(int i = 0; i < max_count; i++)
    {
        do_c();
        uint8_t code = get_code(false);
        if(code != MAX)
            return code;
    }
    return MAX;
}

函数流程:

  • 发送C开始码
  • 获取操作码,如果获取到有效操作码,则返回
  • 获取无效操作码重复max_count次上述操作后返回
3.2.2.6 do_send
void XModem::do_send(uint8_t const* data, uint16_t size)
{
    uint16_t data_size = SIZE2;

    memset(frame_, 0, sizeof(frame_));

    frame_[1] = id_;
    frame_[2] =  not_id(id_);

    if(size > SIZE1)
        frame_[0] = STX;
    else
    {
        frame_[0] = SOH;
        data_size = SIZE1;
    }

    memcpy(&frame_[FRAME_HEAD], data, size);
    memset(&frame_[FRAME_HEAD + size], 0x1A, data_size - size);

    uint16_t crc = crc16(&frame_[FRAME_HEAD], data_size);
    frame_[FRAME_HEAD + data_size] = (uint8_t)(crc >> 8);
    frame_[FRAME_HEAD + data_size + 1] = (uint8_t)(crc >> 0);

    write(frame_, (data_size == SIZE1 ? FRAME_SIZE1 : FRAME_SIZE2));
}

函数流程:

相关推荐

  1. Qt实现XYModem协议()

    2024-04-21 04:14:02       12 阅读
  2. Qt实现XYModem协议(七)

    2024-04-21 04:14:02       11 阅读
  3. Qt实现XYModem协议(八)

    2024-04-21 04:14:02       13 阅读
  4. 串口通信----XModem协议协议(文件传输)

    2024-04-21 04:14:02       20 阅读
  5. QTQT实现TCP协议

    2024-04-21 04:14:02       28 阅读
  6. Qt实现Kermit协议(二)

    2024-04-21 04:14:02       16 阅读

最近更新

  1. TCP协议是安全的吗?

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

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

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

    2024-04-21 04:14:02       18 阅读

热门阅读

  1. 面向对象——类与对象

    2024-04-21 04:14:02       13 阅读
  2. stable diffusion本地部署教程

    2024-04-21 04:14:02       15 阅读
  3. AIOS: LLM Agent Operating System

    2024-04-21 04:14:02       15 阅读
  4. uni-app vue3 setup 如何使用 onShow

    2024-04-21 04:14:02       14 阅读
  5. SpringBoot Jar包在CentOS7.x上注册成服务并开机启动

    2024-04-21 04:14:02       12 阅读
  6. Python 一个简化地址解析的利器 addressrec

    2024-04-21 04:14:02       14 阅读
  7. js DOM模型常用方法复盘梳理

    2024-04-21 04:14:02       15 阅读
  8. 信号塔(树形dp)

    2024-04-21 04:14:02       8 阅读
  9. Ocr识别

    2024-04-21 04:14:02       12 阅读
  10. 音视频、网络带宽等常用概念详解

    2024-04-21 04:14:02       12 阅读
  11. pytorch中模型训练的学习率动态调整

    2024-04-21 04:14:02       11 阅读
  12. web应用使用spring

    2024-04-21 04:14:02       16 阅读
  13. 2024.4.20力扣每日一题——组合总和

    2024-04-21 04:14:02       11 阅读
  14. 游戏中的伤害类型

    2024-04-21 04:14:02       11 阅读