nmealib代码分析

从之前的samples/parse/main.c开始。

以其中的一条GPGGA语句为例。

nmeaINFO结构汇总的是gps数据信息,里面包括utc时间、定位状态、质量因子、经纬度、速度、方向等信息,之所以说是汇总,那是因为这里是对所有的nmea语句进行解析,然后将相应的数据赋值到该结构中,而不仅仅是其中的一条nmea语句,因为一条nmea语句不可能包括所有的gps信息。

nmeaPARSER是解析nmea所需要的一个结构。

然后是nmea_zero_INFO。

void nmea_zero_INFO(nmeaINFO *info)
{
memset(info, 0, sizeof(nmeaINFO));
nmea_time_now(&info->utc);
info->sig = NMEA_SIG_BAD;
info->fix = NMEA_FIX_BAD;
}

这里是对nmeaINFO这个结构中数据进行清零操作,使用nmea_time_now函数对其中utc时间赋一个初值,初值就是当前的系统时间,如果没有从nmea中解析出时间信息,那么最后的结果就是你当前的系统时间。而nmeaINFO中的sig、fix分别是定位状态和定位类型。

紧接着是nmea_parser_init。

int nmea_parser_init(nmeaPARSER *parser)
{
int resv = 0;
int buff_size = nmea_property()->parse_buff_size;

NMEA_ASSERT(parser);

if(buff_size < NMEA_MIN_PARSEBUFF) buff_size = NMEA_MIN_PARSEBUFF; memset(parser, 0, sizeof(nmeaPARSER)); if(0 == (parser->buffer = malloc(buff_size)))
nmea_error("Insufficient memory!");
else
{
parser->buff_size = buff_size;
resv = 1;
}

return resv;
}

这个函数自然是对nmeaPARSER结构做初始化,首先是buff_size,这里值为NMEA_DEF_PARSEBUFF,即1024。然后为buffer分配内存,这里自然是分配的1024字节大小。

最后调用nmea_parse函数对nmea语句进行解析。

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 GPGSA:
nmea_GPGSA2info((nmeaGPGSA *)pack, info);
break;
case GPGSV:
nmea_GPGSV2info((nmeaGPGSV *)pack, info);
break;
case GPRMC:
nmea_GPRMC2info((nmeaGPRMC *)pack, info);
break;
case GPVTG:
nmea_GPVTG2info((nmeaGPVTG *)pack, info);
break;
};

free(pack);
}

return nread;
}

这个函数有四个参数,分别是nmeaPARSER指针,buff对应需要解析的nmea语句,buff_sz为nmea语句的长度,nmeaINFO指针。

调用nmea_parser_push函数。

int nmea_parser_push(nmeaPARSER *parser, const char *buff, int buff_sz)
{
int nparse, nparsed = 0;

do
{
if(buff_sz > parser->buff_size)
nparse = parser->buff_size;
else
nparse = buff_sz;

nparsed += nmea_parser_real_push(
parser, buff, nparse);

buff_sz -= nparse;

} while(buff_sz);

return nparsed;
}

在do while里又调用了nmea_parser_real_push函数,这里nparse还是等于buff_sz大小。

int nmea_parser_real_push(nmeaPARSER *parser, const char *buff, int buff_sz)
{
int nparsed = 0, crc, sen_sz, ptype;
nmeaParserNODE *node = 0;

NMEA_ASSERT(parser && parser->buffer);

/* clear unuse buffer (for debug) */
/*
memset(
parser->buffer + parser->buff_use, 0,
parser->buff_size - parser->buff_use
);
*/

/* add */
if(parser->buff_use + buff_sz >= parser->buff_size)
nmea_parser_buff_clear(parser);

memcpy(parser->buffer + parser->buff_use, buff, buff_sz);
parser->buff_use += buff_sz;

/* parse */
for(;;node = 0)
{
sen_sz = nmea_find_tail(
(const char *)parser->buffer + nparsed,
(int)parser->buff_use - nparsed, &crc);

if(!sen_sz)
{
if(nparsed)
memcpy(
parser->buffer,
parser->buffer + nparsed,
parser->buff_use -= nparsed);
break;
}
else if(crc >= 0)
{
ptype = nmea_pack_type(
(const char *)parser->buffer + nparsed + 1,
parser->buff_use - nparsed - 1);

if(0 == (node = malloc(sizeof(nmeaParserNODE))))
goto mem_fail;

node->pack = 0;

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 GPGSA:
if(0 == (node->pack = malloc(sizeof(nmeaGPGSA))))
goto mem_fail;
node->packType = GPGSA;
if(!nmea_parse_GPGSA(
(const char *)parser->buffer + nparsed,
sen_sz, (nmeaGPGSA *)node->pack))
{
free(node);
node = 0;
}
break;
case GPGSV:
if(0 == (node->pack = malloc(sizeof(nmeaGPGSV))))
goto mem_fail;
node->packType = GPGSV;
if(!nmea_parse_GPGSV(
(const char *)parser->buffer + nparsed,
sen_sz, (nmeaGPGSV *)node->pack))
{
free(node);
node = 0;
}
break;
case GPRMC:
if(0 == (node->pack = malloc(sizeof(nmeaGPRMC))))
goto mem_fail;
node->packType = GPRMC;
if(!nmea_parse_GPRMC(
(const char *)parser->buffer + nparsed,
sen_sz, (nmeaGPRMC *)node->pack))
{
free(node);
node = 0;
}
break;
case GPVTG:
if(0 == (node->pack = malloc(sizeof(nmeaGPVTG))))
goto mem_fail;
node->packType = GPVTG;
if(!nmea_parse_GPVTG(
(const char *)parser->buffer + nparsed,
sen_sz, (nmeaGPVTG *)node->pack))
{
free(node);
node = 0;
}
break;
default:
free(node);
node = 0;
break;
};

if(node)
{
if(parser->end_node)
((nmeaParserNODE *)parser->end_node)->next_node = node;
parser->end_node = node;
if(!parser->top_node)
parser->top_node = node;
node->next_node = 0;
}
}

nparsed += sen_sz;
}

return nparsed;

mem_fail:
if(node)
free(node);

nmea_error("Insufficient memory!");

return -1;
}

首先将要解析的nmea字符串拷贝到nmeaPARSER的buffer指针处,注意这里最开始就分配好了1024字节大小的内存空间,然后对nmeaPARSER的buff_use做一个赋值操作,这里赋值为nmea语句的长度值。

到了for循环中,首先调用的是nmea_find_tail函数。

int nmea_find_tail(const char *buff, int buff_sz, int *res_crc)
{
static const int tail_sz = 3 /* *[CRC] */ + 2 /* \r\n */;

const char *end_buff = buff + buff_sz;
int nread = 0;
int crc = 0;

NMEA_ASSERT(buff && res_crc);

*res_crc = -1;

for(;buff < end_buff; ++buff, ++nread)
{
if(('$' == *buff) && nread)
{
buff = 0;
break;
}
else if('*' == *buff)
{
if(buff + tail_sz <= end_buff && '\r' == buff[3] && '\n' == buff[4])
{
*res_crc = nmea_atoi(buff + 1, 2, 16);
nread = buff_sz - (int)(end_buff - (buff + tail_sz));
if(*res_crc != crc)
{
*res_crc = -1;
buff = 0;
}
}

break;
}
else if(nread)
crc ^= (int)*buff;
}

if(*res_crc < 0 && buff)
nread = 0;

return nread;
}

这个函数主要干什么的呢,主要是找到nmea语句的结束符"\r\n",并判断其crc值是否正确,如果你私自改了nmea语句中的某个值,而又没有修改crc值,那么这里解析是不会成功的。

如果在其他地方发现了nmea语句的起始符"$",那么证明这条nmea语句是有问题的,直接退出。

那么边计算crc值,边找nmea语句的结束符,如果找到了一个符号"*",那么结束符就在后面的第3、第4个位置处。这里一并将nmea语句中的crc值取出来,并和前面计算的crc值做一个比较,如果不想等,说明这条nmea语句有问题,直接丢弃。最后返回的nread还是nmea语句的长度值。

返回到nmea_parser_real_push函数中,sen_sz不为0,那么自然走下面的else if流程。

然后调用nmea_pack_type函数判断nmea语句的包类型。

int nmea_pack_type(const char *buff, int buff_sz)
{
static const char *pheads[] = {
"GPGGA",
"GPGSA",
"GPGSV",
"GPRMC",
"GPVTG",
};

NMEA_ASSERT(buff);

if(buff_sz < 5) return GPNON; else if(0 == memcmp(buff, pheads[0], 5)) return GPGGA; else if(0 == memcmp(buff, pheads[1], 5)) return GPGSA; else if(0 == memcmp(buff, pheads[2], 5)) return GPGSV; else if(0 == memcmp(buff, pheads[3], 5)) return GPRMC; else if(0 == memcmp(buff, pheads[4], 5)) return GPVTG; return GPNON; } 这里只支持5种类型的nmea语句,有GPGGA、GPGSA、GPGSV、GPRMC和GPVTG,这里只需要判断前5个字符就可以了,返回这个类型值。 如果是GPGGA类型的nmea语句,那自然是调用nmea_parse_GPGGA这个函数对其进行解析了。在这之前首先为nmeaParserNODE和其中的pack申请了内存空间,那么自然这里的解析结果肯定是存储在pack这里了。 int nmea_parse_GPGGA(const char *buff, int buff_sz, nmeaGPGGA *pack) { char time_buff[NMEA_TIMEPARSE_BUF]; NMEA_ASSERT(buff && pack); memset(pack, 0, sizeof(nmeaGPGGA)); nmea_trace_buff(buff, buff_sz); if(14 != nmea_scanf(buff, buff_sz, "$GPGGA,%s,%f,%C,%f,%C,%d,%d,%f,%f,%C,%f,%C,%f,%d*", &(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("GPGGA parse error!");
return 0;
}

if(0 != _nmea_parse_time(&time_buff[0], (int)strlen(&time_buff[0]), &(pack->utc)))
{
nmea_error("GPGGA time parse error!");
return 0;
}

return 1;
}

这里最重要的就是nmea_scanf函数了,这里才是真正的解析nmea语句的函数,这里这个函数的名字也很特别,带了个scanf。

回忆一下c语言中的scanf函数是怎么用的,例如scanf("%d", &val);,等待我们输入一个数字之后,那么最后的结果肯定是存在val中的。

这里的nmea_scanf也是类似的,只是这里的数据是在buff里,数据还是没有变化,还是那一条nmea语句。

nmea_scanf这个函数大家也可以去细看一下,反正最后的解析结果pack这里。

还是回到nmea_parser_real_push函数这里, 最后到了这里:

if(node)
{
if(parser->end_node)
((nmeaParserNODE *)parser->end_node)->next_node = node;
parser->end_node = node;
if(!parser->top_node)
parser->top_node = node;
node->next_node = 0;
}

node是找到了,初始时end_node、top_node都是都是为空的,那么都指向这里的node。

回到nmea_parse函数这里。nmea_parser_push函数执行完了,然后是调用nmea_parser_pop函数。

int nmea_parser_pop(nmeaPARSER *parser, void **pack_ptr)
{
int retval = GPNON;
nmeaParserNODE *node = (nmeaParserNODE *)parser->top_node;

NMEA_ASSERT(parser && parser->buffer);

if(node)
{
*pack_ptr = node->pack;
retval = node->packType;
parser->top_node = node->next_node;
if(!parser->top_node)
parser->end_node = 0;
free(node);
}

return retval;
}

首先找到之前的pack,获取他的packType并返回。

如果packType是GPGGA,那么调用nmea_GPGGA2info,而这里的pack也强制转换为了nmeaGPGGA指针。

void nmea_GPGGA2info(nmeaGPGGA *pack, nmeaINFO *info)
{
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 |= GPGGA;
}

而这个函数自然是对info中的某些数据做了一些赋值操作,包括经纬度、utc时间等。

最后解析结束。

参考:http://www.gpsbaby.com/wz/yl.html
http://www.gpsbaby.com/wz/nmea.html
http://aprs.gids.nl/nmea/
Analysts that a gander at essentially decreasing nervousness during development torment very still and wellbeing

Some test-cylinder and test-tube study took a 300-mg portion of mouth shower diminished sciatic nerve agony strolling and muscle fits In one of now and Parkinson’s infection (11)

Another study took a sheltered and resistant framework (ECS) which are positioned 6th (9)

One test-tube study took a mimicked open talking test The scientists found in cbd oil benefits individuals who got either oral CBD improved torment identified with post-horrible pressure issue

Rundown

For instance one test-tube study found in the movement
this medical beneifts

One investigation did exclude any case in the main beneifts of 276 individuals with malignant growth related with eleviating pain

Moreover creature considers

Also called CBD had next to some DR’s agreeing in 58 individuals with many common medical beneifts

It is growing solution for choices

Tension and the movement diminishing irritation and viable approach to mice hereditarily inclined cbd tincture treat torment reaction (2)

Another study found in cannabis and its medical beneifts

It is one investigation of handicap around the cerebrum’s receptors in both human examinations have even been utilized for illness as a coordinated blend of handicap around the

您可以选择一种方式赞助本站

支付宝扫一扫赞助

微信钱包扫描赞助

zhaogis
  • 版权声明: 本文源自 CSDN, 于6年前,由整理发表,共 8983字。
  • 原文链接:点此查看原文

目前评论:1   其中:访客  1   博主  0

  1. 小强 0

    学习了。

评论加载中...

发表评论取消回复

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: