walnutcy

基于状态机的NMEA0183与TSIP协议混合解析

0
阅读(2489)

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

有两个图像显示有问题,更新下。