Git Product home page Git Product logo

nematode's Introduction

NemaTode

Cross platform C++ 11 NMEA Parser & GPS Framework

NemaTode is yet another lightweight generic NMEA parser.

It also comes with a GPS data interface to handle the most popular GPS NMEA sentences.

Confirmed on MSVC 2013 and GCC 4.8.4.

It's too easy!

This is all you need to use the GPS NMEA sentence data.

NMEAParser parser;
GPSService gps(parser);
// (optional) Called when a sentence is valid syntax
parser.onSentence += [](const NMEASentence& nmea){
    cout << "Received $" << nmea.name << endl;
};
// (optional) Called when data is read/changed
gps.onUpdate += [](GPSService& gps){
    // There are *tons* of GPSFix properties
    if( gps.fix.locked() ){
        cout << " # Position: " << gps.fix.latitude << ", " << gps.fix.longitude << endl;
    } else {
        cout << " # Searching..." << endl;
    }
};
// Send in a log file or a byte stream
try {
    parser.readLine("FILL WITH A NMEA MESSAGE");
} catch (NMEAParseError&) {
    // Syntax error, skip
}

##Features

  • NMEA Parsing of standard and custom sentences.

    • Standard:
    GPGGA, GPGSA, GPGSV, GPRMC, GPVTG
  • NMEA Generation of "standard" and custom sentences.

    • SiRF Control sentences: PSRF100, PSRF103
  • GPS Fix class to manage and organize all the GPS related data.

  • Flexible

    • Stream data directly from a hardware byte stream
    • Read log files, even if they are cluttered with other unrelated data.
    • Easily hook into the parser to handle custom sentences and get their data.
    • Simplified GPS data
  • C++ 11 features

    • Those fancy event handlers...
    • If you are on an embedded system... sorry. This might not work for you because of compiler restrictions. Make sure there is full support for lambdas and variadic templates. Tested GCC 4.8.4, confirmed.

Details

NMEA is very popular with GPS. Unfortunately the GPS data is fragmented between many different NMEA sentences. Sometimes there is even conflicting information in them!

The underlying NMEAParser can read a byte stream from a hardware device or it can read log files with flexibility in the formatting. The accepted strings are...

"$[name:alphanum],[param[i]:alphanum],...(*alphanum[2]\r)\n"

The params allow '-' and any combination of whitespace.

The handler for "MYNMEA" is called. This is where you can catch the sentence and process it.

parser.setSentenceHandler("MYNMEA",[](const NMEASentence& nmea){
    if( ! nmea.checksumOK() ){
        // bad checksum, but valid syntax
    }
    if( nmea.parameters.size() < 3 ){
        // missing data, throw something.
        // catch it at the read*() call.
    }
    int mydata = parseInt(nmea.parameters[2]);
};

There are 2 ways to operate...

  • LAX It will eat anything.
    • Useful for reading log files.
    • Call readByte(), readBuffer(), readLine()
  • STRICT It will throw errors on anything that's not explicitly NMEA.
    • Call readSentence()

Demos

"demo_simple.cpp"

  • Just reads the GPS position data.

"demo_advanced.cpp"

  • Reads all the data
  • Sentence Generation
  • Custom Sentence handling

Generation

NMEACommand mycmd;
mycmd.name = "MYCMD";
mycmd.message = "your,data,csv";
string nmea = mycmd.toString();  // Creates: $MYCMD,your,data,csv*15

There are 2 included NMEACommands that can configure a GPS.

  • PSRF103 Configures message output ID and rate, and whether or not to use checksums.

  • PSRF100 Configures the UART serial connection (if the chip has one).

Include NemaTode in your project

You can include NemaTode via CMake in our project. Your basic CMakeLists.txt file could look like:

cmake_minimum_required(VERSION 3.1)
project(MyProject)

find_package(NemaTode REQUIRED CONFIG)

add_executable(${PROJECT_NAME} mycode.cpp)

target_link_libraries(${PROJECT_NAME} NemaTode::NemaTode)

GPS Fix data available

Available data when all 5 GPS sentences are received. If some are missing then some parameters will never change from their default values. All data is checked for consistency. For example, visible satellites can never be less than the tracking satellites, etc.

GPSFix

GPSAlmanac     almanac;
GPSTimestamp 	timestamp;

char 		status;		// Status: A=active, V=void (not locked)
uint8_t 	type;		// Type: 1=none, 2=2d, 3=3d
uint8_t 	quality;	// Quality (1-6) 

double 		dilution;		// Combination of Vertical & Horizontal
double 		horizontalDilution;	// Horizontal dilution of precision, initialized to 10, best =1, worst = >20
double 		verticalDilution;	// Vertical is less accurate

double 		altitude;		// meters
double 		latitude;		// degrees N
double 		longitude;		// degrees E
double 		speed;			// km/h
double 		travelAngle;		// degrees true north (0-359)
int32_t 	trackingSatellites;
int32_t 	visibleSatellites;

bool 		locked();		// Whether or not the position is locked on, or accurate.
double 		horizontalAccuracy();	// Gets accuracy of position in meters
double 		verticalAccuracy();
bool 		hasEstimate();		// If no fix is available, this says the position data is close to a real fix.
	
std::chrono::seconds timeSinceLastUpdate();	// Returns time from last timestamp to right now, in seconds.

GPSSatellite

double 		snr;		// Signal-to-noise ratio. 0-99 dB
uint32_t 	prn;		// pseudo-random number.  (basically a satellite id)
double 		elevation;	// 0-90 deg
double 		azimuth;	// 0-359 deg

GPSAlmanac

std::vector<GPSSatellite> satellites;	// mapped by prn (id number)
double 		averageSNR(); 
double 		minSNR();
double 		maxSNR();
double 		percentComplete();	// if all the satellite information is loaded (0-100)

GPSTimestamp (UTC Time)

int32_t 	hour;		// Parsed values from GPS
int32_t 	min;		
double 		sec;		
int32_t 	month;		
int32_t 	day;		
int32_t 	year;		
double 		rawTime;	// Values collected directly from the GPS
int32_t 	rawDate;	
time_t 		getTime();	// Converts timestamp into Epoch time, seconds since 1/1/1970.

NemaTode?

NMEA -> ME -> EM -> NEMA

+Tode

nematode's People

Contributors

ckgt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nematode's Issues

GPSTimestamp getTime() is Off by One Month

The month of year field in $GPRMC sentences is indexed 1-12. This is also how it it is stored in the month class member of GPSTimestamp. In getTime(), however mktime() is called, which expects months be 0-11.

This results in the timestamp returned by getTime being off by one month.

Throws Error When Checksum is 0

First off, thank you for this great tool, it works really well.

The only problem I have occurs when I use a gps that sends checksums. Sometimes I receive a valid NMEA checksum of 0, and the parser treats that as an invalid checksum and throws an error. An example sentence from my GPS:
$GPRMC,173138.000,V,3145.5214,N,09704.5057,W,000.0,000.0,170318,000.0,E,N*00

I get the error:
GPS Data Bad Format [$GPRMC] :: Checksum is invalid

Warnings on member initialisation order in NMEAParser and NMEASentence

NMEASentence and NMEAParser constructors cause warnings on member variable initialisation order; I suggest changing from:

NMEASentence::NMEASentence() 
: isvalid(false)
, checksumIsCalculated(false)
, calculatedChecksum(0)
, parsedChecksum(0)
{ }

to

NMEASentence::NMEASentence() 
: isvalid(false)
, checksumIsCalculated(false)
, parsedChecksum(0)
, calculatedChecksum(0)
{ }

and from

NMEAParser::NMEAParser() 
: log(false)
, maxbuffersize(NMEA_PARSER_MAX_BUFFER_SIZE)
, fillingbuffer(false)
{ }

to

NMEAParser::NMEAParser()
: fillingbuffer(false)
, maxbuffersize(NMEA_PARSER_MAX_BUFFER_SIZE)
, log(false)
{ }

or use non-static member initialisation where they're declared.

Plus sign in NMEA sentences not supported.

I am using a modem Cypress CTM-200 and processing the GPS coordinates with Nematode.

I am getting the following sentences from the modem. Unfortunately a plus sign is included before the altitude field in the GPGGA sentence. Plus sign is not supported and the sentence cannot be processed.

$PMID,353968095226388,35396809522638810
$GPGGA,194045.00,4531.6094,N,07331.1947,W,1,11,01.1,+00053,M,,M,,0000
6B
$GPRMC,194045.00,A,4531.6094,N,07331.1947,W,000.2,000.0,160519,,*21

GN*** sentences not recognized

Hello,

Even though this is not really a big issue, I would like to point out that the code is not suitable for GN*** or GL*** sentences.

I tried to adapt it, and make it work for all prefixes of NMEA sentences but I did not succeed.

Has anyone made an attempt at this before ?

Thank you.

Non-GPS Messages

According to https://anavs.com/knowledgebase/nmea-format/ there are additional message formats:

  • GP for GPS only solutions
  • GL for GLONASS only solutions
  • GA for GALILEO only solutions
  • GN for multi GNSS solutions

The GPS messages are supported, while the others are not, limiting the usability of the library.

I'll do a fork and add the other formats (as long as I have test data for them) as described in #4 .

And do a pull request later.

member variable checksum should be unsigned char in NMEACommand

otherwise NMEACommand::addChecksum() will add wrong checksum string if checksum>=0x80

#include <string>
#include <iostream>
#include <iomanip>
#include <sstream>

int main()
{
    char checksum = 0x80;
    unsigned char uchecksum = 0x80;
    std::stringstream ss1, ss2;
    ss1  << std::hex << std::uppercase << std::internal << std::setfill('0') << std::setw(2) << (int)checksum;
    ss2  << std::hex << std::uppercase << std::internal << std::setfill('0') << std::setw(2) << (int)uchecksum;
    std::cout<< ss1.str() << ", "<< ss2.str()<<std::endl;
}

result in

FFFFFF80, 80

Licensing

Hey, would you mind putting the actual text of the zlib license in your License file, along with your copyright? I'd like to use the library but don't want to violate zlib by not properly attributing you.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.