赞
踩
XMODEM协议是一种使用拨号调制解调器的个人计算机通信中广泛使用的异步文件运输协议。这种协议以128字节块的形式传输数据,并且每个块都使用一个校验和过程来进行错误检测。使用循环冗余校验的与XMODEM相应的一种协议称为XMODEM-CRC。还有一种是XMODEM-1K,它以1024字节一块来传输数据。YMODEM也是一种XMODEM的实现。它包括XMODEM-1K的所有特征,另外在一次单一会话期间为发送一组文件,增加了批处理文件传输模式。
本文利用C++实现XYModem-1K协议,并利用Qt串口类QSerialPort实现数据读写。
该模块定义和实现了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];
};
纯虚接口:
函数列表:
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;
}
函数流程:
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;
}
函数流程:
void XModem::tx_cancel()
{
uint8_t frame[] = { CAN, CAN, CAN, CAN, CAN };
write(frame, sizeof(frame));
}
函数流程:
void XModem::tx_code(Code code)
{
uint8_t frame = code;
write(&frame, CODE);
}
函数流程:
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;
}
函数流程:
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));
}
函数流程:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。