nmealib增加双模GNSS模块(GPS与BD)协议解析

1. nmealib库

nmealib是c语言编写的的nmea协议解析库,用于解析GPS协议,使用的版本为0.5.3。
但是该版本的库只支持解析GPS,不支持解析BD2的协议及两者混合的协议
官方库下载地址为:跳转

2. 双模GPS模块

NMEA消息头分为三种
1.GP代表GPS系统单独定位
2.BD代表BD2系统单独定位
3.GN代表GPS与DB2系统混合定位

截取的部分双模GPS模块的数据包如下

$GPGSV,4,3,15,193,82,240,,22,55,320,,10,42,179,,26,14,201,*46
$GPGSV,4,4,15,23,12,162,,1,9,300,,21,7,280,*7F
$BDGSV,3,1,09,209,70,350,,225,56,177,,224,53,65,,206,50,304,*59
$BDGSV,3,2,09,201,38,143,,202,37,221,,210,22,185,,216,22,291,*6B
$BDGSV,3,3,09,213,12,201,*61
$GNRMC,030852.200,A,1234.92417,N,11234.14385,E,0.000,31.61,291222,,,A*75
$GNZDA,030852.200,29,12,2022,00,00*4C
$GNTXT,01,01,01,ANT_OK*50
$GNGGA,030852.300,1234.92418,N,11234.14386,E,1,05,3.80,120.1,M,-13.7,M,,*40
$GPGSA,A,3,25,196,12,32,194,,,,,,,,5.49,3.80,3.97,1*16
$BDGSA,A,3,,,,,,,,,,,,,5.49,3.80,3.97,4*05
$GPGSV,4,1,15,29,2,122,31,25,53,74,29,196,49,157,29,12,28,48,28*7F
$GPGSV,4,2,15,32,73,38,25,194,56,119,24,199,44,160,21,31,54,266,19*4E
$GPGSV,4,3,15,193,82,240,,22,55,320,,10,42,179,,26,14,201,*46
$GPGSV,4,4,15,23,12,162,,1,9,300,,21,7,280,*7F
$BDGSV,3,1,09,209,70,350,,225,56,177,,224,53,65,,206,50,304,*59
$BDGSV,3,2,09,201,38,143,,202,37,221,,210,22,185,,216,22,291,*6B
$BDGSV,3,3,09,213,12,201,*61
$GNRMC,030852.300,A,4123.92418,N,12345.14386,E,0.000,31.61,291222,,,A*1B
$GNZDA,030852.300,29,12,2022,00,00*4D

3. 修改nmealib库

3.1 分析需要增加哪些协议的解析

这是nmealib库支持的协议 对于这些类型的数据,均增加BD及GN类型的解析

enum nmeaPACKTYPE
{
    GPNON   = 0x0000,   /**< Unknown packet type. */
    GPGGA   = 0x0001,   /**< GGA - Essential fix data which provide 3D location and accuracy data. */
    GPGSA   = 0x0002,   /**< GSA - GPS receiver operating mode, SVs used for navigation, and DOP values. */
    GPGSV   = 0x0004,   /**< GSV - Number of SVs in view, PRN numbers, elevation, azimuth & SNR values. */
    GPRMC   = 0x0008,   /**< RMC - Recommended Minimum Specific GPS/TRANSIT Data. */
    GPVTG   = 0x1000,   /**< VTG - Actual track made good and speed over ground. */
};
3.2 修改sentence.h及sentence.c文件

修改nmeaPACKTYPE 结构体 增加新的数据类型

enum nmeaPACKTYPE
{
    GPNON   = 0x0000,   /**< Unknown packet type. */
    GPGGA   = 0x0001,   /**< GGA - Essential fix data which provide 3D location and accuracy data. */
    BDGGA   = 0x0010,   /**< GGA - Essential fix data which provide 3D location and accuracy data. */
    GNGGA   = 0x0100,   /**< GGA - Essential fix data which provide 3D location and accuracy data. */
    GPGSA   = 0x0002,   /**< GSA - GPS receiver operating mode, SVs used for navigation, and DOP values. */
    BDGSA   = 0x0020,   /**< GSA - GPS receiver operating mode, SVs used for navigation, and DOP values. */
    GNGSA   = 0x0200,   /**< GSA - GPS receiver operating mode, SVs used for navigation, and DOP values. */
    GPGSV   = 0x0004,   /**< GSV - Number of SVs in view, PRN numbers, elevation, azimuth & SNR values. */
    BDGSV   = 0x0040,   /**< GSV - Number of SVs in view, PRN numbers, elevation, azimuth & SNR values. */
    GNGSV   = 0x0400,   /**< GSV - Number of SVs in view, PRN numbers, elevation, azimuth & SNR values. */
    GPRMC   = 0x0008,   /**< RMC - Recommended Minimum Specific GPS/TRANSIT Data. */
    BDRMC   = 0x0080,   /**< RMC - Recommended Minimum Specific GPS/TRANSIT Data. */
    GNRMC   = 0x0800,   /**< RMC - Recommended Minimum Specific GPS/TRANSIT Data. */
    GPVTG   = 0x1000,   /**< VTG - Actual track made good and speed over ground. */
    BDVTG   = 0x2000,   /**< VTG - Actual track made good and speed over ground. */
    GNVTG   = 0x4000    /**< VTG - Actual track made good and speed over ground. */
};

每个类型均需要增加相应的结构体,由于BD及GN的数据与GP除了数据头(GNGGA GPGGA BDGGA)不一样之外别的都一样,所以在原有的结构体之上增加名称即可。示例: 增加nameBDGGA与nameGNGGA

typedef struct _nmeaGPGGA
{
    nmeaTIME utc;       /**< UTC of position (just time) */
    /*.... 其余的省略了*/
} nmeaGPGGA, nmeaBDGGA, nmeaGNGGA;
3.3 修改info.h

info.h声明了info结构体,用于存储GNSS解析后的信息

修改nmeaSATINFO结构体

typedef struct _nmeaSATINFO
{
    int     inuse;      /**< Number of satellites in use (not those in view) */
    int     inuseGP;      /**< Number of satellites in use (not those in view) */
    int     inuseBD;      /**< Number of satellites in use (not those in view) */
    int     inuseGN;      /**< Number of satellites in use (not those in view) */
    int     inview;     /**< Total number of satellites in view */
    int     inviewGP;     /**< Total number of satellites in view */
    int     inviewBD;     /**< Total number of satellites in view */
    int     inviewGN;     /**< Total number of satellites in view */
    int     sat_prnGP[NMEA_MAXSAT]; /*存储GP包中使用的卫星id*/
    int     sat_prnBD[NMEA_MAXSAT]; /*存储BD包中使用的卫星id*/
    int     sat_prnGN[NMEA_MAXSAT]; /*存储GN包中使用的卫星id*/
    nmeaSATELLITE sat[NMEA_MAXSAT]; /**< Satellites information */
    nmeaSATELLITE satGP[NMEA_MAXSAT]; /**< Satellites information */
    nmeaSATELLITE satBD[NMEA_MAXSAT]; /**< Satellites information */
    nmeaSATELLITE satGN[NMEA_MAXSAT]; /**< Satellites information */
    nmeaGenerNumber insig_greater35;
    nmeaGenerNumber insig_32to35;
} nmeaSATINFO;
3.4 修改parse.c .h文件

对所有的nmea_parse_*方法 增加BD与GN的解析
对所有的name_*2info方法 增加BD与GN的解析

需要注意的是,对于GSA以及GSV数据来说,需要对应进行解析 例:GPGSA和GPGSV解析出来的数据进行关联才能拿到GPS系统的卫星数量及信号强度信息,BD及GN是一样的

示例如下:

//parse.h文件

int nmea_parse_GPGGA(const char *buff, int buff_sz, nmeaGPGGA *pack);
int nmea_parse_BDGGA(const char* buff, int buff_sz, nmeaBDGGA* pack);
int nmea_parse_GNGGA(const char* buff, int buff_sz, nmeaGNGGA* pack);

void nmea_GPGGA2info(nmeaGPGGA *pack, nmeaINFO *info);
void nmea_BDGGA2info(nmeaBDGGA* pack, nmeaINFO* info);
void nmea_GNGGA2info(nmeaGNGGA* pack, nmeaINFO* info);

//parse.c

#define NMEA_SYSTEM_TYPE_GP "GP"
#define NMEA_SYSTEM_TYPE_BD "BD"
#define NMEA_SYSTEM_TYPE_GN "GN"

/*增加一个通用的解析方法 用于解析除数据头之外的所有的数据*/
int nmea_parse_GGA(const char* buff, int buff_sz,const char* sysType, nmeaGPGGA* pack)
{
    char time_buff[NMEA_TIMEPARSE_BUF];
    char nmeaSysID[3] = { 0 };
    NMEA_ASSERT(buff && pack);

    memset(pack, 0, sizeof(nmeaGPGGA));

    nmea_trace_buff(buff, buff_sz);

    if (15 != nmea_scanf(buff, buff_sz,
        "$%2sGGA,%s,%f,%C,%f,%C,%d,%d,%f,%f,%C,%f,%C,%f,%d*",
        &(nmeaSysID[0]),
        &(time_buff[0]),
        &(pack->lat), &(pack->ns), &(pack->lon), &(pack->ew),
        &(pack->sig), &(pack->satinuse), &(pack->HDOP), &(pack->elv), &(pack->elv_units),
        &(pack->diff), &(pack->diff_units), &(pack->dgps_age), &(pack->dgps_sid)))
    {
        nmea_error("%sGGA parse error!",sysType);
        return 0;
    }
    if (0 != memcmp(nmeaSysID, sysType, 2)) {
        nmea_error("%sGGA sys type error parse[%s]!", sysType, nmeaSysID);
        return 0;
    }
    if (0 != _nmea_parse_time(&time_buff[0], (int)strlen(&time_buff[0]), &(pack->utc)))
    {
        nmea_error("%sGGA time parse error!",sysType);
        return 0;
    }

    return 1;
}
int nmea_parse_GPGGA(const char *buff, int buff_sz, nmeaGPGGA *pack)
{
    return nmea_parse_GGA(buff, buff_sz, NMEA_SYSTEM_TYPE_GP, (nmeaGPGGA*)pack);
}
int nmea_parse_BDGGA(const char* buff, int buff_sz, nmeaBDGGA* pack)
{
    return nmea_parse_GGA(buff, buff_sz, NMEA_SYSTEM_TYPE_BD, (nmeaGPGGA*)pack);
}
int nmea_parse_GNGGA(const char* buff, int buff_sz, nmeaGNGGA* pack)
{
    return nmea_parse_GGA(buff, buff_sz, NMEA_SYSTEM_TYPE_GN, (nmeaGPGGA*)pack);
}


//转换方法也一样
void nmea_GGA2info(nmeaGPGGA* pack, nmeaINFO* info,int type)
{
    NMEA_ASSERT(pack && info);

    info->utc.hour = pack->utc.hour;
    info->utc.min = pack->utc.min;
    info->utc.sec = pack->utc.sec;
    info->utc.hsec = pack->utc.hsec;
    info->sig = pack->sig;
    info->HDOP = pack->HDOP;
    info->elv = pack->elv;
    info->lat = ((pack->ns == 'N') ? pack->lat : -(pack->lat));
    info->lon = ((pack->ew == 'E') ? pack->lon : -(pack->lon));
    info->smask |= type;
}
void nmea_GPGGA2info(nmeaGPGGA *pack, nmeaINFO *info)
{
    nmea_GGA2info(pack, info, GPGGA);
}
void nmea_BDGGA2info(nmeaBDGGA* pack, nmeaINFO* info)
{
    nmea_GGA2info(pack, info, BDGGA);
}
void nmea_GNGGA2info(nmeaGNGGA* pack, nmeaINFO* info)
{
    nmea_GGA2info(pack, info, GNGGA);
}

//GPGSA与GPGSV数据的解析  BD与GN是一样的道理
void nmea_GPGSA2info(nmeaGPGSA *pack, nmeaINFO *info)
{
    int i, j, nuse = 0;

    NMEA_ASSERT(pack && info);

    info->fix = pack->fix_type;
    info->PDOP = pack->PDOP;
    info->HDOP = pack->HDOP;
    info->VDOP = pack->VDOP;

    for(i = 0; i < NMEA_MAXSAT; ++i)
    {
        info->satinfo.sat_prnGP[i] = pack->sat_prn[i]; //存到GP数组中
    }
    info->smask |= GPGSA;
}
void nmea_GPGSV2info(nmeaGPGSV *pack, nmeaINFO *info)
{
    int isat, isi, nsat;

    NMEA_ASSERT(pack && info);

    if(pack->pack_index > pack->pack_count ||
        pack->pack_index * NMEA_SATINPACK > NMEA_MAXSAT)
        return;

    if(pack->pack_index < 1)
        pack->pack_index = 1;
    if (pack->pack_index == 1) {
        info->satinfo.inuseGP = 0;
    }

    info->satinfo.inviewGP = pack->sat_count;
    info->satinfo.inview = info->satinfo.inviewGP + info->satinfo.inviewBD +info->satinfo.inviewGP;

    nsat = (pack->pack_index - 1) * NMEA_SATINPACK;
    nsat = (nsat + NMEA_SATINPACK > pack->sat_count)?pack->sat_count - nsat:NMEA_SATINPACK;

    for(isat = 0; isat < nsat; ++isat)
    {
        isi = (pack->pack_index - 1) * NMEA_SATINPACK + isat;
        info->satinfo.satGP[isi].id = pack->sat_data[isat].id;
        info->satinfo.satGP[isi].elv = pack->sat_data[isat].elv;
        info->satinfo.satGP[isi].azimuth = pack->sat_data[isat].azimuth;
        info->satinfo.satGP[isi].sig = pack->sat_data[isat].sig;
        info->satinfo.satGP[isi].in_use = 0;
        for (int j = 0; j < NMEA_MAXSAT; ++j)
        {
            if (info->satinfo.sat_prnGP[j] && (info->satinfo.sat_prnGP[j] == info->satinfo.satGP[isi].id))
            {
                info->satinfo.satGP[isi].in_use = 1;
                info->satinfo.inuseGP++;
                break;
            }
        }
    }
    info->satinfo.inuse = info->satinfo.inuseGP + info->satinfo.inuseBD + info->satinfo.inuseGN;

    info->smask |= GPGSV;
}

3.5 增加对应方法的调用
//parser.c
int nmea_parse(    
    nmeaPARSER *parser,
    const char *buff, int buff_sz,
    nmeaINFO *info
    )
{
    int ptype, nread = 0;
    void *pack = 0;

    NMEA_ASSERT(parser && parser->buffer);

    nmea_parser_push(parser, buff, buff_sz);

    while(GPNON != (ptype = nmea_parser_pop(parser, &pack)))
    {
        nread++;

        switch(ptype)
        {
        case GPGGA:
            nmea_GPGGA2info((nmeaGPGGA *)pack, info);
            break;
        case BDGGA:
            nmea_BDGGA2info((nmeaBDGGA*)pack, info);
            break;
        case GNGGA:
            nmea_GNGGA2info((nmeaGNGGA*)pack, info);
            break;
        case GPGSA:
            nmea_GPGSA2info((nmeaGPGSA *)pack, info);
            break;
        case BDGSA:
            nmea_BDGSA2info((nmeaBDGSA*)pack, info);
            break;
        case GNGSA:
            nmea_GNGSA2info((nmeaGNGSA*)pack, info);
            break;
         //下面的一样 就不罗列出来了
        };

        free(pack);
    }

    return nread;
}


int nmea_parser_real_push(nmeaPARSER *parser, const char *buff, int buff_sz)
{
 //...省略部分代码
            switch(ptype)
            {
            case GPGGA:
                if(0 == (node->pack = malloc(sizeof(nmeaGPGGA))))
                    goto mem_fail;
                node->packType = GPGGA;
                if(!nmea_parse_GPGGA(
                    (const char *)parser->buffer + nparsed,
                    sen_sz, (nmeaGPGGA *)node->pack))
                {
                    free(node);
                    node = 0;
                }
                break;
            case BDGGA:
                if (0 == (node->pack = malloc(sizeof(nmeaBDGGA))))
                    goto mem_fail;
                node->packType = BDGGA;
                if (!nmea_parse_BDGGA(
                    (const char*)parser->buffer + nparsed,
                    sen_sz, (nmeaBDGGA*)node->pack))
                {
                    free(node);
                    node = 0;
                }
                break;
            case GNGGA:
                if (0 == (node->pack = malloc(sizeof(nmeaGNGGA))))
                    goto mem_fail;
                node->packType = GNGGA;
                if (!nmea_parse_GNGGA(
                    (const char*)parser->buffer + nparsed,
                    sen_sz, (nmeaGNGGA*)node->pack))
                {
                    free(node);
                    node = 0;
                }
                break;
               //后面的就不罗列出来了
 //...
}

4. 结束

项目源码

到这里 修改nmeaLib的解析就完成了,以上只修改了解析数据的接口,对于解析文件等没有做修改!!!

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值