Skip to main content

GPS/GNSS NMEA Sentence Processor Library

The GPS/GNSS NMEA processing library is a set of classes that makes parsing and decoding NMEA Sentences from Global Positioning System (GPS)/Global Navigation Satellite System (GNSS) receivers easy.

GPS/GNSS peripherals communicate by sending semi-standardized sentences that have a prefix tag that describes their type, and data encoded in them, separated by commas. For instance, the following NMEA sentence is of the recommended minimum information type and encodes location (latitude, longitude, altitude) information:

"$GPRMC,000049.799,V,,,,,0.00,0.00,060180,,,N*48"

Because of their length limits, sometimes multiple sentences are needed in order to carry an entire set of information. For example, satellites in view sentences will often come in groups of three or four:

"$GPGSV,3,1,11,03,03,111,00,04,15,270,00,06,01,010,00,13,06,292,00*74"
"$GPGSV,3,2,11,14,25,170,00,16,57,208,39,18,67,296,40,19,40,246,00*74"
"$GPGSV,3,3,11,22,42,067,42,24,14,311,43,27,05,244,00,,,,*4D"

For this reason, the NMEA processing library uses an event-based, asynchronous pattern, in which sentences are passed to it, then internally routed to the correct decoder, and then events are raised as appropriate, which contain the parsed/decoded information.

Using

To use, create an instance of the NmeaSentenceProcessor, register any NMEA sentence decoders you want to use by passing an INmeaDecoder to the RegisterDecoder method, and then call ParseNmeaMessage, passing the NMEA sentence string.

For example, the following Meadow application listens to a serial port for NMEA sentences, feeds them to the NMEA processor, and then listens for decoded message events and writes them to the console:

using System;
using System.Collections.Generic;
using System.Text;
using Meadow;
using Meadow.Devices;
using Meadow.Foundation.Sensors.Location.Gnss.NmeaParsing;
using Meadow.Hardware;
using Meadow.Peripherals.Sensors.Location.Gnss;

namespace MeadowApp
{
/// <summary>
/// A simple app that listens to a serial GPS for NMEA sentences, parses
/// them, and writes them to the console.
/// </summary>
public class MeadowApp : App<F7Micro, MeadowApp>
{
ISerialMessagePort serialPort;
NmeaSentenceProcessor nmeaProcessor;

public MeadowApp()
{
Console.WriteLine($"Start the SerialGPS_Listener app.");
Initialize();
Start();
}

void Initialize()
{
serialPort = Device.CreateSerialMessagePort(
Device.PlatformOS.GetSerialPortName("COM4"),
suffixDelimiter: Encoding.UTF8.GetBytes("\r\n"),
preserveDelimiter: true);
serialPort.MessageReceived += SerialPort_MessageReceived;

InitDecoders();
}

void Start()
{
Console.WriteLine("Starting.");
serialPort.Open();
}

private void SerialPort_MessageReceived(object sender, SerialMessageData e)
{
Console.WriteLine("Message received.");

Console.WriteLine($"{e.GetMessageString(Encoding.UTF8)}");
nmeaProcessor.ProcessNmeaMessage(e.GetMessageString(Encoding.UTF8));
}

protected void InitDecoders()
{
Console.WriteLine("Create NMEA");
nmeaProcessor = new NmeaSentenceProcessor();
// verbose output
nmeaProcessor.DebugMode = true;

Console.WriteLine("Add decoders");

// GGA
var ggaDecoder = new GgaDecoder();
Console.WriteLine("Created GGA");
nmeaProcessor.RegisterDecoder(ggaDecoder);
ggaDecoder.PositionReceived += (object sender, GnssPositionInfo location) => {
Console.WriteLine("*********************************************");
Console.WriteLine(location);
Console.WriteLine("*********************************************");
};

// GLL
var gllDecoder = new GllDecoder();
nmeaProcessor.RegisterDecoder(gllDecoder);
gllDecoder.GeographicLatitudeLongitudeReceived += (object sender, GnssPositionInfo location) => {
Console.WriteLine("*********************************************");
Console.WriteLine(location);
Console.WriteLine("*********************************************");
};

// GSA
var gsaDecoder = new GsaDecoder();
nmeaProcessor.RegisterDecoder(gsaDecoder);
gsaDecoder.ActiveSatellitesReceived += (object sender, ActiveSatellites activeSatellites) => {
Console.WriteLine("*********************************************");
Console.WriteLine(activeSatellites);
Console.WriteLine("*********************************************");
};

// RMC (recommended minimum)
var rmcDecoder = new RmcDecoder();
nmeaProcessor.RegisterDecoder(rmcDecoder);
rmcDecoder.PositionCourseAndTimeReceived += (object sender, GnssPositionInfo positionCourseAndTime) => {
Console.WriteLine("*********************************************");
Console.WriteLine(positionCourseAndTime);
Console.WriteLine("*********************************************");

};

// VTG (course made good)
var vtgDecoder = new VtgDecoder();
nmeaProcessor.RegisterDecoder(vtgDecoder);
vtgDecoder.CourseAndVelocityReceived += (object sender, CourseOverGround courseAndVelocity) => {
Console.WriteLine("*********************************************");
Console.WriteLine($"{courseAndVelocity}");
Console.WriteLine("*********************************************");
};

// GSV (satellites in view)
var gsvDecoder = new GsvDecoder();
nmeaProcessor.RegisterDecoder(gsvDecoder);
gsvDecoder.SatellitesInViewReceived += (object sender, SatellitesInView satellites) => {
Console.WriteLine("*********************************************");
Console.WriteLine($"{satellites}");
Console.WriteLine("*********************************************");
};
}
}
}

NMEA Sentence Class with Automatic Parsing

If you need to manually construct or parse a NMEA sentence, you can use the NmeaSentence class.

Parsing a NMEA Sentence

You can automatically parse a NMEA string via the .From() method:

NmeaSentence sentence = NmeaSentence.From("$GPRMC,000049.799,V,,,,,0.00,0.00,060180,,,N*48");

This will create a new instance of the NmeaSentence class with the NMEA data populated and accessible via its properties. To access the data elements of the actual message, you can access the DataElements property which is a List<string> containing each string element.

Outputting a NMEA Sentence with Checksum

NMEA sentences must have a calculated checksum at the end of the string that validates the data contained within. If you call ToString() on the NmeaSentence, it'll automatically calculate the checksum for you and append it to the output.

Built-in Decoders

There are a number of built-in NMEA decoders for the most common sentences, including:

  • GgaDecoder - GPS Fix Data decoder. Comprehensive location data including latitude, longitude, altitude, quality of signal, time, and precision.
  • GllDecoder - Geographic Position - Latitude/Longitude decoder. Describes location of receiver in latitude and longitude coordinates.
  • GsaDecoder - GPS Dilution of Precision (DoP) and Active Satellites decoder. Lists the satellites used for the location fix, along with their dilution of precision information.
  • GsvDecoder - Satellites in View decoder. Describes the sky position of satellites that the GPS receiver can "see."
  • RmcDecoder - Recommended Minimum Navigation Information decoder. Includes the minimum amount of navigation information including position as well as track made good (direction of travel) and speed.
  • VtgDecoder - Track Made Good and Ground Speed decoder. Describes the course over ground (direction of travel) as well as the speed.

All of these are open source, and it's easy to add new sentence parser as well.