好记性不如铅笔头

网络通讯

Ymodem协议简单实现笔记

X/Y/Zmodem是一个非常古老的协议了,主要用于文件传输,这里简单的笔记下相关内容。

相关概念:
ASCII:这是最快的传输协议,但只能传送文本文件。
Xmodem:这种古老的传输协议速度较慢,但由于使用了CRC错误侦测方法,传输的准确率可高达99.6%。
Ymodem:这是Xmodem的改良版,使用了1024位区段传送,速度比Xmodem要快。
Zmodem:Zmodem采用了串流式(streaming)传输方式,传输速度较快,而且还具有自动改变区段大小和断点续传、快速错误侦测等功能。这是目前最流行的文件传输协议。

相关参考源码:
https://packages.ubuntu.com/zh-cn/source/xenial/lrzsz
http://freshmeat.sourceforge.net/projects/lrzsz/

X/Ymodem协议:
http://pauillac.inria.fr/~doligez/zmodem/ymodem.txt
Zmodem协议:
http://gallium.inria.fr/~doligez/zmodem/zmodem.txt

由于协议比较古老,这里以terminal向device发送1个文件为例,简单笔记下Ymodem-1K的发送数据流程。

Ymodem-1K流程图

Ymodem-1K报文格式

#define YMODEM_CMD_SOH					0x01		// 128字节数据包
#define YMODEM_CMD_STX					0x02		// 1024字节数据包
#define YMODEM_CMD_EOT					0x04		// 结束传输
#define YMODEM_CMD_ACK					0x06		// 回应
#define YMODEM_CMD_NAK					0x15		// 不回应
#define YMODEM_CMD_CA					0x18		// 传输中止
#define YMODEM_CMD_C					0x43		// 请求数据包
#define YMODEM_CONTENT_END_CHAR			0x1A        // 数据包结尾填充

typedef struct __PACKED
{
	uint8_t   cmd;
	uint8_t   frame_index;
	uint8_t   negation_frame_index;
	uint8_t   frame_content[1024];
	uint16_t  frame_crc16;
}ymodem_frame_1024_s;

typedef struct __PACKED
{
	uint8_t   cmd;
	uint8_t   frame_index;
	uint8_t   negation_frame_index;
	uint8_t   frame_content[128];
	uint16_t  frame_crc16;
}ymodem_frame_128_s;

其中:
cmd只能为SOH或者STX
frame_crc16 = crc16(frame_content, sizeof(frame_content)),即crc16只对frame_content进行校验。
frame_index = ~negation_frame_index,即frame_index和negation_frame_index互为bit取反。

Ymodem-1K报文细节

报文1,单字节报文,内容为[C],在没有收到terminal报文前定时发送。

报文2,封装报文,字段描述如下:
cmd只能为SOH或者STX(协议规定只能是SOH,但是SecureCRT扩展了协议)
frame_index = 0 ; negation_frame_index = 0xFF
frame_content内容为:
[字符串格式文件名称][0x0][字符串格式文件大小][0x20][0xXX 补全128/1024字节]

报文3,双字节报文,内容为[ACK,C]

报文4,封装报文,字段描述如下:
cmd只能为SOH或者STX
frame_index从1开始递增,negation_frame_index = ~frame_index
frame_content内容为:
[报文内容] 或者 [报文内容][0x1A][0xXX 补全128/1024字节]

报文5,单字节报文,内容为[ACK]

报文6,单字节报文,内容为[EOT]

报文7,单字节报文,内容为[NAK]

报文8,单字节报文,内容为[EOT]

报文9,双字节报文,内容为[ACK,C]

报文10,封装报文,字段描述如下:
cmd只能为SOH或者STX
frame_index = 0 ; negation_frame_index = 0xFF
frame_content内容为:
[0xXX 补全128/1024字节]

报文11,单字节报文,内容为[ACK]

报文12,双字节报文,内容为[CA,CA]

报文13,单字节报文,内容为[ACK]

报文15,双字节报文,内容为[CA,CA]

报文17,双字节报文,内容为[NAK]

Leave a Reply

3 + 16 =

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据