Skip to content

NUSHSat/NMEA-Parser

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

C Library for Parsing NMEA 0183 Sentences

Build Status Memory Leaks License

Libnmea is a lightweight C library that parses NMEA 0183 sentence strings into structs. It is written in a modular architecture that dynamically loads a parser module for each implemented sentence type. This way, new sentences can easily be added to the library without modifying the core code. It is also possible to statically link the parser modules at build time to enable libnmea to be used in environments where a dynamic loader isn't available.

If you find any sentence missing, please add it by contributing to the code. I am open to suggestions regarding the code and architecture, so if you have any ideas or improvements, please tell me or submit a merge request :-).

Supported sentences: GPGGA, GPGLL, GPGSA, GPGSV, GPRMC, GPTXT, and GPVTG.

To build

cmake -B ./build
cmake --build ./build

When running cmake, the library will be built to a local build directory (./build).

How to use it

First, include nmea.h and the header files for the desired sentence types:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <nmea.h>
#include <nmea/gpgll.h>
#include <nmea/gpgga.h>

int
main(void)
{
	/* ... */
	return 0;
}

To parse an NMEA sentence string, use nmea_parse():

// Sentence string to be parsed
char sentence[] = "$GPGLL,4916.45,N,12311.12,W,225444,A,*1D\r\n";

// Pointer to struct containing the parsed data
nmea_s *data;

// Parse it...
data = nmea_parse(sentence, strlen(sentence), 0);
if (NULL == data) {
	exit(EXIT_FAILURE);
}

The parsed data can be found in the data variable and for example printed to screen:

if (NMEA_GPGGA == data->type) {
	nmea_gpgga_s *gpgga = (nmea_gpgga_s *) data;

	printf("GPGGA Sentence\n");
	printf("Number of satellites: %d\n", gpgga->n_satellites);
	printf("Altitude: %d %c\n", gpgga->altitude, gpgga->altitude_unit);
}

if (NMEA_GPGLL == data->type) {
	nmea_gpgll_s *gpgll = (nmea_gpgll_s *) data;

	printf("GPGLL Sentence\n");
	printf("Longitude:\n");
	printf("  Degrees: %d\n", gpgll->longitude.degrees);
	printf("  Minutes: %f\n", gpgll->longitude.minutes);
	printf("  Cardinal: %c\n", (char) gpgll->longitude.cardinal);
	printf("Latitude:\n");
	printf("  Degrees: %d\n", gpgll->latitude.degrees);
	printf("  Minutes: %f\n", gpgll->latitude.minutes);
	printf("  Cardinal: %c\n", (char) gpgll->latitude.cardinal);
}

Free the memory used by the data variable:

nmea_free(data);

Compile with -lnmea:

$ gcc example.c -lnmea -o example

Library functions

Check nmea.h for more detailed info about functions. The header files for the sentences (ex: nmea/gpgll.h) contains the struct definitions for each sentence.

Implement a new sentence type

To create a new sentence parser, create the following files and replace the <TYPE> with the sentence type word in uppercase letters and <type> in lowercase. Make sure that the sentence type is defined in src/nmea.h and add it to src/nmea/parser_static.h.

src/parsers/.h:

#ifndef INC_NMEA_<TYPE>_H
#define INC_NMEA_<TYPE>_H

#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <nmea.h>

typedef struct {
	nmea_s base;
	/* sentence values */
} nmea_<type>_s;

/* Value indexes */
#define NMEA_<TYPE>_<index>	0
/* more value indexes... */

#endif  /* INC_NMEA_<TYPE>_H */

src/parsers/.c:

#include "../nmea/parser_types.h"
#include "<type>.h"
#include "parse.h"

int
init(nmea_parser_s *parser)
{
	/* Declare what sentence type to parse */
	NMEA_PARSER_TYPE(parser, NMEA_<TYPE>);
	NMEA_PARSER_PREFIX(parser, "<TYPE>");
	return 0;
}

int
allocate_data(nmea_parser_s *parser)
{
	parser->data = malloc(sizeof (nmea_<type>_s));
	return 0;
}

int
set_default(nmea_parser_s *parser)
{
	memset(parser->data, 0, sizeof (nmea_<type>_s));
	return 0;
}

int
free_data(nmea_s *data)
{
	free(data);
	return 0;
}

int
parse(nmea_parser_s *parser, char *value, int val_index)
{
	nmea_gpgll_s *data = (nmea_<type>_s *) parser->data;

	switch (val_index) {
	case NMEA_<TYPE>_<index>:
		/* Parse some value */
		data->some_value = value;
		break;

	default:
		break;
	}

	return 0;
}

Contributing

Contributions are more than welcome. Be sure to read this chapter before submitting a merge request.

Coding style

The code should conform to the KNF formatting guidelines.

Example indent command:

$ indent -st -bad -bap -bbb -bc -blf -bli0 -br -brs -bs -cbi0 -ce -cli0 -cs -nbfda -npcs -nprs -nsob -saf -saw -sai src/nmea/nmea.c

Example astyle command:

astyle --style=knf --indent=tab src/nmea/nmea.c

Use hard tabs. Example vim options:

:set noexpandtab
:set preserveindent
:set softtabstop=0
:set shiftwidth=4
:set tabstop=4

New sentence types

When contributing support for new sentence types, please do the following:

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published