nix.long 于 2017-08-14
重新整理在csdn
文章目录
STM32/Dvm项目移植FatFS时,使用W25Qxx Flash做文件系统,不能使用USB或其他外设接口直接进行文件拷贝, 因此移植Ymodem协议用于向Flash下载文件.
0.Ymodem介绍
Ymodem在嵌入式项目中,常用于文件下载和IAP在线编程.
Ymodem协议是一种发送并等待的协议。即发送方发送一个数据包以后,都要等待接收方的确认,分为Ymodem-1K和Ymodem-G两种子格式.
- YModem-1K用1024字节信息块传输取代标准的128字节传输,数据的发送回使用CRC校验,保证数据传输的正确性。它每传输一个信息块数据时,就会等待接收端回应ACK信号,接收到回应后,才会继续传输下一个信息块,保证数据已经全部接收。
- YModem-g传输形式与YModem-1K差不多,但是它去掉了数据的CRC校验码,同时在发送完一个数据块信息后,它不会等待接收端的ACK信号,而直接传输下一个数据块。正是它没有涉及错误校验,才使得它的传输速度比YModem-1K来得块。
一般情况使用YModem-1K传输,而平时所说的YModem也是指的是YModem-1k.
1. Ymodem的协议格式
传输信号定义:
1.0 帧格式
START CC ~CC Data[128]:[1024] CRCH CRCL
一个Ymodem数据帧由帧头(START CC ~CC)、数据体和帧尾三部分构成:
1) START : 如果是SOH,表示这帧数据体长度为128 Bytes; 为STX, 标识这帧数据体长度为1024 Bytes.(总长恒为128+5 或者1024+5)
2) CC : 表示帧序号, 从0开始增加,超过255后,又从0开始计数
3) ~CC为: CC的反码. 一起进行帧序的有效性判断
4) CRCH/CRCL分别为CRC16校验的高低字节, 校验多项式定义为: CRC16-CCITT/x16+x12+x5+1. CRC只针对数据体计算,不包含帧头
1.1 传输起始帧
SOH 00 FF filename 00 filezise 00 NUL[00] CRCH CRCL
- 传输起始帧以SOH信号开始,数据体长度128
- 序号为0,数据体已filename开始,为ascii码格式字符串,然后紧跟00表示文件名结束;之后紧跟filesize,将每位转换为16进制的ascii码,后续到数据体结尾完全补00。如文件名123.c 长度 1024字节(0x400), 那么在数据体的格式为: 31 32 33 2E 63 00 34 30 30 00 … 后续用00 补充
- filename和filesize构成最长不超过128字节
1.2 数据帧
SIG CC ~CC Data[128]:[1024] <1A...> CRCH CRCL
在实际传输中, 数据帧根据文件大小不同分多种情况处理。假设文件大小为X.M=X/1024,N=X%1024.因为Ymodem-1K只有128和1024两种数据帧大小:
- 如果M大于0:那么这M帧按照每帧1024字节传输,SIG为信号STX
- 如果N大于128小于1024:SIG为STX,这帧按照1024字节传输,不足1024字节部分使用 1A 补全
- 如果N小于等于128:SIG为SOH,这帧按照128字节传输,不足128字节使用1A补全
1.3 结束帧
SOH 00 FF 128x[00] CRCH CRCL
结束帧类似起始帧,序号为00, 但数据体为空(全0x00).
1.4 要点
- 帧长恒为133(SOH开始)或1029(STX开始)之一
- 起始/结束帧序号一定为0x00(反码0xff)
- 数据帧序号从1开始计数, 但超过255后,会从0开始重新计数
- 发送方实际发送的数据size是大于等于实际文件大小的, 接收方善用filesize和1A进行实际size接收
2. Ymodem的传输过程
1. 接收方发送信号C启动传输会话,然后进入等待(SOH)状态,如果没有回应,就会超时退出
2. 发送方开始时处于等待C过程中。收到C以后,发送携带文件名和文件长度的起始帧(SOH)数据包开始信号。进入等待(ACK)状态
3. 接收方收到SOH起始帧以后,CRC校验满足,则发送ACK。发送方接收到ACK,又进入等待“文件传输开启”信号,即重新进入等待“C”的状态
4. 接收方发送C,表示可以开始数据的传输
5. 于是发送方发送数据帧、接收方接收到后回复ACK,如此循环进行数据接收(过程中双方因为任何异常,如人工终端、通讯故障等都可能造成传输中断).
6. 文件传输完毕后,发送方发送EOT信号,接收方收到后,回应NAK
7. 发送方再次发送EOT,接收方回应ACK。
8. 接收方发送C,准备再次文件传输
9. 如果是单次文件传输,发送方发送传输结束帧,接收方回应ACK后,整个传输会话结束
3. Ymodem向STM32的移植
这里没有根据Ymodem协议进行全新实现,而是选用了ST官方 STM32F0xx_IAP demo的一个Ymodem实现进行修改移植. 它原本用于IAP的, 这里修改为即可适用普通文件传输也可以用于IAP.
3.1. 原ST代码下载 原代码在对filesize处理时存在bug,将最后一帧多余的1A也认作文件内容了
3.2. 重构代码为两部分:ANSI-C部分和Porting移植层,ANSI-C部分可以方便移植到各个平台,而只需要重新实现Porting层的接口即可
3.3 重构后的目录结构:
src: 为ANSI-C部分, 方便向各平台移植
inc: porting头文件,包含需要移植实现的接口函数
3.4 接口函数
/*********************************************************
* The Porting APIs Should Be Implemented
********************************************************/
extern unsigned int SerialKeyPressed(unsigned char *key);
extern void SerialPutChar(unsigned char c);
extern unsigned char SerialReadByte(void);
extern void ymodem_init(void);
extern unsigned int ymodem_get_receive_maxsize(void);
extern unsigned int ymodem_get_transmit_size(void);
//0 - success ; -1 - fail
extern int ymodem_recv_start_cb(const char * filename, const unsigned int filesize);
extern int ymodem_recv_processing_cb(const unsigned char * buffer, const unsigned int buff_size);
extern int ymodem_recv_end_cb(void);
3.5 在项目的接口实现