Tremble的授时模块支持两种协议:NMEA0183与TSIP,软件要支持两种协议,
该文讨论如何用状态机同时支持两种协议的分离、解析。
- NMEA0183,协议简介如下:
[注释]:
◆帧头:1个ASCII字符,‘$’(0x24)
◆信息类别:2个ASCII字符,如‘GP’(0x47 50)
◆信息ID:3个ASCII字符,定义信息内容,‘A’~‘Z’,如‘GGA’。
◆数据:不定长,由‘,’分割。
◆校验和:2个ASCII字符表示的1字节十六进制数,‘$’和‘*’之间全部字符异或运算的结果。通过‘*’与数据段区隔。
◆帧尾:2个ASCII字符,回车换行<CR><LF>(0x0D 0x0A)
- TSIP协议简介如下:
协议解析模块设计如下图中状态所示:
状态机主要分三种状态:等待包头、等待NMEA语句、等待TSIP数据包。
其各个状态的跳转见上图的注释,由数据决定。
由状态机,设计数据结构如下:
struct NMEA_PacketST
{
u8 state;
u8 lastCh; // add by walter for TSIP decoder
u16 rxLen;
u16 length;
u8 mDat[120];
};
状态机初始化:
nmea.state = NMEA_STS_HEAD;
nmea.rxLen = 0;
状态机实现:
u8 NMEA_FormatProc(u8 ch)
{
u8 rst = 0;
if (nmea.state == NMEA_STS_HEAD)
{
if (('$' == nmea.mDat[1])
&& ('G' == nmea.mDat[2])
&& ('P' == ch)) // $GP GGA/GSV/GSA/VTG/RMC/...
{
nmea.state = NMEA_STS_NMEA;
nmea.mDat[0] = nmea.mDat[1];
nmea.mDat[1] = nmea.mDat[2];
nmea.mDat[2] = ch;
nmea.rxLen = 3;
}
else if (ch == TSIP_D_DLE)
{
nmea.state = NMEA_STS_TSIP;
nmea.mDat[0] = ch;
nmea.lastCh = ch;
nmea.rxLen = 1;
}
else
{
nmea.mDat[0] = nmea.mDat[1];
nmea.mDat[1] = nmea.mDat[2];
nmea.mDat[2] = ch;
return rst;
}
}
else if (nmea.state == NMEA_STS_NMEA)
{
nmea.mDat[nmea.rxLen] = ch;
nmea.rxLen++;
if ((nmea.mDat[nmea.rxLen-2] == 0x0D) && (0x0A == ch))
{
nmea.state = NMEA_STS_HEAD;
nmea.length= nmea.rxLen;
nmea.mDat[nmea.rxLen] = 0x00;
nmea.rxLen = 0;
rst = 1;
}
}
else if (nmea.state == NMEA_STS_TSIP)
{
nmea.mDat[nmea.rxLen] = ch;
nmea.rxLen++;
if ((nmea.lastCh == TSIP_D_DLE) && (TSIP_D_DLE == ch))
{
nmea.lastCh = 0x00;
}
else if ((nmea.lastCh == TSIP_D_DLE) && (TSIP_D_ETX == ch))
{
nmea.lastCh = 0x00;
nmea.length= nmea.rxLen;
nmea.rxLen = 0;
rst = 2;
}
else
{
nmea.lastCh = ch;
}
}
else
{
nmea.state = NMEA_STS_HEAD;
}
return rst;
}
这里仅仅讨论了如何分离两种格式的数据,利用了状态机的基本工作原理:状态随条件而跳转,状态决定了软件的工作流程。
欢迎各位讨论,个人联系地址如下:
作者: walnutcy 邮箱: walt_chen#163.com
文章评论(0条评论)
登录后参与讨论