目录
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的解析就完成了,以上只修改了解析数据的接口,对于解析文件等没有做修改!!!