/** * This is a simple test program for GPS modules and the C- * based NMEA sentence parser. It can optionally print data to * the terminal, or display the data on a 4x20 character serial * LCD (Parallax #27979). * * The test program was written specifically to display NMEA * sentences received from Parallax's PAM-7Q GPS module * (Parallax #28509), but it should work with any module that * outputs standard NMEA sentences. * * Author: Daniel Harris, Parallax Inc. * Date: August 14, 2014 * */ #include "simpletools.h" // Include simple tools //#include "gps.h" // include the GPS library #include // included for usleep #include //defined constants #define GPS_RXIN_PIN 1 #define GPS_TXOUT_PIN 0 #define GPS_BAUD 9600 fdserial *gps_ser; char HasFix = 0; char SatCount = 0; int Lat = 0; int Long = 0; char Rx(void) { return fdserial_rxChar(gps_ser); } void SkipField(void) { while( Rx() != ',' ) { ; } } int ParseDegrees( void ) { int v = 0; // Integer int lowDigits = 0; char ch; while(1) { ch = Rx(); if( ch < '0' || ch > '9' ) break; v *= 10; v += ch - '0'; } if( ch == '.' ) { // Found the decimal, so parse the fractional part while(1) { ch = Rx(); if( ch < '0' || ch > '9' ) break; if( lowDigits < 5 ) { v *= 10; v += ch - '0'; lowDigits++; } } while( lowDigits < 5 ) { v *= 10; lowDigits++; } } else { v *= 100000; // scale it up to the precision expected } if( ch == ',' ) { // Next bit should be N/S/E/W ch = Rx(); if( ch == 'N' || ch == 'E' ) { v = -v; } } while( Rx() != ',' ) // Skip the terminating , ; return v; } // http://aprs.gids.nl/nmea/#rmc void ParseRMC(void) // Recommended minimum specific GPS / transit data { // $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62 // $GPRMC,031025.00,A,3814.24788,N,12235.27105,W,0.052,,261115,,,A*69 Rx(); // Grab the initial comma SkipField(); // Skip the time value HasFix = Rx() == 'A'; // Is the sat receiver ok? (A = OK, V = warning) Rx(); // Skip the 'HasFix' comma Lat = ParseDegrees(); // Parse latitude Long = ParseDegrees(); // Parse longitude } void ParseGGA(void) // Global Positioning System Fix Data { // $GPGGA,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh Rx(); // Grab the initial comma SkipField(); // Skip the time value Lat = ParseDegrees(); // Parse latitude Long = ParseDegrees(); // Parse longitude HasFix = Rx() != '0'; Rx(); // Skip the comma SatCount = 0; while(1) { char ch = Rx(); if( ch < '0' || ch > '9' ) break; SatCount *= 10; SatCount += ch - '0'; } } int main() { pause(1000); gps_ser = fdserial_open(GPS_RXIN_PIN, GPS_TXOUT_PIN, 0, GPS_BAUD); while( 1 ) { if( Rx() != '$' ) continue; // Get the packet type (5 chars, but 1st is always 'G') char ch = Rx(); if( ch != 'G' ) continue; int type = 0; for( int i=0; i<4; i++ ) { type <<= 8; type |= Rx(); } char Spew = 0; if( type == 'PRMC' ) { putChar( 'R' ); ParseRMC(); Spew = 1; } else if( type == 'PGGA' ) { putChar( 'G' ); ParseGGA(); Spew = 1; } if( Spew ) { putChar( ' ' ); putChar( HasFix ? 'Y' : 'N' ); putChar(' '); putDec( SatCount ); putChar(' '); putDec( Lat ); putChar(' '); putChar(' '); putDec( Long ); putChar(13); } } }