自定义文件传输协议 上位机和下位机串口通信

 该协议为自定义协议,模仿了YModem-1K帧结构,每包传输1K数据,最后一包数据根据文件大小决定,为总字节数对1024取整。

该协议用N字节信息块传输,N可以自定义,数据的发送会使用CRC16校验,保证数据传输的正确性。它每传输一个信息块数据时,就会等待接收端回应ACK信号,接收到回应后,才会继续传输下一个信息块,保证数据已经全部接收。且支持了下位机的序列包定位,当漏发了一包数据,或者需要跳转,当前仅支持按照1024字节整数倍进行文件跳转,该协议不包含结束帧,可根据序列号进行判断。文件大小应小于67108864 Bytes,即64Mbyte。

文件发送篇

1、起始帧的数据格式

    起始帧并不直接传输文件的数据,而是将文件名与文件的大小放在数据帧中传输,它的帧长=4字节帧头+4字节文件大小+2字节包大小+2字节CRC16校验码+文件名(不定长字符串)。

它的数据结构如下:

    AA BB CC DD FileSize[4] PacketSize[2] CRCH CRCL filename[…]

其中AA BB CC DD,表示这个数据帧为起始帧;在帧头后面的FileSize [4]表示文件大小,4个字节高位在前低位在后;PacketSize[2] 表示每包文件数据大小,文件将拆分成多个PacketSize进行传输;CRCH CRCL分别表示16位CRC校验码的高8位与低8位,校验的数据为4字节文件长度+2字节包大小;filename[…]就是文件名,如文件名foo.c,它在数据帧中存放格式为:66 6F 6F 2E 63 00,一定要在文件名最后跟上一个00,表示文件名结束 。

 

2、数据帧的数据格式

       数据帧中会预留PacketSize字节空间用来传输文件数据,它跟起始帧接收差不多,如下:

       00 00 data[PacketSize] CRCH CRCL

其中00 00表示第一帧数据帧,当然如果是第二帧数据的话就是:00 01;data[PacketSize]表示存放着PacketSize字节的文件数据;CRCH与CRCL是CRC16校验码的高8位与低8位,校验的数据为data中的数据。

       如果文件数据的最后剩余的数据小于PacketSize,假设最后一包序列号为num的数据,剩余n字节数据,且n< PacketSize,则如下结构:

       [num]  data[n]  CRCH  CRCL

      

3、文件传输过程

       文件的传输过程,以具体的例子说明。把foo.c,大小为4196Byte(16进制为0x1064)的文件作为传输的对象,拆分为1024byte(PacketSize=1024,16进制为0x0400)一包,则它的传输过程如下:

 发送端                                                             接收端

AA BB CC DD 00 00 64 10 04 00 CRCH CRCL "foo.c" >>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<     ACK

00 00 data[1024] CRCH CRCL >>>>>>>>>>>>>>>>>>>>>>>>      

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    ACK

00 01 data[1024] CRCH CRCL >>>>>>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    ACK

00 02 data[1024] CRCH CRCL >>>>>>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    ACK

00 03 data[1024] CRCH CRCL >>>>>>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    ACK

00 04 data[100] CRCH CRCL >>>>>>>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    ACK

 

传输过程就是上面所示。但是上面传输过程中存在许多通信信号,它们的数值与意义如下表所示:

 符号

 数值

 含义

 ACK

 0x06

 正常回应

 ERR

 0X07

 校验错误

 ERR1

 0x08

 请求重传序列号包

 CA

 0XFFFF

 传输中止

 

 

 

   

还是有几点需要说明下:

       1)CA中止传输信号都可以发送,可在需要传输新文件时发送

       2)ERR信号,当校验失败的时候,由接收方发送,发送方收到后重传当前序列包。

       3)ERR1信号,基本上不可能出现。当出现该信号的时候说明帧错乱,需要重新定位序列帧数据,请求重传,格式为0x08 numH numL ,num为请求的序列包,高字节在前,低字节在后。

4CRC的计算

       采用的是CRC-16-IBM(A001)的CRC校验,它的生成多项式为x16+x12+x5+1。

下面列出两种c语言的计算方法查表和计算。

计算方式

  1. /****************************************************** 
  2. *函数名称:CRC16RTU 
  3. *输   入:pszBuf  要校验的数据 
  4.         unLength 校验数据的长 
  5. *输   出:校验值 
  6. *功   能:循环冗余校验-16 
  7.          (RTU标准-0xA001) 
  8. *******************************************************/  
  9. u16 CRC16RTU( u8 * pszBuf, u16 unLength)  
  10. {  
  11.     u16 CRCx=0XFFFF;  
  12.     u32 CRC_count;  
  13.     for(CRC_count=0;CRC_count<unLength;CRC_count++)  
  14.     {  
  15.         int i;  
  16.         CRCx=CRCx^*(pszBuf+CRC_count);  
  17.   
  18.         for(i=0;i<8;i++)  
  19.         {  
  20.             if(CRCx&1)  
  21.             {  
  22.                 CRCx>>=1;  
  23.                 CRCx^=0xA001;  
  24.             }  
  25.             else  
  26.             {   
  27.                 CRCx>>=1;  
  28.             }  
  29.         }  
  30.     }  
  31.   
  32.     return CRCx;  
  33. }  

查表方式:

 
  1. //CRC高位字节值表  
  2.   
  3. const u8 auchCRCHi[] = {  
  4.   
  5. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,  
  6.   
  7. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,  
  8.   
  9. 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,  
  10.   
  11. 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,  
  12.   
  13. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,  
  14.   
  15. 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,  
  16.   
  17. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,  
  18.   
  19. 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,  
  20.   
  21. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,  
  22.   
  23. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,  
  24.   
  25. 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,  
  26.   
  27. 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,  
  28.   
  29. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,  
  30.   
  31. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,  
  32.   
  33. 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,  
  34.   
  35. 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,  
  36.   
  37. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,  
  38.   
  39. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,  
  40.   
  41. 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,  
  42.   
  43. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,  
  44.   
  45. 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,  
  46.   
  47. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,  
  48.   
  49. 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,  
  50.   
  51. 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,  
  52.   
  53. 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,  
  54.   
  55. 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40  
  56.   
  57. };  
  58.   
  59. //CRC 低位字节值表  
  60.   
  61. const u8 auchCRCLo[]={  
  62.   
  63. 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,  
  64.   
  65. 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,  
  66.   
  67. 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,  
  68.   
  69. 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,  
  70.   
  71. 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,  
  72.   
  73. 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,  
  74.   
  75. 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,  
  76.   
  77. 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,  
  78.   
  79. 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,  
  80.   
  81. 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,  
  82.   
  83. 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,  
  84.   
  85. 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,  
  86.   
  87. 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,  
  88.   
  89. 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,  
  90.   
  91. 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,  
  92.   
  93. 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,  
  94.   
  95. 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,  
  96.   
  97. 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,  
  98.   
  99. 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,  
  100.   
  101. 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,  
  102.   
  103. 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,  
  104.   
  105. 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,  
  106.   
  107. 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,  
  108.   
  109. 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,  
  110.   
  111. 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,  
  112.   
  113. 0x43, 0x83, 0x41, 0x81, 0x80, 0x40  
  114.   
  115. };  
  116.   
  117. //获得CRC16值  
  118.   
  119. //puchMsg:要校验的数组  
  120.   
  121. //usDataLen:数组长度  
  122.   
  123. u16 Get_Crc16(u8 *puchMsg,u16 usDataLen)  
  124.   
  125. {  
  126.   
  127.          u8 uchCRCHi=0xFF;        //高CRC 字节初始化  
  128.   
  129.          u8 uchCRCLo=0xFF;        //低CRC 字节初始化  
  130.   
  131.          u32 uIndex;               //CRC 循环中的索引  
  132.   
  133.          while(usDataLen--)           //传输消息缓冲区  
  134.   
  135.          {  
  136.   
  137.                    uIndex=uchCRCHi^*puchMsg++; //计算CRC  
  138.   
  139.                    uchCRCHi=uchCRCLo^auchCRCHi[uIndex];  
  140.   
  141.                    uchCRCLo=auchCRCLo[uIndex];  
  142.   
  143.          }  
  144.   
  145.          return (uchCRCHi<<8|uchCRCLo);  
  146.   
  147. }  

 

 

文件接收篇

准备进入接收模式的时候,发送一帧数据告诉对方已准备好接收(当然也是可以不发该帧数据,让发送方主动发送就可以了)。该协议默认通知发送方已准备好接收数据。

帧格式(3字节): 0XAA 0XBB 0XDD

 

文件传输无响应:

 

文件传输强制中断:

 

文件传输完成:

 

文件正在传输:

猜你喜欢

转载自www.cnblogs.com/miaoguoqiang/p/9158443.html