aboutsummaryrefslogtreecommitdiff
path: root/apps/gps/nmealib/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/gps/nmealib/parser.c')
-rw-r--r--apps/gps/nmealib/parser.c400
1 files changed, 400 insertions, 0 deletions
diff --git a/apps/gps/nmealib/parser.c b/apps/gps/nmealib/parser.c
new file mode 100644
index 000000000..f8b415866
--- /dev/null
+++ b/apps/gps/nmealib/parser.c
@@ -0,0 +1,400 @@
+/*
+ *
+ * NMEA library
+ * URL: http://nmea.sourceforge.net
+ * Author: Tim (xtimor@gmail.com)
+ * Licence: http://www.gnu.org/licenses/lgpl.html
+ * $Id: parser.c 17 2008-03-11 11:56:11Z xtimor $
+ *
+ */
+
+/**
+ * \file parser.h
+ */
+#include "nmea/tok.h"
+#include "nmea/parse.h"
+#include "nmea/parser.h"
+#include "nmea/context.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+typedef struct _nmeaParserNODE
+{
+ int packType;
+ void *pack;
+ struct _nmeaParserNODE *next_node;
+
+} nmeaParserNODE;
+
+/*
+ * high level
+ */
+
+/**
+ * \brief Initialization of parser object
+ * @return true (1) - success or false (0) - fail
+ */
+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;
+}
+
+/**
+ * \brief Destroy parser object
+ */
+void nmea_parser_destroy(nmeaPARSER *parser)
+{
+ //NMEA_ASSERT(parser && parser->buffer);
+ free(parser->buffer);
+ nmea_parser_queue_clear(parser);
+ memset(parser, 0, sizeof(nmeaPARSER));
+}
+
+/**
+ * \brief Analysis of buffer and put results to information structure
+ * @return Number of packets wos parsed
+ */
+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;
+}
+
+/*
+ * low level
+ */
+
+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;
+}
+
+/**
+ * \brief Analysis of buffer and keep results into parser
+ * @return Number of bytes wos parsed from buffer
+ */
+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;
+}
+
+/**
+ * \brief Get type of top packet keeped into parser
+ * @return Type of packet
+ * @see nmeaPACKTYPE
+ */
+int nmea_parser_top(nmeaPARSER *parser)
+{
+ int retval = GPNON;
+ nmeaParserNODE *node = (nmeaParserNODE *)parser->top_node;
+
+ //NMEA_ASSERT(parser && parser->buffer);
+
+ if(node)
+ retval = node->packType;
+
+ return retval;
+}
+
+/**
+ * \brief Withdraw top packet from parser
+ * @return Received packet type
+ * @see nmeaPACKTYPE
+ */
+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;
+}
+
+/**
+ * \brief Get top packet from parser without withdraw
+ * @return Received packet type
+ * @see nmeaPACKTYPE
+ */
+int nmea_parser_peek(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;
+ }
+
+ return retval;
+}
+
+/**
+ * \brief Delete top packet from parser
+ * @return Deleted packet type
+ * @see nmeaPACKTYPE
+ */
+int nmea_parser_drop(nmeaPARSER *parser)
+{
+ int retval = GPNON;
+ nmeaParserNODE *node = (nmeaParserNODE *)parser->top_node;
+
+ //NMEA_ASSERT(parser && parser->buffer);
+
+ if(node)
+ {
+ if(node->pack)
+ free(node->pack);
+ retval = node->packType;
+ parser->top_node = node->next_node;
+ if(!parser->top_node)
+ parser->end_node = 0;
+ free(node);
+ }
+
+ return retval;
+}
+
+/**
+ * \brief Clear cache of parser
+ * @return true (1) - success
+ */
+int nmea_parser_buff_clear(nmeaPARSER *parser)
+{
+ //NMEA_ASSERT(parser && parser->buffer);
+ parser->buff_use = 0;
+ return 1;
+}
+
+/**
+ * \brief Clear packets queue into parser
+ * @return true (1) - success
+ */
+int nmea_parser_queue_clear(nmeaPARSER *parser)
+{
+ //NMEA_ASSERT(parser);
+ while(parser->top_node)
+ nmea_parser_drop(parser);
+ return 1;
+}