常用于嵌入式IAP串口升级。
一、什么是Xmodem协议?
XMODEM协议是一种串口通信中广泛用到的异步文件传输协议。分为标准Xmodem和1k-Xmodem两种,前者以128字节块的形式传输数据,后者字节块为1k即1024字节,并且每个块都使用一个校验和过程来进行错误检测。在校验过程中如果接收方关于一个块的校验和与它在发送方的校验和相同时,接收方就向发送方发送一个确认字节(ACK)。由于Xmodem需要对每个块都进行认可,这将导致性能有所下降,特别是延时比较长的场合,这种协议显得效率更低。
除了Xmodem,还有Ymodem,Zmodem协议。他们的协议内容和Xmodem类似,但是进行了拓展。
- Ymodem允许批处理文件传输,效率更高;
- Zmodem则是改进的了Xmodem,它只需要对损坏的块进行重发,其它正确的块不需要发送确认字节。减少了通信量。
二、Xmodem协议相关控制字符
命令字符 | 命令码 |
---|---|
SOH | 0x01 (Modem数据头) |
STX | 0x02 |
EOT | 0x04 (发送结束) |
ACK | 0x06 (应答) |
NAK | 0x15 (非应答) |
CAN | 0x18 (取消发送) |
CTRLZ | 0x1A |
三、Xmodem数据包格式
标准Xmodem协议(每个数据包含有128字节数据)帧格式
| SOH | 信息包序号 | 信息包序号的补码 | 数据区段(128个字节) | 校验和 |
标准XModem传输流程
1k-Xmodem 只是在Xmodem协议基础上,进行了数据包长度的改进,从原有的128字节更改为1k字节。同时每个信息报的第一个字节的SOH变成了STX,STX定义为
,能有效的加快数据传输速率。
四、校验方式和传输流程
4.1 校验方式说明
Xmodem协议支持2种校验和,它们是累加和与CRC校验。
- 当接收方一开始启动传输时发送的是NAK,表示它希望以累加和方式校验;
- 当接收方一开始启动传输时发送的是字符“C”,表示它希望以CRC方式校验。
可能有人会问,接收方想怎么校验发送方都得配合吗,难道发送方必须都支持累加和校验和CRC校验?事实上Xmodem要求支持CRC的就必须同时支持累加和。如果发送方只支持累加和,而接收方用字符“C”来启动,那么发送方只要不管它,当接收方继续发送“C”,三次后都没收到应答,就自动会改为发送 NAK;因为它已经明白发送方可能不支持CRC校验,现在接收方改为累加和校验和发送方通讯。发送方收到NAK就赶紧发送数据包响应。
4.2 启动传输
传输由接收方启动,方法是向发送方发送”C”或者NAK (注意哦,这里提到的NAK是用来启动传输的;以后我们会看到NAK还可以用来对数据产生重传的机制)。
- 接收方发送NAK信号表示接收方打算用累加和校验;
- 发送字符”C”则表示接收方想打算使用CRC校验
举例,接收方要求发送方以校验和方式发送时以NAK来请求,发送方将对此做出应答。如下图:
4.3 传输过程
当接收方发送的第一个”C”或者NAK到达发送方,发送方认为可以发送第一个数据包,传输已经启动。发送方接着应该将数据以每次128字节的数据加上包头,包号,包号补码,末尾加上校验和,打包成帧格式传送。
发送方发了第一包后就等待接收方的确认字节ACK,收到接收方传来的ACK确认,就认为数据包被接收方正确接收,并且接收方要求发送方继续发送下一个包;如果发送方收到接收方传来的NAK (这里,NAK用来告诉发送方重传,不是用来启动传输) 字节,则表示接收方请求重发刚才的数据包;
如果发送方收到接收方传来的CAN字节,则表示接收方请求无条件停止传输。
4.4 结束传输
如果发送方正常传输完全部数据,需要结束传输,正常结束需要发送方发送EOT 字节通知接收方。接收方回以ACK进行确认。当然接收方也可强制停止传输,当接收方发送CAN 字节给发送方,表示接收方想无条件停止传输,发送方收到CAN后,不需要再发送 EOT确认(因为接收方已经不想理它了,呵呵)。
4.5 特殊处理
虽然数据包是以 SOH 来标志一个信息包的起始的,但在 SOH 位置上如果出现EOT则表示数据传输结束,再也没有数据传过来。
- 接收方首先应确认数据包序号的完整性,通过对数据包序号取补,然后和数据包序号的补码异或,结果为0表示正确,结果不为0则发送NAK请求重传。
- 接收方确认数据包序号正确后,然后检查是否期望的序号。如果不是期望得到的数据包序号,说明发生严重错误,应该发送一个 CAN 来中止传输。
- 如果接收到的数据包的包序号和前一包相同,那么接收方会忽略这个重复包,向发送方发出 ACK ,准备接收下一个包。
- 接收方确认了信息包序号的完整性和是正确期望的后,只对 128 字节的数据区段进行算术和校验,结果与帧中最后一个字节(算术校验和)比较,相同发送 ACK,不同发送 NAK。
4.6 数据包特殊说明
对于标准Xmodem协议来说,如果传送的文件不是128的整数倍,那么最后一个数据包的有效内容肯定小于帧长,不足的部分需要用CTRL- Z(0x1A)来填充。这里可能有人会问,我数据末尾是0x1A呢?
- 如果传送的是文本文件,那么接收方对于接收的内容是很容易识别的,因为Xmodem协议定义的CTRL-Z(0x1A) 不是前128个ascii码中的通用可见字母等字符( 0x1A 对应 SUB[替补] )。
- 如果传送的是二进制文件,例如 bootloader 工程生成的.bin文件。假如我的.bin文件最末尾是0x1A,那如何区分填充的0x1A?
- 例如像excel文件等,由于其数据内部会有些结构表示各个字段长度等,所以不会读取多余的填充字符。
- 而.bin文件,一般是不做区分的,它直接把填充码直接同样写入flash
- Flash写入是要擦除的,如果想利用填充码位置的Flash,只能用一次性,不然会损坏到IAP升级的APP文件
- Mcu其实不会把填充码当作代码来执行(没有跳转到该位置的代码块)。
- 如果使用 1k-Xmodem ,最极端的情况下,也就浪费Mcu不到1K flash;(对于芯片Flash容量小,即扇区也小,干脆直接用Xmodem升级)
五、补充知识:128个字符的ASCII码表
由于上面的文本文件,对编码格式有疑惑的,建议重新看一下128字符的ASCII码表。基础ascii码值最大值是0x7f=127,扩展ascii码值最大值是0xFF=255。
文章的链接为:128个字符的ASIIC码表
六、补充知识:CRC16校验的实现
对CRC校验有疑惑、不了解的,可以看这篇博文:CRC校验算法原理分析
七、代码实例
这里先放一个官方例程:ST官方的IAP + Ymodem代码;提取码为:aan9
再放一个超级终端方便调试升级:超级终端(支持win10);提取码为:3ejn
7.1 Ymodem协议
从上述Xmodem知识讲解后,如果你去查询 Ymodem协议概念 ,你会发现及其相似。这里我放我的实例;根据官方IAP升级例程进行简化(阉割),方便理解;芯片是Stm32F407vgt6,支持多串口任选升级 的代码:非标准Ymodem协议的IAP升级。
标准Ymodem的特点,就是相对Xmodem能进行批文件传输。Ymodem支持文件传输,体现在YModem的起始帧并不直接传输文件的数据,而是将文件名与文件的大小放在数据帧中传输会先发。
且数据传输结束方法要进行确认:
- 数据传输完毕后,发送方发EOT,第一次接收方以NAK应答,准备二次确认。
- 发送方收到NAK后,重发EOT,接收方第二次收到结束符,就以ACK应答。
- 最后接收方再发送一个’C’,发送方在没有第二个文件要传输的情况下,发送数据
SOH 00 FF 00~00(共128个) CRCH CRCL
- 接收方应答ACK后,正式结束数据传输。
这样的话,每次建立连接,标准Ymodem一次能传输多文件,即批文件传输。
Ps: 如果应用在嵌入式Bootloader的话,基本都只传一个文件,且要压缩Bootloader程序大小;即接收方嵌入式固件为非标准的Ymodem协议。
7.2 Xmodem & Ymodem
根据 7.1 的实例,能够通过Ymodem协议进行IAP升级;Xmodem 和 Ymodem 极其相似,直接切换成 Xmodem协议 进行升级能不能成呢?
当然是理所当然地报错了!那么极其相似,但到底差别在哪里?
- 文件传输的第一个数据包
- Ymodem支持文件传输,体现在了传输文件第一个包;YModem的起始帧并不直接传输文件的数据,而是将文件名与文件的大小放在数据帧中传输会先发;
- 而Xmodem是直接传输数据的
- 数据包报文中的 Byte2 和 Byte3,一个是数据包数,一个是数据包数补码
- Ymodem协议,他的数据包数是0x00开始(因为要多接一个文件信息)
- Xmodem协议,它的数据包数是0x01开始的(= =|||)
通过上述的总结,因为Ymodem与Xmodem很相似,可以根据上面的不同点稍微改一下,就能得到 基于Xmodem协议的IAP升级 代码: 基于Xmodem协议的IAP升级。(残留一些Ymodem的代码,想精简可去掉)
- 两者带来的差别:Flash的擦除
- Ymodem协议,第一包数据可以知道文件名、文件大小,所以不必要直接连接上就擦除Flash;
- 可以第一包(文件)数据不符合要求就不擦除旧APP的Flash
- 因此连上超级终端,不升级,设备是不会变成砖的(未擦除)
- Xmodem协议,不清楚文件,因此一般会连接上后直接擦除旧APP存储的Flash;
- 因为擦除程序在连接成功后就做,那么如果连上后放弃升级,该设备自然就会变成砖(就我现在写的那个);
- 当然也可以改进成在确实收到(识别)第一包数据包后,再擦除Flash;就能实现类似Ymodem的效果
- Ymodem协议,第一包数据可以知道文件名、文件大小,所以不必要直接连接上就擦除Flash;
7.3 文件加密(小技巧)
通过上述的Xmodem、Ymodem进行文件传输时,有时候需要文件加密安全一点。我举一个自己在用的例子:
- 做一个简易的上位机,把bin文件拖进去;由于bin文件就是二进制文件,可以将其 异或 某条字符串,不断循环直至 整个文件异或成 新的文件
- 通过协议传输后,把获取到的数据,又重新异或一遍,这样的话,数据就会解密(数据异或两次就会变回原来的数据),再写入Flash
- 上位机的字符串加密要可改写非固定,这样就能实现简单文件加密传输拉!!
Ps: 上面我的代码例程就有夹杂解密的,可以去掉;不过我代码的Ymodem没加CRC校验;Xmodem例程就加了CRC校验。实测加了校验,对实际传输的时间影响不大。