7E頭解析的那些事兒(幀格式分析實例)
0. 前言
作為一名嵌入式工程師,經(jīng)常需要通過UART與外設(shè)打交道,而對于串行總線來說,往往我們必須要進行幀同步。通常的做法是把信令包含在2個0x7E的中間。
除此之外還有HDLC、PPP等協(xié)議也會到有此應(yīng)用場景。
那么如何從這些數(shù)據(jù)幀中提取有效數(shù)據(jù)呢?
本文通過一個簡單的實例給大家詳細講述如何從幀中提取有效的協(xié)議信令。
1. 幀格式要求
首先我們明確下幀提取的一些要求:
(1)把信息字段中出現(xiàn)的每一個0x7E字節(jié)轉(zhuǎn)變?yōu)?字節(jié)序列(0x7D,0x5E)。
(2)若信息字段中出現(xiàn)一個0x7D的字節(jié)(即出現(xiàn)了和轉(zhuǎn)義字符一樣的比特組合),則把轉(zhuǎn)義字符0x7D轉(zhuǎn)變?yōu)?字節(jié)序列(0x7D,0x5D)。
舉例:一個PPP幀的數(shù)據(jù)部分:
- 7D 5E FE 27 7D 5D 7D 5D 65 7D 5E
那么實際上真正的數(shù)據(jù)是
- 7E FE 27 7D 7D 65
轉(zhuǎn)換圖解:
同樣的,如果要發(fā)送數(shù)據(jù),則反過來。
2. 設(shè)計
- 底層傳上來的每一短幀長度不固定
- 底層傳上來的每一短幀7e頭位置不固定,可能有可能沒有,可能有1個7e也可能有2個7e
- 默認每一幀數(shù)據(jù)最多2個7e
比如:我們從底層收上來的原始數(shù)據(jù)幀格式如下:
那么我們要能夠提取兩個7e之間的協(xié)議數(shù)據(jù)幀,同時還原幀中的所有的7e。
很顯然我們希望最終解析后結(jié)果如下:
- 7e 0f 0e 30 27 1c 00 27 1c 01 27 1c 02 7e 00 29 7e
- 7e 11 73 7e
- 7e 00 27 1c 01 27 1c 02 7e 00 29 7e
幀解析詳細設(shè)計流程圖
3.代碼
不上代碼的就是耍流氓
首先看下如果下發(fā)數(shù)據(jù)幀,如何將所有的7e和7d做替換:函數(shù)hdlc_send(char * data,UINT8 len)實現(xiàn)如下:
int hdlc_rcv_frm(UINT8 *data,int len)實現(xiàn)如下
測試代碼如下:
- int main()
- {
- int len;
- char data1[6]={0x7e,0xf,0xe,0x30,0x27,0x1c};
- char data2[6]={0x0,0x27,0x1c,0x1,0x27,0x1c};
- char data3[8]={0x2,0x7d,0x5e,0x0,0x29,0x7e,0x0,0x7e};
- char data4[6]={0x11,0x73,0x7e,0x30,0x27,0x7e};
- char data5[6]={0x0,0x27,0x1c,0x1,0x27,0x1c};
- char data6[6]={0x2,0x7d,0x5e,0x0,0x29,0x7e};
- #if 0
- printf("************測試hdlc_send()******************\n");
- len = hdlc_send(data1,6);
- printf("********************end**********************\n\n");
- #endif
- printf("\n************測試hdlc_rcv_frm()******************\n");
- hdlc_rcv_frm(data1,6);
- hdlc_rcv_frm(data2,6);
- hdlc_rcv_frm(data3,8);
- hdlc_rcv_frm(data4,6);
- hdlc_rcv_frm(data5,6);
- hdlc_rcv_frm(data6,6);
- printf("********************end**************************\n");
- }
- 運行結(jié)果如下:
運行結(jié)果如下:
注意
本代碼仍然有一些bug,暫時沒有修改,所以實際項目慎用。小心數(shù)組越界啊!
完整代碼鏈接:
鏈接:https://pan.baidu.com/s/1rPEDC3erLpPRH0OnkfNH_A
提取碼:wzxq