|
|
/*
|
|
|
* nmeaParser.cpp
|
|
|
*
|
|
|
* Created on: Oct 21, 2014
|
|
|
* Author: Alan Aguilar Sologuren
|
|
|
*/
|
|
|
|
|
|
#include "nmea_defs.h"
|
|
|
#include "nmeaParser.h"
|
|
|
|
|
|
/**
|
|
|
* \brief Initialization of parser object
|
|
|
*/
|
|
|
nmeaParser::nmeaParser():
|
|
|
top_node(nullptr),end_node(nullptr),
|
|
|
buffer(nullptr),buff_size(0),
|
|
|
buff_use(0){
|
|
|
int buff_sz = nmea_property()->parse_buff_size;
|
|
|
NMEA_ASSERT(this);
|
|
|
|
|
|
if(buff_sz < NMEA_MIN_PARSEBUFF)
|
|
|
buff_sz = NMEA_MIN_PARSEBUFF;
|
|
|
|
|
|
if(0 == (buffer = malloc(buff_size)))
|
|
|
nmea_error("Insufficient memory!");
|
|
|
delete this;
|
|
|
else
|
|
|
{
|
|
|
buff_size = buff_sz;
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* \brief Destroy parser object
|
|
|
*/
|
|
|
nmeaParser::~nmeaParser() {
|
|
|
NMEA_ASSERT(this && buffer);
|
|
|
free(buffer);
|
|
|
nmea_parser_queue_clear();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* \brief Analysis of buffer and put results to information structure
|
|
|
* @return Number of packets wos parsed
|
|
|
*/
|
|
|
int nmeaParser::nmea_parse(const char *buff, int buff_sz, nmeaInfo *info )
|
|
|
{
|
|
|
int ptype, nread = 0;
|
|
|
nmeaCode *pack = 0;
|
|
|
|
|
|
NMEA_ASSERT(this && buffer);
|
|
|
|
|
|
nmea_parser_push(buff, buff_sz);
|
|
|
|
|
|
while(GPNON != (ptype = nmea_parser_pop(&pack)))
|
|
|
{
|
|
|
nread++;
|
|
|
code_2info(pack, info);
|
|
|
free(pack);
|
|
|
}
|
|
|
|
|
|
return nread;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* low level
|
|
|
*/
|
|
|
|
|
|
int nmeaParser::nmea_parser_real_push(const char *buff, int buff_sz)
|
|
|
{
|
|
|
int nparsed = 0, crc, sen_sz, ptype;
|
|
|
nmeaParserNODE *node = 0;
|
|
|
|
|
|
NMEA_ASSERT(this && buffer);
|
|
|
|
|
|
/* add */
|
|
|
if(buff_use + buff_sz >= buff_size)
|
|
|
nmea_parser_buff_clear(parser);
|
|
|
|
|
|
memcpy(buffer + buff_use, buff, buff_sz);
|
|
|
buff_use += buff_sz;
|
|
|
|
|
|
/* parse */
|
|
|
for(;;node = 0)
|
|
|
{
|
|
|
sen_sz = nmea_find_tail(
|
|
|
(const char *)buffer + nparsed,
|
|
|
(int)buff_use - nparsed, &crc);
|
|
|
|
|
|
if(!sen_sz)
|
|
|
{
|
|
|
if(nparsed)
|
|
|
memcpy(
|
|
|
buffer,
|
|
|
buffer + nparsed,
|
|
|
buff_use -= nparsed);
|
|
|
break;
|
|
|
}
|
|
|
else if(crc >= 0)
|
|
|
{
|
|
|
if(!node->pack->code_parse( (const char *)buffer + nparsed,
|
|
|
sen_sz)
|
|
|
{
|
|
|
free(node);
|
|
|
node = 0;
|
|
|
}
|
|
|
|
|
|
if(node)
|
|
|
{
|
|
|
if(end_node)
|
|
|
((nmeaParserNODE *)end_node)->next_node = node;
|
|
|
end_node = node;
|
|
|
if(!top_node)
|
|
|
top_node = node;
|
|
|
node->next_node = 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
nparsed += sen_sz;
|
|
|
}
|
|
|
return nparsed;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* \brief Analysis of buffer and keep results into parser
|
|
|
* @return Number of bytes wos parsed from buffer
|
|
|
*/
|
|
|
int nmeaParser::nmea_parser_push(const char *buff, int buff_sz)
|
|
|
{
|
|
|
int nparse, nparsed = 0;
|
|
|
|
|
|
do
|
|
|
{
|
|
|
if(buff_sz > buff_size)
|
|
|
nparse = buff_size;
|
|
|
else
|
|
|
nparse = buff_sz;
|
|
|
|
|
|
nparsed += nmea_parser_real_push(
|
|
|
buff, nparse);
|
|
|
|
|
|
buff_sz -= nparse;
|
|
|
|
|
|
} while(buff_sz);
|
|
|
|
|
|
return nparsed;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* \brief Get type of top packet keeped into parser
|
|
|
* @return Type of packet
|
|
|
* @see nmeaPACKTYPE
|
|
|
*/
|
|
|
int nmeaParser::nmea_parser_top()
|
|
|
{
|
|
|
int retval = GPNON;
|
|
|
nmeaParserNODE *node = (nmeaParserNODE *)top_node;
|
|
|
|
|
|
NMEA_ASSERT(this && buffer);
|
|
|
|
|
|
if(node)
|
|
|
retval = node->pack->type;
|
|
|
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* \brief Withdraw top packet from parser
|
|
|
* @return Received packet type
|
|
|
* @see nmeaPACKTYPE
|
|
|
*/
|
|
|
int nmeaParser::nmea_parser_pop( nmeaCode **pack_ptr)
|
|
|
{
|
|
|
int retval = GPNON;
|
|
|
nmeaParserNODE *node = (nmeaParserNODE *)top_node;
|
|
|
|
|
|
NMEA_ASSERT(this && buffer);
|
|
|
|
|
|
if(node)
|
|
|
{
|
|
|
*pack_ptr = node->pack;
|
|
|
retval = node->pack->type;
|
|
|
top_node = node->next_node;
|
|
|
if(!top_node)
|
|
|
end_node = 0;
|
|
|
free(node);
|
|
|
}
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* \brief Get top packet from parser without withdraw
|
|
|
* @return Received packet type
|
|
|
* @see nmeaPACKTYPE
|
|
|
*/
|
|
|
int nmeaParser::nmea_parser_peek(nmeaCode **pack_ptr)
|
|
|
{
|
|
|
int retval = GPNON;
|
|
|
nmeaParserNODE *node = (nmeaParserNODE *)top_node;
|
|
|
|
|
|
NMEA_ASSERT(this && buffer);
|
|
|
|
|
|
if(node)
|
|
|
{
|
|
|
*pack_ptr = node->pack;
|
|
|
retval = node->pack->type;
|
|
|
}
|
|
|
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* \brief Delete top packet from parser
|
|
|
* @return Deleted packet type
|
|
|
* @see nmeaPACKTYPE
|
|
|
*/
|
|
|
int nmeaParser::nmea_parser_drop()
|
|
|
{
|
|
|
int retval = GPNON;
|
|
|
nmeaParserNODE *node = (nmeaParserNODE *)top_node;
|
|
|
|
|
|
NMEA_ASSERT(this && buffer);
|
|
|
|
|
|
if(node)
|
|
|
{
|
|
|
if(node->pack)
|
|
|
free(node->pack);
|
|
|
retval = node->pack->type;
|
|
|
top_node = node->next_node;
|
|
|
if(!top_node)
|
|
|
end_node = 0;
|
|
|
free(node);
|
|
|
}
|
|
|
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* \brief Clear cache of parser
|
|
|
* @return true (1) - success
|
|
|
*/
|
|
|
int nmeaParser::nmea_parser_buff_clear()
|
|
|
{
|
|
|
NMEA_ASSERT(this && buffer);
|
|
|
buff_use = 0;
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* \brief Clear packets queue into parser
|
|
|
* @return true (1) - success
|
|
|
*/
|
|
|
int nmeaParser::nmea_parser_queue_clear()
|
|
|
{
|
|
|
NMEA_ASSERT(this);
|
|
|
while(top_node)
|
|
|
nmea_parser_drop();
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
virtual void nmeaParser::code_2info(nmeaCode* code, nmeaInfo* info) {
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
int nmeaParser::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 = code_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;
|
|
|
}
|
|
|
|