作者:zzssdd2
E-mail:zzssdd2@foxmail.com
〇、前言
近段時(shí)間做的項(xiàng)目涉及到設(shè)備固件OTA升級(jí)相關(guān)工作,其中有用到Ymodem 協(xié)議傳輸數(shù)據(jù),故整理一下Ymodem協(xié)議的知識(shí)。一是為寫上位機(jī)/下位機(jī)做準(zhǔn)備,二是做個(gè)備忘便于以后用時(shí)查閱。
一、符號(hào)說明
協(xié)議中用到的符號(hào)及其對(duì)應(yīng)的數(shù)值和含義說明
符號(hào) |
數(shù)值 |
含義 |
SOH |
0x01 |
128字節(jié)數(shù)據(jù)包 |
STX |
0x02 |
1024字節(jié)數(shù)據(jù)包 |
EOT |
0x04 |
結(jié)束傳輸 |
ACK |
0x06 |
正確接收回應(yīng) |
NAK |
0x15 |
錯(cuò)誤接收回應(yīng) |
CAN |
0x18 |
傳輸中止 |
C |
0x43 |
請(qǐng)求數(shù)據(jù) |
二、傳輸起始幀
接收方發(fā)起傳輸請(qǐng)求后由發(fā)送方發(fā)送的第一包數(shù)據(jù)
幀頭 |
幀序 |
幀序反碼 |
文件名 |
文件大小 |
NULL |
CRC-H |
CRC-L |
SOH |
00 |
FF |
n Bytes |
m Bytes |
x Bytes |
1 Byte |
1 Byte |
- SOH:表示這個(gè)數(shù)據(jù)幀中包含著128個(gè)字節(jié)的數(shù)據(jù)段
- 00:表示數(shù)據(jù)幀序號(hào),初始是0,依次遞增(滿255從0開始)
- FF:是幀序號(hào)的取反(提供一種數(shù)據(jù)是否正確的判斷依據(jù))
- 數(shù)據(jù)段(128byte):文件名 + 文件大小 + NULL
- 文件名:例如文件名是
foo.c ,ACSII字符轉(zhuǎn)換為HEX字符就是66 6F 6F 2E 63 。它在數(shù)據(jù)幀中存放格式為66 6F 6F 2E 63 00 ,最后加一個(gè)00表示文件名字段結(jié)束。
- 文件大小:假如上面的
foo.c 文件大小為1024字節(jié),轉(zhuǎn)化成16進(jìn)制即0x400。它在數(shù)據(jù)幀中存放格式為34 30 30 00 ,即ASCII格式的400,最后加一個(gè)00表示文件大小字段結(jié)束
- NULL:數(shù)據(jù)部分大小為128字節(jié),除去文件名與文件大小占用的空間外,剩余的x Bytes全部用00填充
- CRC-H和CRC-L分別表示16位CRC校驗(yàn)碼的高8位與低8位,校驗(yàn)只針對(duì)數(shù)據(jù)段。
三、傳輸數(shù)據(jù)幀
文件內(nèi)容數(shù)據(jù)包
幀頭 |
幀序 |
幀序反碼 |
數(shù)據(jù) |
CRC-H |
CRC-L |
STX/SOH |
num |
~num |
1024/128 Bytes |
1 Byte |
1 Byte |
-
STX 表示這幀數(shù)據(jù)的數(shù)據(jù)段為1024字節(jié),SOH 表示這幀數(shù)據(jù)的數(shù)據(jù)段為128字節(jié)
-
第一包幀序?yàn)?1,幀序反碼為FE,第二包幀序?yàn)?2,其反碼為FD......以此類推
-
CRC-H和CRC-L分別表示16位CRC校驗(yàn)碼的高8位與低8位,校驗(yàn)只針對(duì)數(shù)據(jù)段。
-
如果文件最后一幀數(shù)據(jù)在128~1024之間,則使用STX的1024字節(jié)傳輸,但是剩余空間全部用0x1A填充,如下結(jié)構(gòu):
-------------------------------------------------------
| STX | num | ~num | data[ ] | 1A ...1A | CRCH | CRCL |
-------------------------------------------------------
-
如果文件最后一幀數(shù)據(jù)小于128字節(jié),則選擇SOH的128字節(jié)來傳輸,但是剩余空間全部用0x1A填充,如下結(jié)構(gòu):
------------------------------------------------------
| SOH | num | ~num | data[ ] | 1A...1A | CRCH | CRCL |
------------------------------------------------------
四、傳輸結(jié)束幀
發(fā)送方發(fā)送的最后一包數(shù)據(jù)
幀頭 |
幀序 |
幀序反碼 |
數(shù)據(jù) |
CRC-H |
CRC-L |
SOH |
00 |
FF |
NUL[128] |
00 |
00 |
- 結(jié)束幀同樣以SOH開頭,表示后面跟著128字節(jié)的數(shù)據(jù),結(jié)束幀的幀序也認(rèn)為是00 FF
- 結(jié)束幀的128字節(jié)的數(shù)據(jù)部分不存放任何信息,即NUL[128]全部用00填充
- 因?yàn)閿?shù)據(jù)段全為00,故校驗(yàn)碼也為00 00
五、傳輸流程
文件的傳輸分為如下幾個(gè)階段進(jìn)行
接收方給發(fā)送方不斷地發(fā)送字符'C',以期望收到發(fā)送方的數(shù)據(jù)響應(yīng)。
接收方->>發(fā)送方: Char 'C'
接收方->>發(fā)送方: Char 'C'
......
發(fā)送方收到接收方發(fā)來'C'字符,開始發(fā)送起始幀數(shù)據(jù)。等待接收方響應(yīng)ACK標(biāo)記,發(fā)送方收到ACK標(biāo)記后等待接收方發(fā)送字符'C'則開始正式傳輸文件內(nèi)容。
發(fā)送方->>接收方: Start packet
接收方->>發(fā)送方: ACK
接收方->>發(fā)送方: C
發(fā)送方每發(fā)一個(gè)文件內(nèi)容數(shù)據(jù)包,就期待接收方響應(yīng)一個(gè)ACK標(biāo)記,以繼續(xù)發(fā)送下一個(gè)包。
發(fā)送方->>接收方: Packet 1
接收方->>發(fā)送方: ACK
發(fā)送方->>接收方: Packet 2
接收方->>發(fā)送方: ACK
......
若發(fā)送方發(fā)完數(shù)據(jù)包后收到了接收方NAK標(biāo)記的響應(yīng),則重發(fā)此包,直到收到ACK響應(yīng)或者超時(shí)退出。
發(fā)送方->>接收方: Packet n
接收方->>發(fā)送方: NAK
發(fā)送方->>接收方: Packet n
接收方->>發(fā)送方: ACK
發(fā)送方->>接收方: Packet n+1
......
若發(fā)送方發(fā)完數(shù)據(jù)包后收到了接收方CAN標(biāo)記的響應(yīng),則停止數(shù)據(jù)包發(fā)送,結(jié)束傳輸。
......
發(fā)送方->>接收方: Packet n
接收方->>發(fā)送方: ACK
發(fā)送方->>接收方: Packet n+1
接收方->>發(fā)送方: CAN
中止傳輸
若發(fā)送方已將數(shù)據(jù)包全部發(fā)完,則發(fā)送EOT標(biāo)記等待接收方的NAK響應(yīng),當(dāng)發(fā)送方收到NAK后會(huì)再次發(fā)送EOT等待接收方的C標(biāo)記來請(qǐng)求結(jié)束幀,發(fā)送結(jié)束幀后收到接收方的ACK標(biāo)記則表示本次傳輸完成
發(fā)送方->>接收方: EOT
接收方->>發(fā)送方: NAK
發(fā)送方->>接收方: EOT
接收方->>發(fā)送方: C
發(fā)送方->>接收方: Over packet
接收方->>發(fā)送方: ACK
傳輸結(jié)束
六、實(shí)例說明
假設(shè)以foo.c,大小為4196Bytes(16進(jìn)制為0x1064)的文件作為傳輸對(duì)象,則它的傳輸過程如下:
發(fā)送方 |
傳輸方向 |
接收方 |
|
<<<<<<<<<<<<<<<< |
C(請(qǐng)求起始幀) |
SOH 00 FF 66 6F 6F 2E 63 00 31 30 36 34 00 NUL[117] CRCH CRCL |
>>>>>>>>>>>>>>>> |
|
|
<<<<<<<<<<<<<<<< |
ACK |
|
<<<<<<<<<<<<<<<< |
C(請(qǐng)求數(shù)據(jù)幀) |
STX 01 FE data[1024] CRCH CRCL |
>>>>>>>>>>>>>>>> |
|
|
<<<<<<<<<<<<<<<< |
ACK |
STX 02 FD data[1024] CRCH CRCL |
>>>>>>>>>>>>>>>> |
|
|
<<<<<<<<<<<<<<<< |
ACK |
STX 03 FC data[1024] CRCH CRCL |
>>>>>>>>>>>>>>>> |
|
|
<<<<<<<<<<<<<<<< |
NAK(接收錯(cuò)誤請(qǐng)求重發(fā)) |
STX 03 FC data[1024] CRCH CRCL |
>>>>>>>>>>>>>>>> |
|
|
<<<<<<<<<<<<<<<< |
ACK |
STX 04 FB data[1024] CRCH CRCL |
>>>>>>>>>>>>>>>> |
|
|
<<<<<<<<<<<<<<<< |
ACK |
SOH 05 FA data[100] 1A[28] CRCH CRCL |
>>>>>>>>>>>>>>>> |
|
|
<<<<<<<<<<<<<<<< |
ACK |
EOT |
>>>>>>>>>>>>>>>> |
|
|
<<<<<<<<<<<<<<<< |
NAK(響應(yīng)結(jié)束命令) |
EOT |
>>>>>>>>>>>>>>>> |
|
|
<<<<<<<<<<<<<<<< |
C(請(qǐng)求結(jié)束幀) |
SOH 00 FF NUL[128] CRCH CRCL |
>>>>>>>>>>>>>>>> |
|
|
<<<<<<<<<<<<<<<< |
ACK |
七、CRC16校驗(yàn)
數(shù)據(jù)幀中校驗(yàn)碼的計(jì)算方式——C語言
/******************************************************************************************
* 函 數(shù): CRC16_Xmodem
* 描 述: 計(jì)算CRC16-Xmodem
* 多項(xiàng)式x16+x12+x5+1(0x1021) | 初始值0x0000 | 低位在后,高位在前 | 結(jié)果與0x0000異或
* 輸 入: pData : 數(shù)據(jù)指針
* ulSize : 數(shù)據(jù)長度
* 輸 出: CRC16檢驗(yàn)碼
******************************************************************************************/
uint16_t CRC16_Xmodem(uint8_t *pData, uint32_t ulSize)
{
uint8_t i;
uint16_t usCRC = 0x0000;
while (ulSize--)
{
usCRC ^= (*pData++ << 8);
for(i = 0; i < 8; i++)
{
if(usCRC & 0x8000)
{
usCRC = (CRCin << 1) ^ 0x1021;
}
else
{
usCRC = usCRC << 1;
}
}
}
return usCRC;
}
|