作者:zzssdd2
E-mail:zzssdd2@foxmail.com
近段時間做的項目涉及到設(shè)備固件OTA升級相關(guān)工作,其中有用到Ymodem
協(xié)議傳輸數(shù)據(jù),故整理一下Ymodem協(xié)議的知識。一是為寫上位機/下位機做準備,二是做個備忘便于以后用時查閱。
協(xié)議中用到的符號及其對應(yīng)的數(shù)值和含義說明
符號 | 數(shù)值 | 含義 |
---|---|---|
SOH | 0x01 | 128字節(jié)數(shù)據(jù)包 |
STX | 0x02 | 1024字節(jié)數(shù)據(jù)包 |
EOT | 0x04 | 結(jié)束傳輸 |
ACK | 0x06 | 正確接收回應(yīng) |
NAK | 0x15 | 錯誤接收回應(yīng) |
CAN | 0x18 | 傳輸中止 |
C | 0x43 | 請求數(shù)據(jù) |
接收方發(fā)起傳輸請求后由發(fā)送方發(fā)送的第一包數(shù)據(jù)
幀頭 | 幀序 | 幀序反碼 | 文件名 | 文件大小 | NULL | CRC-H | CRC-L |
---|---|---|---|---|---|---|---|
SOH | 00 | FF | n Bytes | m Bytes | x Bytes | 1 Byte | 1 Byte |
foo.c
,ACSII字符轉(zhuǎn)換為HEX字符就是66 6F 6F 2E 63
。它在數(shù)據(jù)幀中存放格式為66 6F 6F 2E 63 00
,最后加一個00表示文件名字段結(jié)束。foo.c
文件大小為1024字節(jié),轉(zhuǎn)化成16進制即0x400。它在數(shù)據(jù)幀中存放格式為34 30 30 00
,即ASCII格式的400,最后加一個00表示文件大小字段結(jié)束文件內(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é)
第一包幀序為01,幀序反碼為FE,第二包幀序為02,其反碼為FD......以此類推
CRC-H和CRC-L分別表示16位CRC校驗碼的高8位與低8位,校驗只針對數(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 |
------------------------------------------------------
發(fā)送方發(fā)送的最后一包數(shù)據(jù)
幀頭 | 幀序 | 幀序反碼 | 數(shù)據(jù) | CRC-H | CRC-L |
---|---|---|---|---|---|
SOH | 00 | FF | NUL[128] | 00 | 00 |
文件的傳輸分為如下幾個階段進行
接收方給發(fā)送方不斷地發(fā)送字符'C',以期望收到發(fā)送方的數(shù)據(jù)響應(yīng)。
接收方->>發(fā)送方: Char 'C'
接收方->>發(fā)送方: Char 'C'
......
發(fā)送方收到接收方發(fā)來'C'字符,開始發(fā)送起始幀數(shù)據(jù)。等待接收方響應(yīng)ACK標記,發(fā)送方收到ACK標記后等待接收方發(fā)送字符'C'則開始正式傳輸文件內(nèi)容。
發(fā)送方->>接收方: Start packet
接收方->>發(fā)送方: ACK
接收方->>發(fā)送方: C
發(fā)送方每發(fā)一個文件內(nèi)容數(shù)據(jù)包,就期待接收方響應(yīng)一個ACK標記,以繼續(xù)發(fā)送下一個包。
發(fā)送方->>接收方: Packet 1
接收方->>發(fā)送方: ACK
發(fā)送方->>接收方: Packet 2
接收方->>發(fā)送方: ACK
......
若發(fā)送方發(fā)完數(shù)據(jù)包后收到了接收方NAK標記的響應(yīng),則重發(fā)此包,直到收到ACK響應(yīng)或者超時退出。
發(fā)送方->>接收方: Packet n
接收方->>發(fā)送方: NAK
發(fā)送方->>接收方: Packet n
接收方->>發(fā)送方: ACK
發(fā)送方->>接收方: Packet n+1
......
若發(fā)送方發(fā)完數(shù)據(jù)包后收到了接收方CAN標記的響應(yīng),則停止數(shù)據(jù)包發(fā)送,結(jié)束傳輸。
......
發(fā)送方->>接收方: Packet n
接收方->>發(fā)送方: ACK
發(fā)送方->>接收方: Packet n+1
接收方->>發(fā)送方: CAN
中止傳輸
若發(fā)送方已將數(shù)據(jù)包全部發(fā)完,則發(fā)送EOT標記等待接收方的NAK響應(yīng),當發(fā)送方收到NAK后會再次發(fā)送EOT等待接收方的C標記來請求結(jié)束幀,發(fā)送結(jié)束幀后收到接收方的ACK標記則表示本次傳輸完成
發(fā)送方->>接收方: EOT
接收方->>發(fā)送方: NAK
發(fā)送方->>接收方: EOT
接收方->>發(fā)送方: C
發(fā)送方->>接收方: Over packet
接收方->>發(fā)送方: ACK
傳輸結(jié)束
假設(shè)以foo.c,大小為4196Bytes(16進制為0x1064)的文件作為傳輸對象,則它的傳輸過程如下:
發(fā)送方 | 傳輸方向 | 接收方 |
---|---|---|
<<<<<<<<<<<<<<<< | C(請求起始幀) | |
SOH 00 FF 66 6F 6F 2E 63 00 31 30 36 34 00 NUL[117] CRCH CRCL | >>>>>>>>>>>>>>>> | |
<<<<<<<<<<<<<<<< | ACK | |
<<<<<<<<<<<<<<<< | C(請求數(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(接收錯誤請求重發(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(請求結(jié)束幀) | |
SOH 00 FF NUL[128] CRCH CRCL | >>>>>>>>>>>>>>>> | |
<<<<<<<<<<<<<<<< | ACK |
數(shù)據(jù)幀中校驗碼的計算方式——C語言
/******************************************************************************************
* 函 數(shù): CRC16_Xmodem
* 描 述: 計算CRC16-Xmodem
* 多項式x16+x12+x5+1(0x1021) | 初始值0x0000 | 低位在后,高位在前 | 結(jié)果與0x0000異或
* 輸 入: pData : 數(shù)據(jù)指針
* ulSize : 數(shù)據(jù)長度
* 輸 出: CRC16檢驗碼
******************************************************************************************/
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;
}
聯(lián)系客服