optical/NxFuncs/comm/xmodem.h
2025-09-04 09:45:08 +08:00

158 lines
5.9 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifndef __XMODEM_H__
#define __XMODEM_H__
#include "config.h"
/*
Xmodem 协议是一种串口通信中广泛用到的异步文件传输协议。
分为标准Xmodem和1k-Xmodem两种前者以128字节块的形式传输数据后者字节块为1k即1024字节并且每个块都使用一个校验和过程来进行错误检测。
在校验过程中如果接收方关于一个块的校验和与它在发送方的校验和相同时,接收方就向发送方发送一个确认字节(ACK)。
由于Xmodem需要对每个块都进行认可这将导致性能有所下降特别是延时比较长的场合这种协议显得效率更低。
除了Xmodem还有YmodemZmodem协议。他们的协议内容和Xmodem类似不同的是Ymodem允许批处理文件传输效率更高Zmodem则是改进的了Xmodem它只需要对损坏的块进行重发其它正确的块不需要发送确认字节减少了通信量。
标准Xmodem协议每个数据包含有128字节数据帧格式如下
________________________________________________________________
| | | | | |
| SOH | 信息包序号 | 信息包序号的补码 | 数据区段 | 校验和 |
|_____|_____________|___________________|___________|___________|
| | | | | |
| 1B | 1B | 1B | 128B | 1B |
|_____|_____________|___________________|___________|___________|
SOH0x01是启动传输的字符
包序号从1--255如果大于255则从头再开始
数据段在标准Xmodem协议中是128字节如果传送的文件不是128的整数倍那么最后一个数据包的有效内容肯定小于帧长不足的部分需要用CTRL-Z(0x1A)来填充。
校验和是数据区段的累加和校验
XModem 扩展协议每个数据包含有128字节数据帧格式如下
________________________________________________________________
| | | | | |
| SOH | 信息包序号 | 信息包序号的补码 | 数据区段 | CRC校验 |
|_____|_____________|___________________|___________|___________|
| | | | | |
| 1B | 1B | 1B | 128B | 2B |
|_____|_____________|___________________|___________|___________|
CRC校验是数据区段的16位CRC校验MSB存放
X16+X12+X5+X0
1K-Xmodem每个数据包含有1024字节数据帧格式如下
________________________________________________________________
| | | | | |
| STX | 信息包序号 | 信息包序号的补码 | 数据区段 | CRC校验 |
|_____|_____________|___________________|___________|___________|
| | | | | |
| 1B | 1B | 1B | 1024B | 2B |
|_____|_____________|___________________|___________|___________|
传输协议:
1. 启动传输
传输由接收方启动,方法是向发送方发送"C"或者NAK (注意哦这里提到的NAK是用来启动传输的。以下我们会看到NAK还可以用来对数据产生重传的机制)。
接收方发送NAK信号表示接收方打算用累加和校验发送字符"C"则表示接收方想打算使用CRC校验。
2. 传输过程
当接收方发送的第一个"C"或者NAK到达发送方发送方认为可以发送第一个数据包传输已经启动。
发送方接着应该将数据以每次128字节的数据加上包头包号包号补码末尾加上校验和或CRC校验打包成帧格式传送。
发送方发了第一包后就等待接收方的确认字节ACK收到接收方传来的ACK确认就认为数据包被接收方正确接收并且接收方要求发送方继续发送下一个包
如果发送方收到接收方传来的NAK(这里NAK用来告诉发送方重传不是用来启动传输)字节,则表示接收方请求重发刚才的数据包。
如果发送方收到接收方传来的CAN字节则表示接收方请求无条件停止传输。
3. 结束传输
如果发送方正常传输完全部数据,需要结束传输,正常结束需要发送方发送 EOT 字节通知接收方接收方回以ACK进行确认。
当然接收方也可强制停止传输,当接收方发送 CAN 字节给发送方表示接收方想无条件停止传输发送方收到CAN后不需要再发送 EOT确认。
4. 特殊处理
虽然数据包是以 SOH 来标志一个信息包的起始的,但在 SOH 位置上如果出现EOT则表示数据传输结束再也没有数据传过来。
接收方首先应确认数据包序号的完整性通过对数据包序号取补然后和数据包序号的补码异或结果为0表示正确结果不为0则发送NAK请求重传。
接收方确认数据包序号正确后,然后检查是否期望的序号。如果不是期望得到的数据包序号,说明发生严重错误,应该发送一个 CAN 来中止传输。
如果接收到的数据包的包序号和前一包相同,那么接收方会忽略这个重复包,向发送方发出 ACK ,准备接收下一个包。
接收方确认了信息包序号的完整性和是正确期望的后,只对 128 字节的数据区段进行算术和校验结果与帧中最后一个字节的校验和或2字节的CRC比较相同发送 ACK不同发送 NAK。
5校验的说明
Xmodem协议支持2种校验和它们是累加和与CRC校验。
当接收方一开始启动传输时发送的是NAK表示它希望以累加和方式校验。
当接收方一开始启动传输时发送的是字符“C”表示它希望以CRC方式校验。
Xmodem要求发送方支持CRC的就必须同时支持累加和。
如果发送方只支持累加和而接收方用字符“C”来启动那么发送方只要不管它当接收方继续发送“C”三次后都没收到应答就自动会改为发送NAK发送方可能不支持CRC校验需要改为累加和校验方式
发送方收到NAK就赶紧发送数据包响应
*/
#define XMODEM_SOH 0x01 // Xmodem数据包头
#define XMODEM_STX 0x02 // 1K-Xmodem数据包头
#define XMODEM_EOT 0x04 // 传输结束
#define XMODEM_ACK 0x06 // 认可响应,如:数据包正确接收
#define XMODEM_NAK 0x15 // 不认可响应
#define XMODEM_CAN 0x18 // 取消传输
#define XMODEM_CTRLZ 0x1A // 填充数据
//-----------------------------------------------
#define XMODEM_F_SIZE 128
#define XMODEM1K_F_SIZE 1024
#define XMODEM_HEAD_SIZE 3
#define XMODEM_CHECK_SIZE 1
#define XMODEM_CRC_SIZE 2
#define XMODEM_FRAME (XMODEM_F_SIZE+XMODEM_HEAD_SIZE+XMODEM_CHECK_SIZE)
#define XMODEM1K_FRAME (XMODEM1K_F_SIZE+XMODEM_HEAD_SIZE+XMODEM_CHECK_SIZE)
#define XMODEM_FRAME_C (XMODEM_F_SIZE+XMODEM_HEAD_SIZE+XMODEM_CRC_SIZE)
#define XMODEM1K_FRAME_C (XMODEM1K_F_SIZE+XMODEM_HEAD_SIZE+XMODEM_CRC_SIZE)
//-----------------------------------------------
typedef struct
{
void (*InitSave)(void);
int (*SaveData)(int, u8 *, int, u32);
int (*XmodemOutBuff)(u8 *, int);
int (*XmodemInBuff)(u8 *, int);
int (*XmodemGetInBuffLen)(void);
int (*XmodemCleanBuff)(void);
int savedsize;
int xpktlen;
}XmodemCtrl;
//-----------------------------------------------
int XmodemReceive(XmodemCtrl * pCtrl);
void OutDebugBufInfo(void);
//-----------------------------------------------
#endif