还剩15页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
研究Xmodem协议必看的11个问题原文地力上^type=v5_onelabel=rela_prevarticleXmodem协议作为串口数据传输重要的方式之一,恐怕只有做过bootloader的才有机会接触一下,网上有关该协议的内容要么是英语要么讲解不具体笔者以前写bootloader时研究过Ik-Xmodem,参考了不少相关资料这里和大家交流一下我对Xmodem的理解,多多指教!
1.Xmodem协议是什么?XMODEM协议是一种串口通信中广泛用到的异步文献传输协议分为标准Xmodem和Ik-Xmodem两种,前者以128字节块的形式传输数据,后者字节块为1k即1024字节,并且每个块都使用一个校验和过程来进行错误检测在校验过程中假如接受方关于一个块的校验和与它在发送方的校验和相同时,接受方就向发送方发送一个确认字节(ACK)o由于Xmodem需要对每个块都进行认可,这将导致性能有所下降,特别是延时比较长的场合,这种协议显得效率更低除了Xmodem,尚有Ymodem,Zmodem协议他们的协议内容和Xmodem类似,不同的是Ymodem允许批解决文献传输,效率更高;Zmodem则是改善的了Xmodem,它只需要对损坏的块进行重发,其它对的的块不需要发送确认字节减少了通信量
2.Xmodem协议相关控制字符SOH0x01STX0x02EOT0x04ACK0x06NAK0x15CAN0x18CTRLZOxlA
3.标准Xmodem协议(每个数据包具有128字节数据)帧格式I SOH|信息包序号|信息包序号的补码I数据区段I校验和I
4.Ik-Xmodem(每个数据包具有1024字节数据)帧格式STX|信息包序号信息包序号的补码数据区if last_error!=0goto reject;*p++=c;if xbuff[l]==unsigned char〜xbuff
[2]xbuff
[1]==packetno||xbuff
[1]==unsigned charpacketno-1checkcrc,xbuff
[3],bufszif xbuff[l]==packetno{int count=destsz-len;if countbufszcount=bufsz;if count0memcpy dest[len],xbuff
[3],count;len+=count;++packetno;二retrans MAXRETRANS+l;if—retrans=0flushinput;port_outbyteCAN;port_outbyteCAN;port_outbyteCAN;return-3;port_outbyteACK;continue;reject:flushinput;port_outbyteNAK;int xmodemTransmitunsigned char*src,int srcszunsigned char xbuff
[1030];int bufsz,crc=-1;unsigned charpacketno=1;int i,c,len=0;int retry;for;;{for retry=0;retry16;++retryc=port_inbyteDLY_1S«1;if last_error==0switch ccaseC:crc=1;goto start_trans;case NAK:crc=0;goto start_trans;case CAN:c=port_inbyteDLY_l S;ifc==CANport_outbyteACK;flushinput;return-1;break;default:break;port_outbyteCAN;port_outbyteCAN;port_outbyteCAN;flushinput;return-2;for;;start_trans:xbuff[O]=SOH;bufsz=128;xbuff[l]=packetno;xbuff
[2]=〜packetno;c=srcsz-len;if cbufsz c=bufsz;if c=0memset xbuff
[3],0,bufsz;if c==0xbuff
[3]=CTRLZ;else{memcpy xbuff
[3],src[len],c;ifcbufsz xbuff[3+c]=CTRLZ;if crc{unsigned shortccrc=crc16_ccittxbuff
[3],bufsz;xbuff[bufsz+3]=ccrc»8OxFF;二xbuff[bufsz+4]ccrcOxFF;elseunsigned charccks=0;for i=3;ibufsz+3;++i十二ccks xbuff[i];xbuff[bufsz+3]=ccks;for retry=0;retryMAXRETRANS;++retry{for i=0;ibufsz+4+crc1:0;++i{port_outbytexbuff[i];c=port_inbyteDLY_l S;if last_error==0{switch ccaseACK:++packetno;len+=bufsz;goto start_trans;case CAN:二c port_inbyteDLY_lS;ifc=CANport_outbyteACK;flushinput;return-1;break;case NAK:default:break;port_outbyteCAN;port_outbyteCAN;port_outbyteCAN;flushinput;return-4;elsefor retry=0;retry10;++retry{port_outbyteEOT;c=port_inbyteDLY_l S«1;if c==ACK break;flushinput;return c==ACKlen:-5;校验和
5.数据包说明对于标准Xmodem协议来说,假如传送的文献不是128的整数倍,那么最后一个数据包的有效内容肯定小于帧长,局限性的部分需要用CTRL-Z(OxlA)来填充这里也许有人会问,假如我传送的是bootloader工程生成的.bin文献,mcu收到后碰到OxlA字符会怎么解决?其实如果传送的是文本文献,那么接受方对于接受的内容是很容易辨认的,由于CTRL-Z不是前128个ascii码,不是通用可见字符,假如是二进制文献,mcu其实也不会把它当作代码来执行哪怕是excel文献等,由于其内部会有些结构表达各个字段长度等,所以不会读取多余的填充字符否则Xmodem太弱了对于Ik-Xmodem,同上理
6.如何启动传输?传输由接受方启动,方法是向发送方发送〃C〃或者NAK(注意哦,这里提到的NAK是用来启动传输的以下我们会看到NAK还可以用来对数据产生重传的机制)接受方发送NAK信号表达接受方打算用累加和校验;发送字符〃C〃则表达接受方想打算使用CRC校验(具体校验规则下文Xmodem源码,源码胜于雄辩)7,传输过程当接受方发送的第一个〃C〃或者NAK到达发送方,发送方认为可以发送第一个数据包,传输已经启动发送方接着应当将数据以每次128字节的数据加上包头,包号,包号补码,末尾加上校验和,打包成帧格式传送发送方发了第一包后就等待接受方的确认字节ACK,收到接受方传来的ACK确认,就认为数据包被接受方对的接受,并且接受方规定发送方继续发送下一个包;假如发送方收到接受方传来的NAK(这里,NAK用来告诉发送方重传,不是用来启动传输)字节,则表达接受方请求重发刚才的数据包;假如发送方收到接受方传来的CAN字节,则表达接受方请求无条件停止传输
8.如何结束传输?假如发送方正常传输完所有数据,需要结束传输,正常结束需要发送方发送EOT字节告知接受方接受方回以ACK进行确认当然接受方也可强制停止传输,当接受方发送CAN字节给发送方,表达接受方想无条件停止传输,发送方收到CAN后,不需要再发送EOT确认(由于接受方已经不想理它了,呵呵)
9.特殊解决虽然数据包是以SOH来标志一个信息包的起始的,但在SOH位置上假如出现EOT则表达数据传输结束,再也没有数据传过来接受方一方面应确认数据包序号的完整性,通过对数据包序号取补,然后和数据包序号的补码异或,结果为0表达对的,结果不为0则发送NAK请求重传接受方确认数据包序号对的后,然后检查是否盼望的序号假如不是盼望得到的数据包序号,说明发生严重错误,应当发送一个CAN来中止传输假如接受到的数据包的包序号和前一包相同,那么接受方会忽略这个反复包,向发送方发出ACK,准备接受下一个包接受方确认了信息包序号的完整性和是对的盼望的后,只对128字节的数据区段进行算术和校验,结果与帧中最后一个字节(算术校验和)比较,相同发送ACK,不同发送NAKo
10.校验和的说明Xmodem协议支持2种校验和,它们是累加和与CRC校验当接受方一开始启动传输时发送的是NAK,表达它希望以累加和方式校验当接受方一开始启动传输时发送的是字符“C”,表达它希望以CRC方式校验也许有人会问,接受方想怎么校验发送方都得配合吗,难道发送方必须都支持累加和校验和CRC校验?事实上Xmodem规定支持CRC的就必须同时支持累加和,假如发送方只支持累加和,而接受方用字符来启动,那么发送方只要不管它,当接受方继续发送“C”,三次后都没收到应答,就自动会改为发送NAK,由于它已经明白发送方也许不支持CRC校验,现在接受方改为累加和校验和发送方通讯发送方收到NAK就赶紧发送数据包响应
11.Xmodem协议代码看了以上说明,再参考代码,应当很容易会理解代码编写者的思绪源码XModem#include ncrcl
6.hn#define SOH0x01#define STX0x02#define EOT0x04#define ACK0x06#define NAK0x15#define CAN0x18#define CTRLZOx1A#define DLY_1S1000#define MAXRETRANS25static intlast_error=0;#include,string.hnvoid port_outbyteunsigned chartrycharunsigned charbuf
[2];buf[O]=trychar;lowLevel_writebuf,1;unsigned charport_inbyteunsigned inttime_outunsigned charch;int i;last error=0;iflowLevel_readch,1==1return ch;last_error=1;return ch;static intcheckint crc,const unsigned char*buf,int szif crcunsigned shortcrc=crcl6_ccittbuf,sz;unsigned shorttcrc=buf[sz]«8+buf[sz+1];ifcrc==tcrcreturn1;elseint i;unsigned charcks=0;for i=0;isz;++icks+=buf[i];if cks==buf[sz]return1;return0;static voidflushinputvoid//while port_inbyteDLY_lS*3»1=0int xmodemReceiveunsignedchar*dest,int destszunsignedchar xbuff
[1030];unsignedchar*p;int bufsz,crc=0;unsignedchartrychar=C*;unsignedcharpacketno=1;int i,c,len=0;int retry,retrans=MAXRETRANS;for;;for retry=0;retry16;++retryif trycharport_outbytetrychar;c=port_inbyteDLY_1S«1;if last_error==0switch ccaseSOH:bufsz=128;goto start_recv;case STX:bufsz=1024;goto start_recv;case EOT:flushinput;port_outbyteACK;return len;case CAN:c=port_inbyteDLY_l S;ifc=CANflushinput;port_outbyteACK;return-1;break;default:break;if trychar==*Ctrychar=NAK;continue;flushinput;port_outby teCAN;port_outbyteCAN;port_outbyteCAN;return-2;start_recv:if trychar=C crc=1;trychar=0;p=xbuff;*p++=c;for i=0;ibufsz+crc l:0+3;++i二c port_inbyteDLY_l S;。
个人认证
优秀文档
获得点赞 0