Added non-final versions of iris and tower firmware.

This commit is contained in:
2018-02-20 15:45:21 -08:00
parent 31a07e82f8
commit 6bb3539488
171 changed files with 36168 additions and 13 deletions

View File

@@ -0,0 +1,168 @@
#include <NMEAGPS.h>
//======================================================================
// Program: NMEA.ino
//
// Description: This program uses the fix-oriented methods available() and
// read() to handle complete fix structures.
//
// When the last character of the LAST_SENTENCE_IN_INTERVAL (see NMEAGPS_cfg.h)
// is decoded, a completed fix structure becomes available and is returned
// from read(). The new fix is saved the 'fix' structure, and can be used
// anywhere, at any time.
//
// If no messages are enabled in NMEAGPS_cfg.h, or
// no 'gps_fix' members are enabled in GPSfix_cfg.h, no information will be
// parsed, copied or printed.
//
// Prerequisites:
// 1) Your GPS device has been correctly powered.
// Be careful when connecting 3.3V devices.
// 2) Your GPS device is correctly connected to an Arduino serial port.
// See GPSport.h for the default connections.
// 3) You know the default baud rate of your GPS device.
// If 9600 does not work, use NMEAdiagnostic.ino to
// scan for the correct baud rate.
// 4) LAST_SENTENCE_IN_INTERVAL is defined to be the sentence that is
// sent *last* in each update interval (usually once per second).
// The default is NMEAGPS::NMEA_RMC (see NMEAGPS_cfg.h). Other
// programs may need to use the sentence identified by NMEAorder.ino.
// 5) NMEAGPS_RECOGNIZE_ALL is defined in NMEAGPS_cfg.h
//
// 'Serial' is for debug output to the Serial Monitor window.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
//-------------------------------------------------------------------------
// The GPSport.h include file tries to choose a default serial port
// for the GPS device. If you know which serial port you want to use,
// edit the GPSport.h file.
#include <GPSport.h>
//------------------------------------------------------------
// For the NeoGPS example programs, "Streamers" is common set
// of printing and formatting routines for GPS data, in a
// Comma-Separated Values text format (aka CSV). The CSV
// data will be printed to the "debug output device".
// If you don't need these formatters, simply delete this section.
#include <Streamers.h>
//------------------------------------------------------------
// This object parses received characters
// into the gps.fix() data structure
static NMEAGPS gps;
//------------------------------------------------------------
// Define a set of GPS fix information. It will
// hold on to the various pieces as they are received from
// an RMC sentence. It can be used anywhere in your sketch.
static gps_fix fix;
//----------------------------------------------------------------
// This function gets called about once per second, during the GPS
// quiet time. It's the best place to do anything that might take
// a while: print a bunch of things, write to SD, send an SMS, etc.
//
// By doing the "hard" work during the quiet time, the CPU can get back to
// reading the GPS chars as they come in, so that no chars are lost.
static void doSomeWork()
{
// Print all the things!
trace_all( DEBUG_PORT, gps, fix );
} // doSomeWork
//------------------------------------
// This is the main GPS parsing loop.
static void GPSloop()
{
while (gps.available( gpsPort )) {
fix = gps.read();
doSomeWork();
}
} // GPSloop
//--------------------------
void setup()
{
DEBUG_PORT.begin(9600);
while (!DEBUG_PORT)
;
DEBUG_PORT.print( F("NMEA.INO: started\n") );
DEBUG_PORT.print( F(" fix object size = ") );
DEBUG_PORT.println( sizeof(gps.fix()) );
DEBUG_PORT.print( F(" gps object size = ") );
DEBUG_PORT.println( sizeof(gps) );
DEBUG_PORT.println( F("Looking for GPS device on " GPS_PORT_NAME) );
#ifndef NMEAGPS_RECOGNIZE_ALL
#error You must define NMEAGPS_RECOGNIZE_ALL in NMEAGPS_cfg.h!
#endif
#ifdef NMEAGPS_INTERRUPT_PROCESSING
#error You must *NOT* define NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h!
#endif
#if !defined( NMEAGPS_PARSE_GGA ) & !defined( NMEAGPS_PARSE_GLL ) & \
!defined( NMEAGPS_PARSE_GSA ) & !defined( NMEAGPS_PARSE_GSV ) & \
!defined( NMEAGPS_PARSE_RMC ) & !defined( NMEAGPS_PARSE_VTG ) & \
!defined( NMEAGPS_PARSE_ZDA ) & !defined( NMEAGPS_PARSE_GST )
DEBUG_PORT.println( F("\nWARNING: No NMEA sentences are enabled: no fix data will be displayed.") );
#else
if (gps.merging == NMEAGPS::NO_MERGING) {
DEBUG_PORT.print ( F("\nWARNING: displaying data from ") );
DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) );
DEBUG_PORT.print ( F(" sentences ONLY, and only if ") );
DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) );
DEBUG_PORT.println( F(" is enabled.\n"
" Other sentences may be parsed, but their data will not be displayed.") );
}
#endif
DEBUG_PORT.print ( F("\nGPS quiet time is assumed to begin after a ") );
DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) );
DEBUG_PORT.println( F(" sentence is received.\n"
" You should confirm this with NMEAorder.ino\n") );
trace_header( DEBUG_PORT );
DEBUG_PORT.flush();
gpsPort.begin( 9600 );
}
//--------------------------
void loop()
{
GPSloop();
}

View File

@@ -0,0 +1,107 @@
#include <NMEAGPS.h>
NMEAGPS gps; // This parses the GPS characters
gps_fix fix; // This holds on to the latest values
//======================================================================
// Program: NMEAGSV.ino
//
// Description: Display satellites in view, as reported by the GSV sentences.
//
// Prerequisites:
// 1) NMEA.ino works with your device (correct TX/RX pins and baud rate)
// 2) NMEAGPS_PARSE_SATELLITES and NMEAGPS_PARSE_SATELLITE_INFO are
// enabled in NMEAGPS_cfg.h
// 3) The GSV sentence has been enabled in NMEAGPS_cfg.h.
// 4) Your device emits the GSV sentence (use NMEAorder.ino to confirm).
// 5) LAST_SENTENCE_IN_INTERVAL has been set to GSV (or any other enabled sentence)
// in NMEAGPS_cfg.h (use NMEAorder.ino).
//
// 'Serial' is for debug output to the Serial Monitor window.
//
// License:
// Copyright (C) 2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <GPSport.h>
//-----------------
// Check configuration
#ifndef NMEAGPS_PARSE_GSV
#error You must define NMEAGPS_PARSE_GSV in NMEAGPS_cfg.h!
#endif
#ifndef NMEAGPS_PARSE_SATELLITES
#error You must define NMEAGPS_PARSE_SATELLITE in NMEAGPS_cfg.h!
#endif
#ifndef NMEAGPS_PARSE_SATELLITE_INFO
#error You must define NMEAGPS_PARSE_SATELLITE_INFO in NMEAGPS_cfg.h!
#endif
//-----------------
void setup()
{
DEBUG_PORT.begin(9600);
while (!Serial)
;
DEBUG_PORT.print( F("NeoGPS GSV example started\n") );
gpsPort.begin(9600);
} // setup
//-----------------
void loop()
{
while (gps.available( gpsPort )) {
fix = gps.read();
displaySatellitesInView();
}
} // loop
//-----------------
void displaySatellitesInView()
{
DEBUG_PORT.print( gps.sat_count );
DEBUG_PORT.print( ',' );
for (uint8_t i=0; i < gps.sat_count; i++) {
DEBUG_PORT.print( gps.satellites[i].id );
DEBUG_PORT.print( ' ' );
DEBUG_PORT.print( gps.satellites[i].elevation );
DEBUG_PORT.print( '/' );
DEBUG_PORT.print( gps.satellites[i].azimuth );
DEBUG_PORT.print( '@' );
if (gps.satellites[i].tracked)
DEBUG_PORT.print( gps.satellites[i].snr );
else
DEBUG_PORT.print( '-' );
DEBUG_PORT.print( F(", ") );
}
DEBUG_PORT.println();
} // displaySatellitesInView

View File

@@ -0,0 +1,433 @@
#include <Arduino.h>
#include <NMEAGPS.h>
//======================================================================
// Program: NMEASDlog.ino
//
// Description: This program is an interrupt-driven GPS logger.
// It uses the alternative serial port libraries NeoHWSerial,
// NeoSWSerial, or NeoICSerial.
//
// Prerequisites:
// 1) You have completed the requirements for NMEA_isr.ino
// 2) You have connected an SPI SD card and verified it is working
// with other SD utilities.
// 3) For logging faster than the default 1Hz rate, you have
// identified the required commands for your GPS device.
//
// 'Serial' is for debug output to the Serial Monitor window.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <GPSport.h>
//#include <Streamers.h>
//----------------------------------------------------------------
// Check configuration
#if !defined( GPS_FIX_TIME ) || !defined( GPS_FIX_LOCATION )
#error You must define TIME and LOCATION in GPSfix_cfg.h
#endif
#if !defined( NMEAGPS_PARSE_RMC )
#error You must define NMEAGPS_PARSE_RMC in NMEAGPS_cfg.h!
#endif
#ifndef NMEAGPS_INTERRUPT_PROCESSING
#error You must define NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h!
#endif
static const int LED = 13;
static NMEAGPS gps;
//----------------------------------------------------------------
// SD card includes and declarations
#include <SPI.h>
#include <SdFat.h>
SdFat SD;
const int chipSelect = 8;
//----------------------------------------------------------------
// For testing, it may be more convenient to simply print the
// GPS fix fields to the Serial Monitor. Simply uncomment
// this define to skip all SD operations. An SD card module
// does not have to be connected.
#define SIMULATE_SD
#ifdef SIMULATE_SD
auto &logfile = DEBUG_PORT;
#else
File logfile;
#endif
//----------------------------------------------------------------
// Utility to print a long integer like it's a float
// with 9 significant digits.
void printL( Print & outs, int32_t degE7 )
{
// Extract and print negative sign
if (degE7 < 0) {
degE7 = -degE7;
outs.print( '-' );
}
// Whole degrees
int32_t deg = degE7 / 10000000L;
outs.print( deg );
outs.print( '.' );
// Get fractional degrees
degE7 -= deg*10000000L;
// Print leading zeroes, if needed
if (degE7 < 10L)
outs.print( F("000000") );
else if (degE7 < 100L)
outs.print( F("00000") );
else if (degE7 < 1000L)
outs.print( F("0000") );
else if (degE7 < 10000L)
outs.print( F("000") );
else if (degE7 < 100000L)
outs.print( F("00") );
else if (degE7 < 1000000L)
outs.print( F("0") );
// Print fractional degrees
outs.print( degE7 );
}
//----------------------------------------------------------------
// Because the SD write can take a long time, GPSisr will store
// parsed data in the NMEAGPS 'buffer' array until GPSloop can get to it.
//
// The number of elements you should have in the array depends on
// two things: the speed of your SD card, and the update rate you
// have chosen.
//
// For an update rate of 10Hz (100ms period), two fixes are probably
// enough. Most cards take ~100ms to complete a write of 512 bytes.
// With FIX_MAX=2, two complete fixes can be stored, which were
// received in 200ms. A third fix can be started, giving a little
// more time before an overrun occurs, a total of about 250ms.
//
// If your card is slower or your update rate is faster, you should
// first build and run this program to determine the speed of your
// card. The time it takes to log one record is printed to the log
// file.
//
// After the program has run for a minute or two, remove the
// card and examine the loggingTimes. You may see that an interval
// was skipped, and you will also see an OVERRUN message on the
// DEBUG_PORT (usually Serial).
//
// You should calculate a new FIX_MAX from the maximum loggingTime
// you see in the log file:
//
// FIX_MAX = (max loggingTime)/(update period) + 1;
//
// For example, if the max loggingTime is 160ms, and the update period is
// 100ms (10Hz), then FIX_MAX = 160/100 + 1 = 2.
//
// Change the FIX_MAX value, build and run the program again. The
// SD log file should now contain all records, and no OVERRUN
// messages should have been printed on the DEBUG_PORT.
//
// If you do see an OVERRUN message, examine the loggingTime to see
// if it exceeded the maximum value from the previous build, and
// increase FIX_MAX.
//
// If you are also printing data to a Serial device, you could be
// printing too much information. In general, you must print less than
// (baudrate/10) characters per second. For example, if your baudrate
// is 9600, you must print less than 960 characters per second. And if
// the update rate is 10Hz, you must print no more than 96 characters
// per update.
//
// There are also restrictions on how much you should print to Serial in one
// section of code. If you print more than 64 characters (the output buffer
// size), then some prints will block until all characters can be stored in the
// output buffer.
//
// For example, if you try to print 80 characters, the first 64 characters
// will be immediately stored in the output buffer. However, the last 16
// characters must wait until the output buffer has room for 16 more
// characters. That takes 16 * (10/baudrate) milliseconds. At 9600 baud
// that will take 17ms. The loggingTimes will show no less than 17ms per
// record, and will occasionally include the longer SD write time of ~100ms.
//----------------------------------------------------------------
static void GPSloop()
{
if (gps.available()) {
gps_fix fix = gps.read();
// Log the fix information if we have a location and time
if (fix.valid.location && fix.valid.time) {
static uint16_t lastLoggingTime = 0;
uint16_t startLoggingTime = millis();
// If you like the CSV format implemented in Streamers.h,
// you could replace all these prints with
// trace_all( logFile, fix ); // uncomment include Streamers.h
printL( logfile, fix.latitudeL() );
logfile.print( ',' );
printL( logfile, fix.longitudeL() );
logfile.print(',');
if (fix.dateTime.hours < 10)
logfile.print( '0' );
logfile.print(fix.dateTime.hours);
logfile.print( ':' );
if (fix.dateTime.minutes < 10)
logfile.print( '0' );
logfile.print(fix.dateTime.minutes);
logfile.print( ':' );
if (fix.dateTime.seconds < 10)
logfile.print( '0' );
logfile.print(fix.dateTime.seconds);
logfile.print( '.' );
if (fix.dateTime_cs < 10)
logfile.print( '0' ); // leading zero for .05, for example
logfile.print(fix.dateTime_cs);
logfile.print(',');
logfile.print( lastLoggingTime ); // write how long the previous logging took
logfile.println();
// flush() is used to empty the contents of the SD buffer to the SD.
// If you don't call flush, the data will fill up the SdFat buffer
// of 512bytes and flush itself automatically.
//
// To avoid losing data or corrupting the SD card file system, you must
// call flush() at least once (or close()) before powering down or pulling
// the SD card.
//
// It is *strongly* recommended that you use some external event
// to close the file. For example, staying within 50m of the moving
// average location for 1 minute, or using a switch to start and stop
// logging. It would also be good to provide a visual indication
// that it is safe to power down and/or remove the card, perhaps via
// the LED.
//
// To reduce the amount of data that may be lost by an abnormal shut down,
// you can call flush() periodically.
//
// Depending on the amount of data you are printing, you can save
// *a lot* of CPU time by not flushing too frequently. BTW, flushing
// every time at 5Hz is too frequent.
// This shows how to flush once a second.
static uint16_t lastFlushTime = 0;
if (startLoggingTime - lastFlushTime > 1000) {
lastFlushTime = startLoggingTime; // close enough
logfile.flush();
}
#ifdef SIMULATE_SD
// Simulate the delay of writing to an SD card. These times are
// very long. This is intended to show (and test) the overrun detection.
//
// On a 1Hz GPS, delaying more than 2 seconds here, or more than
// 2 seconds in two consecutive updates, will cause OVERRUN.
//
// Feel free to try different delays to simulate the actual behavior
// of your SD card.
uint16_t t = random(0,5); // 0..4
t += 3; // 3..7
t = t*t*t*t; // 81..2401ms
delay( t ); // cause an OVERRUN
#endif
// All logging is finished, figure out how long that took.
// This will be written in the *next* record.
lastLoggingTime = (uint16_t) millis() - startLoggingTime;
}
}
} // GPSloop
//----------------------------------------------------------------
void GPSisr( uint8_t c )
{
gps.handle( c );
} // GPSisr
//----------------------------------------------------------------
// This routine waits for GPSisr to provide
// a fix that has a valid location.
//
// The LED is slowly flashed while it's waiting.
static void waitForFix()
{
DEBUG_PORT.print( F("Waiting for GPS fix...") );
uint16_t lastToggle = millis();
for (;;) {
if (gps.available()) {
if (gps.read().valid.location)
break; // Got it!
}
// Slowly flash the LED until we get a fix
if ((uint16_t) millis() - lastToggle > 500) {
lastToggle += 500;
digitalWrite( LED, !digitalRead(LED) );
DEBUG_PORT.write( '.' );
}
}
DEBUG_PORT.println();
digitalWrite( LED, LOW );
gps.overrun( false ); // we had to wait a while...
} // waitForFix
//----------------------------------------------------------------
void setup()
{
DEBUG_PORT.begin(9600);
while (!DEBUG_PORT)
; // wait for serial port to connect.
DEBUG_PORT.println( F("NMEASDlog.ino started!") );
DEBUG_PORT.print( F("fix size = ") );
DEBUG_PORT.println( sizeof(gps_fix) );
DEBUG_PORT.print( NMEAGPS_FIX_MAX );
DEBUG_PORT.println( F(" GPS updates can be buffered.") );
if (gps.merging != NMEAGPS::EXPLICIT_MERGING)
DEBUG_PORT.println( F("Warning: EXPLICIT_MERGING should be enabled for best results!") );
gpsPort.attachInterrupt( GPSisr );
gpsPort.begin( 9600 );
// Configure the GPS. These are commands for MTK GPS devices. Other
// brands will have different commands.
gps.send_P( &gpsPort, F("PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0") ); // RMC only for MTK GPS devices
gps.send_P( &gpsPort, F("PMTK220,100") ); // 10Hz update rate for MTK GPS devices
// Enable the LED for blinking feedback
pinMode( LED, OUTPUT );
initSD();
waitForFix();
} // setup
//----------------------------------------------------------------
void loop()
{
GPSloop();
if (gps.overrun()) {
gps.overrun( false );
DEBUG_PORT.println( F("DATA OVERRUN: fix data lost!") );
}
}
//----------------------------------------------------------------
void initSD()
{
#ifdef SIMULATE_SD
DEBUG_PORT.println( F(" Simulating SD.") );
#else
DEBUG_PORT.println( F("Initializing SD card...") );
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
DEBUG_PORT.println( F(" SD card failed, or not present") );
// don't do anything more:
// Flicker the LED
while (true) {
digitalWrite(LED,HIGH);
delay(75);
digitalWrite(LED,LOW);
delay(75);
}
}
DEBUG_PORT.println( F(" SD card initialized.") );
// Pick a numbered filename, 00 to 99.
char filename[15] = "data_##.txt";
for (uint8_t i=0; i<100; i++) {
filename[5] = '0' + i/10;
filename[6] = '0' + i%10;
if (!SD.exists(filename)) {
// Use this one!
break;
}
}
logfile = SD.open(filename, FILE_WRITE);
if (!logfile) {
DEBUG_PORT.print( F("Couldn't create ") );
DEBUG_PORT.println(filename);
// If the file can't be created for some reason this leaves the LED on
// so I know there is a problem
digitalWrite(LED,HIGH);
while (true) {}
}
DEBUG_PORT.print( F("Writing to ") );
DEBUG_PORT.println(filename);
// GPS Visualizer requires a header to identify the CSV fields.
// If you are saving other data or don't need this, simply remove/change it
logfile.println( F("latitude,longitude,time,loggingTime") );
//trace_header( logfile ); // and uncomment #include Streamers.h
#endif
} // initSD

View File

@@ -0,0 +1,90 @@
#include <NMEAGPS.h>
//======================================================================
// Program: NMEA_isr.ino
//
// Prerequisites:
// 1) NMEA.ino works with your device
//
// Description: This minimal program parses the GPS data during the
// RX character interrupt. The ISR passes the character to
// the GPS object for parsing. The GPS object will add gps_fix
// structures to a buffer that can be later read() by loop().
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <GPSport.h>
#include <Streamers.h>
// Check configuration
#ifndef NMEAGPS_INTERRUPT_PROCESSING
#error You must define NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h!
#endif
static NMEAGPS gps;
//--------------------------
static void GPSisr( uint8_t c )
{
gps.handle( c );
} // GPSisr
//--------------------------
void setup()
{
DEBUG_PORT.begin(9600);
while (!DEBUG_PORT)
;
DEBUG_PORT.print( F("NMEA_isr.INO: started\n") );
DEBUG_PORT.print( F("fix object size = ") );
DEBUG_PORT.println( sizeof(gps.fix()) );
DEBUG_PORT.print( F("NMEAGPS object size = ") );
DEBUG_PORT.println( sizeof(gps) );
DEBUG_PORT.println( F("Looking for GPS device on " GPS_PORT_NAME) );
trace_header( DEBUG_PORT );
DEBUG_PORT.flush();
gpsPort.attachInterrupt( GPSisr );
gpsPort.begin( 9600 );
}
//--------------------------
void loop()
{
if (gps.available()) {
// Print all the things!
trace_all( DEBUG_PORT, gps, gps.read() );
}
if (gps.overrun()) {
gps.overrun( false );
DEBUG_PORT.println( F("DATA OVERRUN: took too long to print GPS data!") );
}
}

View File

@@ -0,0 +1,265 @@
#include <NMEAGPS.h>
//======================================================================
// Program: NMEAaverage.ino
//
// Description: This program averages locations over time to compute
// a higher-accuracy *static* location. It also shows
// how to use the distance functions in the Location class.
//
// Prerequisites:
// 1) NMEA.ino works with your device (correct TX/RX pins and baud rate)
// 2) At least once sentence with a location field has been enabled
//
// 'Serial' is for debug output to the Serial Monitor window.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <GPSport.h>
//------------------------------------------------------------
// Check that the config files are set up properly
#if !defined( NMEAGPS_PARSE_GGA ) && \
!defined( NMEAGPS_PARSE_GLL ) && \
!defined( NMEAGPS_PARSE_RMC )
#error You must uncomment at least one of NMEAGPS_PARSE_GGA, GGL or RMC in NMEAGPS_cfg.h!
#endif
#if !defined( GPS_FIX_LOCATION )
#error You must uncomment GPS_FIX_LOCATION in GPSfix_cfg.h!
#endif
#if !defined( GPS_FIX_TIME )
#error You must uncomment GPS_FIX_TIME in GPSfix_cfg.h!
#endif
#if !defined( GPS_FIX_DATE )
#error You must uncomment GPS_FIX_DATE in GPSfix_cfg.h!
#endif
//------------------------------------------------------------
static NMEAGPS gps; // This parses the GPS characters
static gps_fix fix; // This holds the latest GPS fix
//------------------------------------------------------------
using namespace NeoGPS;
static gps_fix first; // good GPS data
static clock_t firstSecs; // cached dateTime in seconds since EPOCH
static Location_t avgLoc; // gradually-calculated average location
static uint16_t count; // number of samples
static int32_t sumDLat, sumDLon; // accumulated deltas
static bool doneAccumulating; // accumulation completed
//------------------------------------------------------------
const char nCD [] PROGMEM = "N";
const char nneCD[] PROGMEM = "NNE";
const char neCD [] PROGMEM = "NE";
const char eneCD[] PROGMEM = "ENE";
const char eCD [] PROGMEM = "E";
const char eseCD[] PROGMEM = "ESE";
const char seCD [] PROGMEM = "SE";
const char sseCD[] PROGMEM = "SSE";
const char sCD [] PROGMEM = "S";
const char sswCD[] PROGMEM = "SSW";
const char swCD [] PROGMEM = "SW";
const char wswCD[] PROGMEM = "WSW";
const char wCD [] PROGMEM = "W";
const char wnwCD[] PROGMEM = "WNW";
const char nwCD [] PROGMEM = "NW";
const char nnwCD[] PROGMEM = "NNW";
const char * const dirStrings[] PROGMEM =
{ nCD, nneCD, neCD, eneCD, eCD, eseCD, seCD, sseCD,
sCD, sswCD, swCD, wswCD, wCD, wnwCD, nwCD, nnwCD };
const __FlashStringHelper *compassDir( uint16_t bearing ) // degrees CW from N
{
const int16_t directions = sizeof(dirStrings)/sizeof(dirStrings[0]);
const int16_t degreesPerDir = 360 / directions;
int8_t dir = (bearing + degreesPerDir/2) / degreesPerDir;
while (dir < 0)
dir += directions;
while (dir >= directions)
dir -= directions;
return (const __FlashStringHelper *) pgm_read_ptr( &dirStrings[ dir ] );
} // compassDir
//------------------------------------------------------------
static void doSomeWork()
{
static bool warned = false; // that we're waiting for a valid location
if (fix.valid.location && fix.valid.date && fix.valid.time) {
if (count == 0) {
// Just save the first good fix
first = fix;
firstSecs = (clock_t) first.dateTime;
count = 1;
} else {
// After the first fix, accumulate locations until we have
// a good average. Then display the offset from the average.
if (warned) {
// We were waiting for the fix to be re-acquired.
warned = false;
DEBUG_PORT.println();
}
DEBUG_PORT.print( count );
if (!doneAccumulating) {
// Enough time?
if (((clock_t)fix.dateTime - firstSecs) > 2 * SECONDS_PER_HOUR)
doneAccumulating = true;
}
int32_t dLat, dLon;
if (!doneAccumulating) {
// Use deltas from the first location
dLat = fix.location.lat() - first.location.lat();
sumDLat += dLat;
int32_t avgDLat = sumDLat / count;
dLon = fix.location.lon() - first.location.lon();
sumDLon += dLon;
int32_t avgDLon = sumDLon / count;
// Then calculated the average location as the first location
// plus the averaged deltas.
avgLoc.lat( first.location.lat() + avgDLat );
avgLoc.lon( first.location.lon() + avgDLon );
count++;
}
DEBUG_PORT.print( ',' );
DEBUG_PORT.print( avgLoc.lat() );
DEBUG_PORT.print( ',' );
DEBUG_PORT.print( avgLoc.lon() );
DEBUG_PORT.print( ',' );
dLat = avgLoc.lat() - fix.location.lat();
DEBUG_PORT.print( dLat );
DEBUG_PORT.print( ',' );
dLon = avgLoc.lon() - fix.location.lon();
DEBUG_PORT.print( dLon );
// Calculate the distance from the current fix to the average location
float avgDistError = avgLoc.DistanceKm( fix.location );
DEBUG_PORT.print( ',' );
DEBUG_PORT.print( avgDistError * 100000.0 ); // cm
// Calculate the bearing from the current fix to the average location.
// NOTE: other libraries will have trouble with this calculation,
// because these coordinates are *VERY* close together. Naive
// floating-point calculations will not have enough significant
// digits.
float avgBearingErr = fix.location.BearingTo( avgLoc );
float bearing = avgBearingErr * Location_t::DEG_PER_RAD;
DEBUG_PORT.print( ',' );
DEBUG_PORT.print( bearing, 6 );
DEBUG_PORT.print( ',' );
DEBUG_PORT.print( compassDir( bearing ) );
// Calculate a point that is 10km away from the average location,
// at the error bearing
Location_t tenKmAway( avgLoc );
tenKmAway.OffsetBy( 10.0 / Location_t::EARTH_RADIUS_KM, avgBearingErr );
DEBUG_PORT.print( ',' );
DEBUG_PORT.print( tenKmAway.lat() );
DEBUG_PORT.print( ',' );
DEBUG_PORT.print( tenKmAway.lon() );
// Calculate the bearing from the average location to that point.
// This should be very close to the avgBearingErr, and will
// reflect the calculation error. This is because the
// current fix is *VERY* close to the average location.
float tb = avgLoc.BearingToDegrees( tenKmAway );
DEBUG_PORT.print( ',' );
DEBUG_PORT.print( tb, 6 );
DEBUG_PORT.println();
}
} else {
if (!warned) {
warned = true;
DEBUG_PORT.print( F("Waiting for fix...") );
} else {
DEBUG_PORT.print( '.' );
}
}
} // doSomeWork
//------------------------------------------------------------
static void GPSloop()
{
while (gps.available( gpsPort )) {
fix = gps.read();
doSomeWork();
}
} // GPSloop
//------------------------------------------------------------
void setup()
{
DEBUG_PORT.begin(9600);
while (!DEBUG_PORT)
;
DEBUG_PORT.print( F("NMEAaverage.INO: started\n") );
DEBUG_PORT.print( F(" fix object size = ") );
DEBUG_PORT.println( sizeof(gps.fix()) );
DEBUG_PORT.print( F(" gps object size = ") );
DEBUG_PORT.println( sizeof(gps) );
DEBUG_PORT.println( F("Looking for GPS device on " GPS_PORT_NAME) );
DEBUG_PORT.println( F("Comparing current fix with averaged location.\n"
"count,avg lat,avg lon,dlat,dlon,distance(cm),"
"bearing deg,compass,lat/lon 10km away & recalc bearing") );
DEBUG_PORT.flush();
gpsPort.begin( 9600 );
}
//------------------------------------------------------------
void loop()
{
GPSloop();
}

View File

@@ -0,0 +1,105 @@
#include <NMEAGPS.h>
//======================================================================
// Program: NMEAbenchmark.ino
//
// Prerequisites:
//
// Description: Use GPGGA and GPRMC sentences to test
// the parser's performance.
//
// GSV sentences are tested if enabled.
//
// 'Serial' is for debug output to the Serial Monitor window.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <Streamers.h>
static NMEAGPS gps;
//--------------------------
static uint32_t time_it( const char *data )
{
const uint16_t ITERATIONS = 1024;
uint32_t start, end;
Serial.flush();
start = micros();
for (uint16_t i=ITERATIONS; i > 0; i--) {
char *ptr = (char *) data;
while (*ptr)
gps.decode( *ptr++ );
}
end = micros();
return (end-start)/ITERATIONS;
}
//--------------------------
void setup()
{
Serial.begin(9600);
Serial.println( F("NMEAbenchmark: started") );
Serial.print( F("fix object size = ") );
Serial.println( sizeof(gps.fix()) );
Serial.print( F(" gps object size = ") );
Serial.println( sizeof(gps) );
trace_header( Serial );
Serial.flush();
const char *gga =
"$GPGGA,092725.00,4717.11399,N,00833.91590,E,"
"1,8,1.01,499.6,M,48.0,M,,0*5B\r\n";
const char *gga_no_lat =
"$GPGGA,092725.00,,,00833.91590,E,"
"1,8,1.01,499.6,M,48.0,M,,0*0D\r\n";
Serial << F("GGA time = ") << time_it( gga ) << '\n';
trace_all( Serial, gps, gps.fix() );
Serial << F("GGA no lat time = ") << time_it( gga_no_lat ) << '\n';
trace_all( Serial, gps, gps.fix() );
const char *rmc =
"$GPRMC,083559.00,A,4717.11437,N,00833.91522,E,"
"0.004,77.52,091202,,,A*57\r\n";
Serial << F("RMC time = ") << time_it( rmc ) << '\n';
trace_all( Serial, gps, gps.fix() );
#ifdef NMEAGPS_PARSE_GSV
const char *gsv =
"$GPGSV,3,1,10,23,38,230,44,29,71,156,47,07,29,116,41,08,09,081,36*7F\r\n"
"$GPGSV,3,2,10,10,07,189,,05,05,220,,09,34,274,42,18,25,309,44*72\r\n"
"$GPGSV,3,3,10,26,82,187,47,28,43,056,46*77\r\n";
Serial << F("GSV time = ") << time_it( gsv ) << '\n';
trace_all( Serial, gps, gps.fix() );
#endif
}
//--------------------------
void loop() {}

View File

@@ -0,0 +1,69 @@
#include <NMEAGPS.h>
//======================================================================
// Program: NMEAblink.ino
//
// Prerequisites:
// 1) NMEA.ino works with your device
//
// Description: This program will toggle the LED once per second,
// when the LAST_SENTENCE_IN_INTERVAL is received.
//
// Because no actual GPS data is used, you could disable all
// messages (except the LAST_SENTENCE) and all gps_fix members.
// It would still receive a 'fix' oncer per second, without
// without using any RAM or CPU time to parse or save
// the (unused) values. Essentially, this app uses the LAST_SENTENCE
// as a 1PPS signal.
//
// Note: Because this example does not use 'Serial', you
// could use 'Serial' for the gpsPort, like this:
//
// #define gpsPort Serial
//
// See GPSport.h for more information.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <GPSport.h>
static NMEAGPS gps;
static const int led = 13;
//--------------------------
void setup()
{
gpsPort.begin(9600);
pinMode(led, OUTPUT);
}
//--------------------------
void loop()
{
if (gps.available( gpsPort)) {
gps.read(); // don't really do anything with the fix...
digitalWrite( led, !digitalRead(led) ); // toggle the LED
}
}

View File

@@ -0,0 +1,367 @@
#include <NMEAGPS.h>
//======================================================================
// Program: NMEAdiagnostic.ino
//
// Description: This program tries different baud rates until
// valid NMEA sentences are detected. Some GPS devices may
// have a binary mode that does not emit NMEA sentences. You
// may have to send a special command or use a utility program
// to configure it to emit NMEA sentences instead of binary messages.
//
// Prerequisites:
// 1) Your GPS device has been correctly powered.
// Be careful when connecting 3.3V devices.
// 2) Your GPS device is correctly connected to an Arduino serial port.
// See GPSport.h for the default connections.
//
// 'Serial' is for debug output to the Serial Monitor window.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <GPSport.h>
#include <Streamers.h>
// Check configuration
#ifndef NMEAGPS_RECOGNIZE_ALL
#error You must define NMEAGPS_RECOGNIZE_ALL in NMEAGPS_cfg.h!
#endif
#ifdef NMEAGPS_IMPLICIT_MERGING
#error You must *undefine* NMEAGPS_IMPLICIT_MERGING in NMEAGPS_cfg.h! \
Please use EXPLICIT or NO_MERGING.
#endif
#ifdef NMEAGPS_INTERRUPT_PROCESSING
#error You must *NOT* define NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h!
#endif
static NMEAGPS gps ; // This parses received characters
static gps_fix all_data ; // A composite of all GPS data fields
static uint32_t last_rx = 0UL; // The last millis() time a character was
// received from GPS.
static uint32_t valid_sentence_received = 0UL;
static bool last_sentence_received = false;
static uint32_t baudStartTime = 0UL;
static uint8_t warnings = 0;
static uint8_t errors = 0;
//--------------------------
static void hang()
{
DEBUG_PORT.println( F("\n** NMEAdiagnostic completed **\n") );
if (warnings) {
DEBUG_PORT.print( warnings );
DEBUG_PORT.print( F(" warnings") );
}
if (warnings && errors)
DEBUG_PORT.print( F(" and ") );
if (errors) {
DEBUG_PORT.print( errors );
DEBUG_PORT.print( F(" errors") );
}
if (warnings || errors)
DEBUG_PORT.println();
DEBUG_PORT.flush();
for (;;)
;
} // hang
//--------------------------
// Baud rates to check
static long baud_table[] =
{ 1200, 2400, 4800, 9600, 14400, 19200, 28800, 31250, 38400,
57600, 115200 };
static const uint8_t num_bauds = sizeof(baud_table)/sizeof(baud_table[0]);
static const uint8_t INITIAL_BAUD_INDEX = 3; // 9600
static uint8_t baud_index = INITIAL_BAUD_INDEX;
static bool triedDifferentBaud = false;
//--------------------------
static void tryBaud()
{
long baud = baud_table[baud_index];
DEBUG_PORT.print( F("\n____________________________\n\nChecking ") );
DEBUG_PORT.print( baud );
DEBUG_PORT.print( F(" baud...\n") );
DEBUG_PORT.flush();
//if (baud == 9600) baud = 17000;
gpsPort.begin( baud );
baudStartTime = millis();
} // tryBaud
//--------------------------
static void tryAnotherBaudRate()
{
gpsPort.end();
while (gpsPort.available())
gpsPort.read();
if (baud_index == INITIAL_BAUD_INDEX) {
baud_index = 0;
} else {
baud_index++;
if (baud_index == INITIAL_BAUD_INDEX)
baud_index++; // skip it, we already tried it
if (baud_index >= num_bauds) {
baud_index = INITIAL_BAUD_INDEX;
DEBUG_PORT.print( F("\n All baud rates tried!\n") );
hang();
}
}
tryBaud();
triedDifferentBaud = true;
} // tryAnotherBaudRate
//------------------------------------
static const uint16_t MAX_SAMPLE = 256;
static uint8_t someChars[ MAX_SAMPLE ];
static uint16_t someCharsIndex = 0;
static void dumpSomeChars()
{
if (someCharsIndex > 0) {
DEBUG_PORT.print( F("Received data:\n") );
const uint16_t bytes_per_line = 32;
char ascii[ bytes_per_line ];
uint8_t *ptr = &someChars[0];
for (uint16_t i=0; i<someCharsIndex; ) {
uint16_t j;
for (j=0; (i<someCharsIndex) && (j<bytes_per_line); i++, j++) {
uint8_t c = *ptr++;
if (c < 0x10)
DEBUG_PORT.print('0');
DEBUG_PORT.print( c, HEX );
if ((' ' <= c) && (c <= '~'))
ascii[ j ] = c;
else
ascii[ j ] = '.';
}
uint16_t jmax = j;
while (j++ < bytes_per_line)
DEBUG_PORT.print( F(" ") );
DEBUG_PORT.print( ' ' );
for (j=0; j<jmax; j++)
DEBUG_PORT.print( ascii[ j ] );
DEBUG_PORT.print( '\n' );
}
DEBUG_PORT.flush();
someCharsIndex = 0;
}
} // dumpSomeChars
//----------------------------------------------------------------
void displaySentences()
{
// We received one or more sentences, display the baud rate
DEBUG_PORT.print( F("\n\n**** NMEA sentence(s) detected! ****\n") );
dumpSomeChars();
DEBUG_PORT << F("\nDevice baud rate is ") <<
baud_table[ baud_index ] << '\n';
DEBUG_PORT.print( F("\nGPS data fields received:\n\n ") );
trace_header( DEBUG_PORT );
DEBUG_PORT.print( F(" ") );
trace_all( DEBUG_PORT, gps, all_data );
if (!last_sentence_received) {
warnings++;
DEBUG_PORT.print( F("\nWarning: LAST_SENTENCE_IN_INTERVAL defined to be ") );
DEBUG_PORT.print( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) );
DEBUG_PORT.println( F(", but was never received.\n"
" Please use NMEAorder.ino to determine which sentences your GPS device sends, and then\n"
" use the last one for the definition in NMEAGPS_cfg.h.") );
}
} // displaySentences
//----------------------------------------------------------------
// Listen to see if the GPS device is correctly
// connected and functioning.
static void listenForSomething()
{
uint32_t current_ms = millis();
uint32_t ms_since_last_rx = current_ms - last_rx;
bool waited_long_enough = (current_ms - baudStartTime) > 1000UL;
if ((ms_since_last_rx > 5) && waited_long_enough) {
// The GPS device has not sent any characters for at least 5ms.
// See if we've been getting chars sometime during the last second.
// If not, the GPS may not be working or connected properly.
bool getting_chars = (someCharsIndex > 0);
// Try to diagnose the problem
static uint8_t tries = 1;
bool tryNext = false;
if (!getting_chars) {
if (tries++ >= 3) {
errors++;
DEBUG_PORT.println( F("\nCheck GPS device and/or connections. No data received.\n") );
tryNext = true;
}
} else if (valid_sentence_received) {
uint8_t s = valid_sentence_received/1000;
uint8_t ms = valid_sentence_received - s*1000;
DEBUG_PORT.print( F("Valid sentences were received ") );
DEBUG_PORT.print( s );
DEBUG_PORT.print( '.' );
if (ms < 100)
DEBUG_PORT.print( '0' );
if (ms < 10)
DEBUG_PORT.print( '0' );
DEBUG_PORT.print( ms );
DEBUG_PORT.println(
F(" seconds ago.\n"
" The GPS update rate may be lower than 1Hz,\n"
" or the connections may be bad." ) );
displaySentences();
hang();
} else {
DEBUG_PORT.println(
F("No valid sentences, but characters are being received.\n"
" Check baud rate or device protocol configuration.\n" ) );
dumpSomeChars();
delay( 2000 );
tryNext = true;
}
if (tryNext) {
tries = 1;
tryAnotherBaudRate();
valid_sentence_received = 0UL;
}
}
} // listenForSomething
//------------------------------------
static void GPSloop()
{
while (gpsPort.available()) {
last_rx = millis();
uint8_t c = gpsPort.read();
if (someCharsIndex < MAX_SAMPLE)
someChars[ someCharsIndex++ ] = c;
if (gps.decode( c ) == NMEAGPS::DECODE_COMPLETED) {
all_data |= gps.fix();
valid_sentence_received = last_rx;
if (gps.nmeaMessage == LAST_SENTENCE_IN_INTERVAL)
last_sentence_received = true;
DEBUG_PORT.print( F("Received ") );
DEBUG_PORT.println( gps.string_for( gps.nmeaMessage ) );
static uint8_t sentences_printed = 0;
bool long_enough = (millis() - baudStartTime > 3000);
if (long_enough ||
(
(sentences_printed++ >= 20) &&
(someCharsIndex >= MAX_SAMPLE)
) ) {
displaySentences();
hang();
}
}
}
if (!valid_sentence_received ||
(millis() - valid_sentence_received > 3000UL))
listenForSomething();
} // GPSloop
//--------------------------
void setup()
{
DEBUG_PORT.begin(9600);
while (!DEBUG_PORT)
;
DEBUG_PORT.print( F("NMEAdiagnostic.INO: started\n") );
DEBUG_PORT.println( F("Looking for GPS device on " GPS_PORT_NAME) );
if (sizeof(gps_fix) <= 2) {
warnings++;
DEBUG_PORT.print( F("\nWarning: no fields are enabled in GPSfix_cfg.h.\n Only the following information will be displayed:\n ") );
trace_header( DEBUG_PORT );
}
#if !defined( NMEAGPS_PARSE_GGA ) & !defined( NMEAGPS_PARSE_GLL ) & \
!defined( NMEAGPS_PARSE_GSA ) & !defined( NMEAGPS_PARSE_GSV ) & \
!defined( NMEAGPS_PARSE_RMC ) & !defined( NMEAGPS_PARSE_VTG ) & \
!defined( NMEAGPS_PARSE_ZDA ) & !defined( NMEAGPS_PARSE_GST )
warnings++;
DEBUG_PORT.println( F("\nWarning: no messages are enabled for parsing in NMEAGPS_cfg.h.\n No fields will be valid, including the 'status' field.") );
#endif
DEBUG_PORT.flush();
tryBaud();
} // setup
//--------------------------
void loop()
{
GPSloop();
}

View File

@@ -0,0 +1,82 @@
#include <NMEAGPS.h>
//======================================================================
// Program: NMEAdistance.ino
//
// Description: Display distance from a base location.
//
// Prerequisites:
// 1) NMEA.ino works with your device (correct TX/RX pins and baud rate)
// 2) GPS_FIX_LOCATION has been enabled.
// 3) A sentence that contains lat/long has been enabled (GGA, GLL or RMC).
// 4) Your device sends at least one of those sentences.
//
// 'Serial' is for debug output to the Serial Monitor window.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <GPSport.h>
//------------------------------------------------------------
// Check that the config files are set up properly
#if !defined( NMEAGPS_PARSE_RMC ) & \
!defined( NMEAGPS_PARSE_GGA ) & \
!defined( NMEAGPS_PARSE_GLL )
#error You must uncomment at least one of NMEAGPS_PARSE_RMC, NMEAGPS_PARSE_GGA or NMEAGPS_PARSE_GLL in NMEAGPS_cfg.h!
#endif
#if !defined( GPS_FIX_LOCATION )
#error You must uncomment GPS_FIX_LOCATION in GPSfix_cfg.h!
#endif
NMEAGPS gps;
// The base location, in degrees * 10,000,000
NeoGPS::Location_t base( -253448688L, 1310324914L ); // Ayers Rock, AU
void setup()
{
DEBUG_PORT.begin(9600);
DEBUG_PORT.println( F("NMEAdistance.ino started.") );
DEBUG_PORT.println( F("Looking for GPS device on " GPS_PORT_NAME) );
gpsPort.begin(9600);
} // setup
void loop()
{
while (gps.available( gpsPort )) {
gps_fix fix = gps.read(); // save the latest
// When we have a location, calculate how far away we are from the base location.
if (fix.valid.location) {
float range = fix.location.DistanceMiles( base );
DEBUG_PORT.print( F("Range: ") );
DEBUG_PORT.print( range );
DEBUG_PORT.println( F(" Miles") );
} else
// Waiting...
DEBUG_PORT.print( '.' );
}
} // loop

View File

@@ -0,0 +1,183 @@
#include <NMEAGPS.h>
//======================================================================
// Program: NMEAloc.ino
//
// Description: This program only parses an RMC sentence for the lat/lon.
//
// Prerequisites:
// 1) NMEA.ino works with your device (correct TX/RX pins and baud rate)
// 2) The RMC sentence has been enabled.
// 3) Your device sends an RMC sentence (e.g., $GPRMC).
//
// 'Serial' is for debug output to the Serial Monitor window.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <GPSport.h>
//------------------------------------------------------------
// Check that the config files are set up properly
#if !defined( NMEAGPS_PARSE_RMC )
#error You must uncomment NMEAGPS_PARSE_RMC in NMEAGPS_cfg.h!
#endif
#if !defined( GPS_FIX_TIME )
#error You must uncomment GPS_FIX_TIME in GPSfix_cfg.h!
#endif
#if !defined( GPS_FIX_LOCATION )
#error You must uncomment GPS_FIX_LOCATION in GPSfix_cfg.h!
#endif
#if !defined( GPS_FIX_SPEED )
#error You must uncomment GPS_FIX_SPEED in GPSfix_cfg.h!
#endif
#if !defined( GPS_FIX_SATELLITES )
#error You must uncomment GPS_FIX_SATELLITES in GPSfix_cfg.h!
#endif
#ifdef NMEAGPS_INTERRUPT_PROCESSING
#error You must *NOT* define NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h!
#endif
//------------------------------------------------------------
static NMEAGPS gps; // This parses the GPS characters
//----------------------------------------------------------------
// Print the 32-bit integer degrees *as if* they were high-precision floats
static void printL( Print & outs, int32_t degE7 );
static void printL( Print & outs, int32_t degE7 )
{
// Extract and print negative sign
if (degE7 < 0) {
degE7 = -degE7;
outs.print( '-' );
}
// Whole degrees
int32_t deg = degE7 / 10000000L;
outs.print( deg );
outs.print( '.' );
// Get fractional degrees
degE7 -= deg*10000000L;
// Print leading zeroes, if needed
int32_t factor = 1000000L;
while ((degE7 < factor) && (factor > 1L)){
outs.print( '0' );
factor /= 10L;
}
// Print fractional degrees
outs.print( degE7 );
}
static void doSomeWork( const gps_fix & fix );
static void doSomeWork( const gps_fix & fix )
{
// This is the best place to do your time-consuming work, right after
// the RMC sentence was received. If you do anything in "loop()",
// you could cause GPS characters to be lost, and you will not
// get a good lat/lon.
// For this example, we just print the lat/lon. If you print too much,
// this routine will not get back to "loop()" in time to process
// the next set of GPS data.
if (fix.valid.location) {
if ( fix.dateTime.seconds < 10 )
DEBUG_PORT.print( '0' );
DEBUG_PORT.print( fix.dateTime.seconds );
DEBUG_PORT.print( ',' );
// DEBUG_PORT.print( fix.latitude(), 6 ); // floating-point display
// DEBUG_PORT.print( fix.latitudeL() ); // integer display
printL( DEBUG_PORT, fix.latitudeL() ); // prints int like a float
DEBUG_PORT.print( ',' );
// DEBUG_PORT.print( fix.longitude(), 6 ); // floating-point display
// DEBUG_PORT.print( fix.longitudeL() ); // integer display
printL( DEBUG_PORT, fix.longitudeL() ); // prints int like a float
DEBUG_PORT.print( ',' );
if (fix.valid.satellites)
DEBUG_PORT.print( fix.satellites );
DEBUG_PORT.print( ',' );
DEBUG_PORT.print( fix.speed(), 6 );
DEBUG_PORT.print( F(" kn = ") );
DEBUG_PORT.print( fix.speed_mph(), 6 );
DEBUG_PORT.print( F(" mph") );
} else {
// No valid location data yet!
DEBUG_PORT.print( '?' );
}
DEBUG_PORT.println();
} // doSomeWork
//------------------------------------
static void GPSloop();
static void GPSloop()
{
while (gps.available( gpsPort ))
doSomeWork( gps.read() );
} // GPSloop
//--------------------------
void setup()
{
DEBUG_PORT.begin(9600);
while (!DEBUG_PORT)
;
DEBUG_PORT.print( F("NMEAloc.INO: started\n") );
DEBUG_PORT.print( F("fix object size = ") );
DEBUG_PORT.println( sizeof(gps.fix()) );
DEBUG_PORT.print( F("NMEAGPS object size = ") );
DEBUG_PORT.println( sizeof(gps) );
DEBUG_PORT.println( F("Looking for GPS device on " GPS_PORT_NAME) );
#ifdef NMEAGPS_NO_MERGING
DEBUG_PORT.println( F("Only displaying data from xxRMC sentences.\n Other sentences may be parsed, but their data will not be displayed.") );
#endif
DEBUG_PORT.flush();
gpsPort.begin(9600);
}
//--------------------------
void loop()
{
GPSloop();
}

View File

@@ -0,0 +1,117 @@
#include <Arduino.h>
#include <NMEAGPS.h>
//======================================================================
// Program: NMEAlocDMS.ino
//
// Description: This program only parses an RMC sentence for the lat/lon.
//
// Prerequisites:
// 1) NMEA.ino works with your device (correct TX/RX pins and baud rate)
// 2) The RMC sentence has been enabled.
// 3) Your device sends an RMC sentence (e.g., $GPRMC).
//
// Serial is for trace output to the Serial Monitor window.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <GPSport.h>
//------------------------------------------------------------
// Check that the config files are set up properly
#if !defined( NMEAGPS_PARSE_RMC )
#error You must uncomment NMEAGPS_PARSE_RMC in NMEAGPS_cfg.h!
#endif
#if !defined( GPS_FIX_LOCATION_DMS )
#error You must uncomment GPS_FIX_LOCATION_DMS in GPSfix_cfg.h!
#endif
#ifdef NMEAGPS_INTERRUPT_PROCESSING
#error You must *NOT* define NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h!
#endif
//------------------------------------------------------------
static NMEAGPS gps; // This parses the GPS characters
static void doSomeWork( const gps_fix & fix );
static void doSomeWork( const gps_fix & fix )
{
// This is the best place to do your time-consuming work, right after
// the RMC sentence was received. If you do anything in "loop()",
// you could cause GPS characters to be lost, and you will not
// get a good lat/lon.
// For this example, we just print the lat/lon. If you print too much,
// this routine will not get back to "loop()" in time to process
// the next set of GPS data.
if (fix.valid.location) {
DEBUG_PORT << fix.latitudeDMS;
DEBUG_PORT.print( fix.latitudeDMS.NS() );
DEBUG_PORT.write( ' ' );
if (fix.longitudeDMS.degrees < 100)
DEBUG_PORT.write( '0' );
DEBUG_PORT << fix.longitudeDMS;
DEBUG_PORT.print( fix.longitudeDMS.EW() );
} else {
// No valid location data yet!
DEBUG_PORT.print( '?' );
}
DEBUG_PORT.println();
} // doSomeWork
//------------------------------------
static void GPSloop();
static void GPSloop()
{
while (gps.available( gpsPort ))
doSomeWork( gps.read() );
} // GPSloop
//--------------------------
void setup()
{
DEBUG_PORT.begin(9600);
while (!DEBUG_PORT)
;
DEBUG_PORT.print( F("NMEAlocDMS.INO: started\n") );
DEBUG_PORT.println( F("Looking for GPS device on " GPS_PORT_NAME) );
DEBUG_PORT.flush();
gpsPort.begin(9600);
}
//--------------------------
void loop()
{
GPSloop();
}

View File

@@ -0,0 +1,247 @@
#include <NMEAGPS.h>
//======================================================================
// Program: NMEAorder.ino
//
// Description: This example program records the order of sentences
// received in each 1-second interval. The last sentence is
// important to know, as that will be used to determine when the
// GPS quiet time is starting (see NMEA.ino). It is safe to perform
// time-consuming operations at that point, and the risk of losing
// characters will be minimized (see comments in 'GPSloop').
//
// Prerequisites:
// 1) Your GPS device has been correctly powered.
// Be careful when connecting 3.3V devices.
// 2) Your GPS device is correctly connected to an Arduino serial port.
// See GPSport.h for the default connections.
// 3) You know the default baud rate of your GPS device
// Use NMEAdiagnostic.ino to scan for the correct baud rate.
// 4) NMEAGPS_RECOGNIZE_ALL must be enabled in NMEAGPS_cfg.h
//
// 'Serial' is for debug output to the Serial Monitor window.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <GPSport.h>
//------------------------------------------------------------
// Check configuration
#ifndef NMEAGPS_RECOGNIZE_ALL
#error You must define NMEAGPS_RECOGNIZE_ALL in NMEAGPS_cfg.h!
#endif
#ifdef NMEAGPS_INTERRUPT_PROCESSING
#error You must *NOT* define NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h!
#endif
static NMEAGPS gps ; // This parses received characters
static uint32_t last_rx = 0L; // The last millis() time a character was
// received from GPS. This is used to
// determine when the GPS quiet time begins.
//------------------------------------------------------------
static NMEAGPS::nmea_msg_t last_sentence_in_interval = NMEAGPS::NMEA_UNKNOWN;
static uint8_t prev_sentence_count = 0;
static uint8_t sentence_count = 0;
static const uint8_t MAX_SENTENCES = 20; // per second
static NMEAGPS::nmea_msg_t sentences[ MAX_SENTENCES ];
static void recordSentenceTypes()
{
// Always save the last sentence, even if we're full
sentences[ sentence_count ] = gps.nmeaMessage;
if (sentence_count < MAX_SENTENCES-1)
sentence_count++;
} // recordSentenceTypes
//-----------------------------------------------------------
static void printSentenceOrder()
{
DEBUG_PORT.println( F("\nSentence order in each 1-second interval:") );
for (uint8_t i=0; i<sentence_count; i++) {
DEBUG_PORT.print( F(" ") );
DEBUG_PORT.println( gps.string_for( sentences[i] ) );
}
if (sentences[sentence_count-1] == LAST_SENTENCE_IN_INTERVAL) {
DEBUG_PORT.print( F("\nSUCCESS: LAST_SENTENCE_IN_INTERVAL is correctly set to NMEAGPS::NMEA_") );
} else {
DEBUG_PORT.print( F("\nERROR: LAST_SENTENCE_IN_INTERVAL is incorrectly set to NMEAGPS::NMEA_") );
DEBUG_PORT.print( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) );
DEBUG_PORT.print( F("!\n You must change this line in NMEAGPS_cfg.h:\n"
" #define LAST_SENTENCE_IN_INTERVAL NMEAGPS::NMEA_") );
}
DEBUG_PORT.println( gps.string_for( sentences[sentence_count-1] ) );
DEBUG_PORT.println();
} // printSentenceOrder
//------------------------------------
static void GPSloop()
{
while (gpsPort.available()) {
last_rx = millis();
if (gps.decode( gpsPort.read() ) == NMEAGPS::DECODE_COMPLETED) {
if (last_sentence_in_interval == NMEAGPS::NMEA_UNKNOWN) {
// Still building the list
recordSentenceTypes();
DEBUG_PORT.print( '.' );
}
}
}
} // GPSloop
//----------------------------------------------------------------
// Determine whether the GPS quiet time has started.
//
// This is only needed in the example programs, which must work
// for *any* GPS device.
//
// It also "pretends" to have a quiet time once per
// second so that some debug messages are emitted. This allows
// beginners to see whether the GPS device is correctly
// connected and functioning.
static bool quietTimeStarted()
{
uint32_t current_ms = millis();
uint32_t ms_since_last_rx = current_ms - last_rx;
if (ms_since_last_rx > 5) {
// The GPS device has not sent any characters for at least 5ms.
// See if we've been getting chars sometime during the last second.
// If not, the GPS may not be working or connected properly.
bool getting_chars = (ms_since_last_rx < 1000UL);
static uint32_t last_quiet_time = 0UL;
bool just_went_quiet =
(((int32_t) (last_rx - last_quiet_time)) > 10L);
bool next_quiet_time =
((current_ms - last_quiet_time) >= 1000UL);
if ((getting_chars && just_went_quiet)
||
(!getting_chars && next_quiet_time)) {
last_quiet_time = current_ms; // Remember for next loop
// If we're not getting good data, make some suggestions.
bool allDone = false;
if (!getting_chars) {
DEBUG_PORT.println( F("\nCheck GPS device and/or connections. No characters received.\n") );
allDone = true;
} else if (sentence_count == 0) {
DEBUG_PORT.println( F("No valid sentences, but characters are being received.\n"
"Check baud rate or device protocol configuration.\n" ) );
allDone = true;
}
if (allDone) {
DEBUG_PORT.print( F("\nEND.\n") );
for (;;)
; // hang!
}
// No problem, just a real GPS quiet time.
return true;
}
}
return false;
} // quietTimeStarted
//----------------------------------------------------------------
// Figure out what sentence the GPS device sends
// as the last sentence in each 1-second interval.
static void watchForLastSentence()
{
if (quietTimeStarted()) {
if (prev_sentence_count != sentence_count) {
// We have NOT received two full intervals of sentences with
// the same number of sentences in each interval. Start
// recording again.
prev_sentence_count = sentence_count;
sentence_count = 0;
} else if (sentence_count > 0) {
// Got it!
last_sentence_in_interval = sentences[ sentence_count-1 ];
}
}
} // watchForLastSentence
//--------------------------
void setup()
{
DEBUG_PORT.begin(9600);
while (!DEBUG_PORT)
;
DEBUG_PORT.print( F("NMEAorder.INO: started\n") );
DEBUG_PORT.print( F("fix object size = ") );
DEBUG_PORT.println( sizeof(gps.fix()) );
DEBUG_PORT.print( F("NMEAGPS object size = ") );
DEBUG_PORT.println( sizeof(gps) );
DEBUG_PORT.println( F("Looking for GPS device on " GPS_PORT_NAME) );
DEBUG_PORT.flush();
gpsPort.begin( 9600 );
}
//--------------------------
void loop()
{
GPSloop();
if (last_sentence_in_interval == NMEAGPS::NMEA_UNKNOWN)
watchForLastSentence();
else {
printSentenceOrder();
for (;;)
; // All done!
}
}

View File

@@ -0,0 +1,259 @@
#include <NMEAGPS.h>
//======================================================================
// Program: NMEArevGeoCache.ino
//
// Description: Activates a servo when the current location is
// close enough to the target location.
//
// Prerequisites:
// 1) NMEA.ino works with your device (correct TX/RX pins and baud rate)
// 2) The RMC sentence has been enabled.
// 3) Your device sends an RMC sentence (e.g., $GPRMC).
//
// Additional Hardware examples:
// 16x2 Character LCD: https://www.adafruit.com/products/181)
// Servo : TPro Micro SG90 https://www.adafruit.com/products/169
//
// 'Serial' is for debug output to the Serial Monitor window.
//
// Credits:
// This is simplified version of bnordlund9's Geobox:
// http://www.youtube.com/watch?v=g0060tcuofg
//
// Engagement Box by Kenton Harris 11/12/2012
//
// Reverse Geocache idea by Mikal Hart of http://arduiniana.org/
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <GPSport.h>
//------------------------------------------------------------
// Check that the config files are set up properly
#if !defined( NMEAGPS_PARSE_RMC ) & \
!defined( NMEAGPS_PARSE_GGA ) & \
!defined( NMEAGPS_PARSE_GLL )
#error You must uncomment at least one of NMEAGPS_PARSE_RMC, NMEAGPS_PARSE_GGA or NMEAGPS_PARSE_GLL in NMEAGPS_cfg.h!
#endif
#if !defined( GPS_FIX_LOCATION )
#error You must uncomment GPS_FIX_LOCATION in GPSfix_cfg.h!
#endif
//------------------------------------------------------------
// Additional Hardware includes
#include <LiquidCrystal.h>
//#include <NewLiquidCrystal_emul.h>
#include <PWMServo.h>
PWMServo servoLatch;
const int servoLock = 180; // angle (deg) of "locked" servo
const int servoUnlock = 105; // angle (deg) of "unlocked" servo
using namespace NeoGPS;
NMEAGPS gps;
float range; // current distance from HERE to THERE
const float CLOSE_ENOUGH = 300.0; // miles, change for your needs
LiquidCrystal lcd(7, 8, 6, 10, 11, 12);
const int fixLEDPin = 4;
const int servoPin = 9;
// The target location, in degrees * 10,000,000
Location_t there( 384602500, -1098191667L );
// 38°27'36.2"N 109°49'15.4"W
void setup()
{
servoLatch.attach(SERVO_PIN_A);
servoLatch.write(servoLock);
delay(50);
lcd.begin(16, 2);
Serial.begin(9600);
Serial.println( F("Debug GPS Test:") );
gpsPort.begin(9600);
// Configure GPS (these are Adafruit GPS commands - your brand may be different)
gpsPort.print
( F( "$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29\r\n" // RMC only...
"$PMTK220,1000*1F\r\n" ) ); // ...and 1 Hz update rate
} // setup
void loop()
{
static uint8_t warningState = 0;
static uint32_t lastFixTime, lastDotTime;
while (gps.available( gpsPort )) {
gps_fix fix = gps.read(); // save the latest
// Set the "fix" LED to on or off
bool gpsWasFixed = fix.valid.status && (fix.status >= gps_fix::STATUS_STD);
digitalWrite( fixLEDPin, gpsWasFixed );
// When we have a location, calculate how far away we are from "there".
if (fix.valid.location) {
lastFixTime = millis();
range = fix.location.DistanceMiles( there );
//for GPS debug
DEBUG_PORT.print( F("Here: ") );
//printDMS( DEBUG_PORT, fix.location );
printAsFloat( DEBUG_PORT, fix.location );
DEBUG_PORT.print( F(" There: ") );
//printDMS( DEBUG_PORT, there );
printAsFloat( DEBUG_PORT, there );
DEBUG_PORT.print( F("Range: ") );
DEBUG_PORT.print( range );
DEBUG_PORT.println( F(" Miles") );
// Are we there?
if (range < CLOSE_ENOUGH) {
lcd.setCursor(0,1);
lcd.println( F("Box Unlocking...") );
delay(500);
servoLatch.write(servoUnlock);
lcd.clear();
lcd.setCursor(0,1);
lcd.print( F("Happy Birthday") );
for (;;); // hang here
}
// Nope, just give a little feedback...
lcd.clear();
lcd.setCursor(0,0);
lcd.print( F("Signal Locked") );
lcd.setCursor(0,1);
lcd.print( range );
lcd.print( F(" Miles") );
warningState = 0; // restart in case we lose the fix later
}
}
// Display warnings when the GPS hasn't had a fix for a while
if (millis() - lastFixTime > 2000UL) {
if (warningState == 0) {
// First, show the warning message...
lcd.clear();
lcd.setCursor(0,0);
lcd.print( F("Acquiring Signal") );
warningState = 1;
} else if (warningState < 10) {
// ...then some dots, two per second...
if (millis() - lastDotTime > 500UL ) {
lastDotTime = millis();
lcd.setCursor( warningState-1, 1 );
lcd.print( '.' );
warningState++;
}
} else if (warningState == 10) {
// ... then tell them what to do.
lcd.setCursor(0,1);
lcd.println( F("Take box outside") );
// Don't display anything else until location is valid
warningState++; // 11
}
}
} // loop
//----------------------------------------------------------------
#include "DMS.h"
void printDMS( Print & outs, const Location_t & loc )
{
DMS_t dms;
dms.From( loc.lat() );
outs.print( dms.NS() );
outs << dms;
dms.From( loc.lon() );
outs.print( dms.EW() );
outs << dms;
} // printDMS
//----------------------------------------------------------------
void printL( Print & outs, int32_t degE7 )
{
// Extract and print negative sign
if (degE7 < 0) {
degE7 = -degE7;
outs.print( '-' );
}
// Whole degrees
int32_t deg = degE7 / 10000000L;
outs.print( deg );
outs.print( '.' );
// Get fractional degrees
degE7 -= deg*10000000L;
// Print leading zeroes, if needed
int32_t factor = 1000000L;
while ((degE7 < factor) && (factor > 1L)){
outs.print( '0' );
factor /= 10L;
}
// Print fractional degrees
outs.print( degE7 );
} // printL
//----------------------------------------------------------------
void printAsFloat( Print & outs, const Location_t &loc )
{
printL( outs, loc.lat() ); // display decimal degrees or...
// printDMS( outs, loc.lat() ); // ... display degrees minutes seconds
outs.print( F(", ") );
printL( outs, loc.lat() );
// printDMS( outs, loc.lat() );
}

View File

@@ -0,0 +1,72 @@
#include <NMEAGPS.h>
//======================================================================
// Program: NMEAsimple.ino
//
// Description: This program shows simple usage of NeoGPS
//
// Prerequisites:
// 1) NMEA.ino works with your device (correct TX/RX pins and baud rate)
// 2) At least one of the RMC, GGA or GLL sentences have been enabled in NMEAGPS_cfg.h.
// 3) Your device at least one of those sentences (use NMEAorder.ino to confirm).
// 4) LAST_SENTENCE_IN_INTERVAL has been set to one of those sentences in NMEAGPS_cfg.h (use NMEAorder.ino).
// 5) LOCATION and ALTITUDE have been enabled in GPSfix_cfg.h
//
// 'Serial' is for debug output to the Serial Monitor window.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <GPSport.h>
NMEAGPS gps; // This parses the GPS characters
gps_fix fix; // This holds on to the latest values
void setup()
{
DEBUG_PORT.begin(9600);
while (!Serial)
;
DEBUG_PORT.print( F("NMEAsimple.INO: started\n") );
gpsPort.begin(9600);
}
//--------------------------
void loop()
{
while (gps.available( gpsPort )) {
fix = gps.read();
DEBUG_PORT.print( F("Location: ") );
if (fix.valid.location) {
DEBUG_PORT.print( fix.latitude(), 6 );
DEBUG_PORT.print( ',' );
DEBUG_PORT.print( fix.longitude(), 6 );
}
DEBUG_PORT.print( F(", Altitude: ") );
if (fix.valid.altitude)
DEBUG_PORT.print( fix.altitude() );
DEBUG_PORT.println();
}
}

View File

@@ -0,0 +1,771 @@
#include <NMEAGPS.h>
using namespace NeoGPS;
//======================================================================
// Program: NMEAtest.ino
//
// Prerequisites:
// 1) All NMEA standard messages and Satellite Information
// are enabled.
// 2) All 'gps_fix' members are enabled.
// 3) All validation options are enabled.
//
// Description: This test program uses one GPGGA sentence
// to test the parser's:
// 1) robustness WRT dropped, inserted, and mangled characters
// 2) correctness WRT values extracted from the input stream
//
// Some care in testing must be taken because
// 1) The XOR-style checksum is not very good at catching errors.
// 2) The '*' is a special character for delimiting the CRC. If
// it is changed, a CR/LF will allow the sentence to pass.
//
// 'Serial' is for debug output to the Serial Monitor window.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <Streamers.h>
//------------------------------------------------------------
// Check that the config files are set up properly
#if !defined(NMEAGPS_PARSE_GGA) | \
!defined(NMEAGPS_PARSE_GLL) | \
!defined(NMEAGPS_PARSE_GSA) | \
!defined(NMEAGPS_PARSE_GST) | \
!defined(NMEAGPS_PARSE_GSV) | \
!defined(NMEAGPS_PARSE_RMC) | \
!defined(NMEAGPS_PARSE_VTG) | \
!defined(NMEAGPS_PARSE_ZDA)
#error NMEAGPS_PARSE_GGA, GLL, GSA, GSV, RMC, VTG and ZDA must be defined in NMEAGPS_cfg.h!
#endif
#ifndef GPS_FIX_DATE
#error GPS_FIX_DATE must be defined in GPSfix_cfg.h!
#endif
#ifndef GPS_FIX_TIME
#error GPS_FIX_TIME must be defined in GPSfix_cfg.h!
#endif
#ifndef GPS_FIX_LOCATION
#error GPS_FIX_LOCATION must be defined in GPSfix_cfg.h!
#endif
#ifndef GPS_FIX_LOCATION_DMS
#error GPS_FIX_LOCATION_DMS must be defined in GPSfix_cfg.h!
#endif
#ifndef GPS_FIX_ALTITUDE
#error GPS_FIX_ALTITUDE must be defined in GPSfix_cfg.h!
#endif
#ifndef GPS_FIX_SPEED
#error GPS_FIX_SPEED must be defined in GPSfix_cfg.h!
#endif
#ifndef GPS_FIX_HEADING
#error GPS_FIX_HEADING must be defined in GPSfix_cfg.h!
#endif
#ifndef GPS_FIX_SATELLITES
#error GPS_FIX_SATELLITES must be defined in GPSfix_cfg.h!
#endif
#ifndef GPS_FIX_HDOP
#error GPS_FIX_HDOP must be defined in GPSfix_cfg.h!
#endif
#ifndef GPS_FIX_GEOID_HEIGHT
#error GPS_FIX_GEOID_HEIGHT must be defined in GPSfix_cfg.h!
#endif
static NMEAGPS gps;
//--------------------------
// Example sentences
struct LocVector_t
{
float range;
float bearing;
};
static Location_t AyersRock( -253448688L, 1310324914L );
// -25.3448688,131.0324914
// 2520.692128,S,13101.949484,E
// 25 20' 41.528" S 131 1' 56.969" E
static const LocVector_t NiihauToAyersRock = { 9078.681, 238.33972 };
const char validRMC[] __PROGMEM =
"$GPRMC,092725.00,A,2520.69213,S,13101.94948,E,"
"0.004,77.52,091202,,,A*43\r\n";
//...........................
static Location_t ubloxHQ( 472852369L, 85630763L ); // near Zurich, Switzerland
// 47.2852369, 8.5630763
// 47 17' 6.840" N 008 33' 54.954" E
static const LocVector_t NiihauToUblox = { 12248.67, 8.0625 };
const char validGGA[] __PROGMEM =
"$GPGGA,092725.00,4717.113993,N,00833.915904,E,"
"1,8,1.01,499.6,M,48.0,M,,0*5C\r\n";
//...........................
static Location_t MacchuPicchu( -131628050L, -725455080L );
// -13.162805, -72.545508
// 13.162805,S,72.545508,W
// 13 09' 46.098" S 72 32' 43.830" W
static const LocVector_t NiihauToMacchu = { 10315.93, 103.07306 };
const char validGGA2[] __PROGMEM =
"$GPGGA,162254.00,1309.7683,S,7232.7305,W,1,03,2.36,2430.2,M,-25.6,M,,*7E\r\n";
//...........................
static Location_t DexterMO( 367944050L, -899586550L );
// 36.794405, -89.958655
// 36.794405,N,89.958655,W
// 36 47' 39.858" N 89 57' 31.158" W
static const LocVector_t NiihauToDexter = { 6865.319, 58.85472 };
const char validRMC2[] __PROGMEM =
"$GPRMC,162254.00,A,3647.6643,N,8957.5193,W,0.820,188.36,110706,,,A*49\r\n";
//...........................
static Location_t NiihauHI( 218276210L, -1602448760L );
// 21.827621, -160.244876
// 21.827621,N,160.244876,W
// 21 49' 39.4356" N 160 14' 41.5536 W
static const LocVector_t NiihauToNiihau = { 0.0, 90.0 };
const char validRMC3[] __PROGMEM =
"$GPRMC,235959.99,A,2149.65726,N,16014.69256,W,8.690,359.99,051015,9.47,E,A*26\r\n";
// 218276212L, -1602448757L
// 21 49.65727' N 160 14.69254' W
// 21 49' 39.4362" N 160 14' 41.5524" W
const char validRMC4[] __PROGMEM =
"$GPRMC,235959.99,A,2149.65727,N,16014.69254,W,8.690,359.99,051015,9.47,E,A*25\r\n";
static const LocVector_t NiihauToNiihau2 = { 0.00003812513, 54.31585 };
//...........................
static Location_t JujaKenya( -10934552L, 370261835L );
// -1.0934552, 37.0261835
// 01 05' 36.458" S 037 01' 42.140" E
static const LocVector_t NiihauToJuja = { 17046.24, 318.6483 };
const char validGLL[] __PROGMEM =
"$GNGLL,0105.60764,S,03701.70233,E,225627.00,A,A*6B\r\n";
//--------------------------------
const char mtk1[] __PROGMEM =
"$GPGGA,064951.000,2307.1256,N,12016.4438,E,1,8,0.95,39.9,M,17.8,M,,*63\r\n";
const char mtk2[] __PROGMEM =
"$GPRMC,064951.000,A,2307.1256,N,12016.4438,E,0.03,165.48,260406,3.05,W,A*2C\r\n";
const char mtk3[] __PROGMEM =
"$GPVTG,165.48,T,,M,0.03,N,0.06,K,A*36\r\n";
const char mtk4[] __PROGMEM =
"$GPGSA,A,3,29,21,26,15,18,09,06,10,,,,,2.32,0.95,2.11*00\r\n";
const char mtk5[] __PROGMEM =
"$GPGSV,3,1,09,29,36,029,42,21,46,314,43,26,44,020,43,15,21,321,39*7D\r\n";
const char mtk6[] __PROGMEM =
"$GPGSV,3,2,09,18,26,314,40,09,57,170,44,06,20,229,37,10,26,084,37*77\r\n";
const char mtk7[] __PROGMEM =
"$GPGSV,3,3,09,07,,,26*73\r\n";
const char mtk7a[] __PROGMEM =
"$GLGSV,1,1,4,29,36,029,42,21,46,314,43,26,44,020,43,15,21,321,39*5E\r\n";
const char mtk8[] __PROGMEM =
"$GNGST,082356.00,1.8,,,,1.7,1.3,2.2*60\r\n";
const char mtk9[] __PROGMEM =
"$GNRMC,083559.00,A,4717.11437,N,00833.91522,E,0.004,77.52,091202,,,A,V*33\r\n";
const char mtk10[] __PROGMEM =
"$GNGGA,092725.00,4717.11399,N,00833.91590,E,1,08,1.01,499.6,M,48.0,M,,*45\r\n";
const char mtk11[] __PROGMEM =
"$GLZDA,225627.00,21,09,2015,00,00*70\r\n";
const char fpGGA00[] __PROGMEM = "$GPGGA,092725.00,3242.9000,N,11705.816900,W,"
"1,8,1.01,499.6,M,48.0,M,,0*49\r\n";
const char fpGGA01[] __PROGMEM = "$GPGGA,092725.00,3242.9000,N,11705.816901,W,"
"1,8,1.01,499.6,M,48.0,M,,0*48\r\n";
const char fpGGA02[] __PROGMEM = "$GPGGA,092725.00,3242.9000,N,11705.816902,W,"
"1,8,1.01,499.6,M,48.0,M,,0*4B\r\n";
const char fpGGA03[] __PROGMEM = "$GPGGA,092725.00,3242.9000,N,11705.816903,W,"
"1,8,1.01,499.6,M,48.0,M,,0*4A\r\n";
const char fpGGA04[] __PROGMEM = "$GPGGA,092725.00,3242.9000,N,11705.816904,W,"
"1,8,1.01,499.6,M,48.0,M,,0*4D\r\n";
const char fpGGA05[] __PROGMEM = "$GPGGA,092725.00,3242.9000,N,11705.816905,W,"
"1,8,1.01,499.6,M,48.0,M,,0*4C\r\n";
const char fpGGA06[] __PROGMEM = "$GPGGA,092725.00,3242.9000,N,11705.816906,W,"
"1,8,1.01,499.6,M,48.0,M,,0*4F\r\n";
const char fpGGA07[] __PROGMEM = "$GPGGA,092725.00,3242.9000,N,11705.816907,W,"
"1,8,1.01,499.6,M,48.0,M,,0*4E\r\n";
const char fpGGA08[] __PROGMEM = "$GPGGA,092725.00,3242.9000,N,11705.816908,W,"
"1,8,1.01,499.6,M,48.0,M,,0*41\r\n";
const char fpGGA09[] __PROGMEM = "$GPGGA,092725.00,3242.9000,N,11705.816909,W,"
"1,8,1.01,499.6,M,48.0,M,,0*40\r\n";
const char fpGGA10[] __PROGMEM = "$GPGGA,092725.00,3242.9000,N,11705.816910,W,"
"1,8,1.01,499.6,M,48.0,M,,0*48\r\n";
//--------------------------
static bool parse_P( const char *ptr )
{
bool decoded = false;
char c;
gps.fix().init();
while ( (c = pgm_read_byte( ptr++ )) != '\0' ) {
if (NMEAGPS::DECODE_COMPLETED == gps.decode( c )) {
decoded = true;
}
}
return decoded;
}
//--------------------------
static void traceSample( const char *ptr, bool init = true )
{
Serial << F("Input: ") << (const __FlashStringHelper *) ptr;
if (init)
gps.data_init();
bool decoded = parse_P( ptr );
if (decoded)
Serial << F("Results: ");
else
Serial << F("Failed to decode! ");
trace_all( Serial, gps, gps.fix() );
Serial << '\n';
}
//--------------------------
static uint8_t passed = 0;
static uint8_t failed = 0;
static void checkFix
( const char *msg, NMEAGPS::nmea_msg_t msg_type, gps_fix::status_t status,
int32_t lat, int32_t lon,
uint8_t latDeg, uint8_t latMin, uint8_t latSec, uint16_t latSecFrac, Hemisphere_t ns,
uint8_t lonDeg, uint8_t lonMin, uint8_t lonSec, uint16_t lonSecFrac, Hemisphere_t ew,
const LocVector_t & to )
{
const char *ptr = msg;
for (;;) {
char c = pgm_read_byte( ptr++ );
if (!c) {
Serial.print( F("FAILED to parse \"") );
Serial.print( (const __FlashStringHelper *) msg );
Serial.println( F("\"\n") );
failed++;
break;
}
if (NMEAGPS::DECODE_COMPLETED == gps.decode( c )) {
bool ok = true;
const gps_fix & fix = gps.fix();
if (gps.nmeaMessage != msg_type) {
Serial.print( F("FAILED wrong message type ") );
Serial.println( gps.nmeaMessage );
failed++;
ok = false;
}
if (fix.status != status ) {
Serial.print( F("FAILED wrong status ") );
Serial.print( fix.status );
Serial.print( F(" (expected ") );
Serial.print( status );
Serial.println( ')' );
failed++;
ok = false;
}
if (fix.latitudeL() != lat) {
Serial.print( F("FAILED wrong latitude ") );
Serial.print( fix.latitudeL() );
Serial.print( F(" (expected ") );
Serial.print( lat );
Serial.println( ')' );
failed++;
ok = false;
}
if (fix.longitudeL() != lon) {
Serial.print( F("FAILED wrong longitude ") );
Serial.print( fix.longitudeL() );
Serial.print( F(" (expected ") );
Serial.print( lon );
Serial.println( ')' );
failed++;
ok = false;
}
if (fix.latitudeDMS.degrees != latDeg) {
Serial.print( F("FAILED wrong latitude degrees ") );
Serial.print( fix.latitudeDMS.degrees );
Serial.print( F(", expected ") );
Serial.println( latDeg );
failed++;
ok = false;
}
if (fix.latitudeDMS.minutes != latMin) {
Serial.print( F("FAILED wrong latitude minutes ") );
Serial.print( fix.latitudeDMS.minutes );
Serial.print( F(", expected ") );
Serial.println( latMin );
failed++;
ok = false;
}
if (fix.latitudeDMS.seconds_whole != latSec) {
Serial.print( F("FAILED wrong latitude seconds ") );
Serial.print( fix.latitudeDMS.seconds_whole );
Serial.print( F(", expected ") );
Serial.println( latSec );
failed++;
ok = false;
}
int8_t fracDiff = (int8_t)(fix.latitudeDMS.seconds_frac - latSecFrac);
const int8_t ieps = 1;
if (abs(fracDiff) > ieps) {
Serial.print( F("FAILED wrong latitude seconds fraction ") );
Serial.print( fix.latitudeDMS.seconds_frac );
Serial.print( F(", expected ") );
Serial.println( latSecFrac );
failed++;
ok = false;
}
if (fix.latitudeDMS.hemisphere != ns) {
Serial.print( F("FAILED wrong latitude NS ") );
Serial.println( fix.latitudeDMS.NS() );
failed++;
ok = false;
}
if (fix.longitudeDMS.degrees != lonDeg) {
Serial.print( F("FAILED wrong longitude degrees ") );
Serial.print( fix.longitudeDMS.degrees );
Serial.print( F(", expected ") );
Serial.println( lonDeg );
failed++;
ok = false;
}
if (fix.longitudeDMS.minutes != lonMin) {
Serial.print( F("FAILED wrong longitude minutes ") );
Serial.print( fix.longitudeDMS.minutes );
Serial.print( F(", expected ") );
Serial.println( lonMin );
failed++;
ok = false;
}
if (fix.longitudeDMS.seconds_whole != lonSec) {
Serial.print( F("FAILED wrong longitude seconds ") );
Serial.print( fix.longitudeDMS.seconds_whole );
Serial.print( F(", expected ") );
Serial.println( lonSec );
failed++;
ok = false;
}
fracDiff = (int8_t)(fix.longitudeDMS.seconds_frac - lonSecFrac);
if (abs(fracDiff) > ieps) {
Serial.print( F("FAILED wrong longitude seconds fraction ") );
Serial.print( fix.longitudeDMS.seconds_frac );
Serial.print( F(", expected ") );
Serial.println( lonSecFrac );
failed++;
ok = false;
}
if (fix.longitudeDMS.hemisphere != ew) {
Serial.print( F("FAILED wrong longitude EW ") );
Serial.println( fix.longitudeDMS.EW() );
failed++;
ok = false;
}
char floatChars[16];
float distance = NiihauHI.DistanceKm( fix.location );
float diff = abs( distance - to.range );
if ( (diff/to.range) > 0.000001 ) {
Serial.print( F("FAILED distance ") );
dtostre( distance, floatChars, 6, DTOSTR_PLUS_SIGN );
Serial.print( floatChars );
Serial.print( F(" != ") );
dtostre( to.range, floatChars, 6, DTOSTR_PLUS_SIGN );
Serial.println( floatChars );
failed++;
ok = false;
}
float courseTo = NiihauHI.BearingToDegrees( fix.location );
diff = abs( courseTo - to.bearing );
if ( diff > 0.005 ) {
Serial.print( F("FAILED bearing ") );
dtostre( courseTo, floatChars, 6, DTOSTR_PLUS_SIGN );
Serial.print( floatChars );
Serial.print( F(" != ") );
dtostre( to.bearing, floatChars, 6, DTOSTR_PLUS_SIGN );
Serial.print( floatChars );
failed++;
ok = false;
}
if (ok)
passed++;
break;
}
}
}
//--------------------------
void setup()
{
// Start the normal trace output
Serial.begin(9600);
Serial.print( F("NMEA test: started\n") );
Serial.print( F("fix object size = ") );
Serial.println( sizeof(gps_fix) );
Serial.print( F("gps object size = ") );
Serial.println( sizeof(NMEAGPS) );
// Some basic rejection tests
Serial.println( F("Test rejection of all byte values") );
for (uint16_t c=0; c < 256; c++) {
if (c != '$') {
if (NMEAGPS::DECODE_CHR_INVALID != gps.decode( (char)c )) {
Serial.print( F("FAILED to reject single character ") );
Serial.println( c );
failed++;
return;
}
}
}
passed++;
Serial.println( F("Test rejection of multiple $") );
for (uint16_t i=0; i < 256; i++) {
if (NMEAGPS::DECODE_COMPLETED == gps.decode( '$' )) {
Serial.print( F("FAILED to reject multiple '$' characters\n") );
failed++;
return;
}
}
passed++;
uint16_t validGGA_len = 0;
// Insert a ' ' at each position of the test sentence
Serial.println( F("Insert ' '") );
uint16_t insert_at = 1;
do {
const char *ptr = validGGA;
uint8_t j = 0;
for (;;) {
if (j++ == insert_at) {
NMEAGPS::decode_t result = gps.decode( ' ' );
if (gps.validateChars() || gps.validateFields()) {
if (result == NMEAGPS::DECODE_COMPLETED) {
Serial.print( F("FAILED incorrectly decoded ' ' @ pos ") );
Serial.println( insert_at );
failed++;
} else if (gps.nmeaMessage != NMEAGPS::NMEA_UNKNOWN) {
Serial.print( F("FAILED incorrectly accepted ' ' @ pos ") );
Serial.println( insert_at );
failed++;
}
}
}
char c = pgm_read_byte( ptr++ );
if (!c) {
if (validGGA_len == 0) {
validGGA_len = j-1;
Serial.print( F("Test string length = ") );
Serial.println( validGGA_len );
}
break;
}
if (gps.decode( c ) == NMEAGPS::DECODE_COMPLETED) {
Serial.print( F("FAILED incorrectly decoded @ pos ") );
Serial.println( insert_at );
failed++;
//return;
}
}
} while (++insert_at < validGGA_len-2);
passed++;
// Drop one character from each position in example sentence
Serial.println( F("Drop character") );
for (uint16_t i=0; i < validGGA_len-3; i++) {
const char *ptr = validGGA;
uint8_t firstInvalidPos = 0;
char dropped = 0;
for (uint8_t j = 0;; j++) {
char c = pgm_read_byte( ptr++ );
if (!c || (c == '*')) break;
if (j == i) {
dropped = c;
} else {
NMEAGPS::decode_t result = gps.decode( c );
if (result == NMEAGPS::DECODE_COMPLETED) {
Serial.print( F("FAILED decoded after dropping '") );
Serial << dropped;
Serial.print( F("' at pos ") );
Serial.println( i );
failed++;
} else if (gps.nmeaMessage == NMEAGPS::NMEA_UNKNOWN) {
if (firstInvalidPos != 0)
firstInvalidPos = j;
}
}
}
if (firstInvalidPos != 0) {
Serial.print( F(" /*") );
Serial.print( i );
Serial.print( F("*/ ") );
Serial.println( firstInvalidPos );
}
}
passed++;
// Mangle one character from each position in example sentence
Serial.println( F("Mangle one character") );
for (uint16_t i=0; i < validGGA_len-3; i++) {
const char *ptr = validGGA;
uint8_t j = 0;
char replaced = 0;
for (;;) {
char c = pgm_read_byte( ptr++ );
if (!c || (c == '*')) break;
if (j++ == i)
replaced = c++; // mangle means increment
if (NMEAGPS::DECODE_COMPLETED == gps.decode( c )) {
Serial.print( F("FAILED replacing '") );
Serial << (uint8_t) replaced;
Serial.print( F("' with '") );
Serial << (uint8_t) (replaced+1);
Serial.print( F("' at pos ") );
Serial.println( i );
failed++;
break;
//return;
}
}
}
passed++;
// Verify that exact values are extracted
Serial.println( F("Verify parsed values") );
{
const char *ptr = validGGA;
for (;;) {
char c = pgm_read_byte( ptr++ );
if (!c) {
Serial.print( F("FAILED to parse \"") );
Serial.print( (str_P) validGGA );
Serial.println( F("\"\n") );
failed++;
break;
}
if (NMEAGPS::DECODE_COMPLETED == gps.decode( c )) {
gps_fix expected;
expected.dateTime.parse( PSTR("2002-12-09 09:27:25") );
expected.dateTime_cs = 0;
if (gps.nmeaMessage != NMEAGPS::NMEA_GGA) {
Serial.print( F("FAILED wrong message type ") );
Serial.println( gps.nmeaMessage );
failed++;
break;
}
if ((gps.fix().dateTime.hours != expected.dateTime.hours ) ||
(gps.fix().dateTime.minutes != expected.dateTime.minutes) ||
(gps.fix().dateTime.seconds != expected.dateTime.seconds) ||
(gps.fix().dateTime_cs != expected.dateTime_cs)) {
Serial << F("FAILED wrong time ") << gps.fix().dateTime << '.' << gps.fix().dateTime_cs << F(" != ") << expected.dateTime << '.' << expected.dateTime_cs << '\n';
failed++;
break;
}
if (gps.fix().latitudeL() != 472852332L) {
Serial.print( F("FAILED wrong latitude ") );
Serial.println( gps.fix().latitudeL() );
failed++;
break;
}
if (gps.fix().longitudeL() != 85652651L) {
Serial.print( F("FAILED wrong longitude ") );
Serial.println( gps.fix().longitudeL() );
failed++;
break;
}
if (gps.fix().status != gps_fix::STATUS_STD) {
Serial.print( F("FAILED wrong status ") );
Serial.println( gps.fix().status );
failed++;
break;
}
if (gps.fix().satellites != 8) {
Serial.print( F("FAILED wrong satellites ") );
Serial.println( gps.fix().satellites );
failed++;
break;
}
if (gps.fix().hdop != 1010) {
Serial.print( F("FAILED wrong HDOP ") );
Serial.println( gps.fix().hdop );
failed++;
break;
}
if (gps.fix().altitude_cm() != 49960) {
Serial.print( F("FAILED wrong altitude ") );
Serial.println( gps.fix().longitudeL() );
failed++;
break;
}
break;
}
}
}
passed++;
checkFix( validRMC , NMEAGPS::NMEA_RMC, gps_fix::STATUS_STD,
-253448688L, 1310324913L,
25, 20, 41, 528, SOUTH_H, 131, 1, 56, 969, EAST_H,
NiihauToAyersRock );
checkFix( validGGA , NMEAGPS::NMEA_GGA, gps_fix::STATUS_STD,
472852332L, 85652651L,
47, 17, 6, 840, NORTH_H, 8, 33, 54, 954, EAST_H,
NiihauToUblox );
if (gps.fix().geoidHeight_cm() != 4800) {
Serial.print( F("FAILED wrong geoid height for 48.00") );
Serial.println( gps.fix().geoidHeight_cm() );
failed++;
}
checkFix( validGGA2, NMEAGPS::NMEA_GGA, gps_fix::STATUS_STD,
-131628050L, -725455083L,
13, 9, 46, 98, SOUTH_H, 72, 32, 43, 830, WEST_H,
NiihauToMacchu );
if (gps.fix().geoidHeight_cm() != -2560) {
Serial.print( F("FAILED wrong geoid height for -25.60") );
Serial.println( gps.fix().geoidHeight_cm() );
failed++;
}
checkFix( validRMC2, NMEAGPS::NMEA_RMC, gps_fix::STATUS_STD,
367944050L, -899586550L,
36, 47, 39, 858, NORTH_H, 89, 57, 31, 158, WEST_H,
NiihauToDexter );
checkFix( validRMC3, NMEAGPS::NMEA_RMC, gps_fix::STATUS_STD,
218276210L, -1602448760L,
21, 49, 39, 436, NORTH_H, 160, 14, 41, 554, WEST_H,
NiihauToNiihau );
checkFix( validRMC4, NMEAGPS::NMEA_RMC, gps_fix::STATUS_STD,
218276212L, -1602448757L,
21, 49, 39, 436, NORTH_H, 160, 14, 41, 552, WEST_H,
NiihauToNiihau2 );
checkFix( validGLL , NMEAGPS::NMEA_GLL, gps_fix::STATUS_STD,
-10934607L, 370283722L,
1, 5, 36, 458, SOUTH_H, 37, 1, 42, 140, EAST_H,
NiihauToJuja );
}
//--------------------------
void loop()
{
Serial.print( F("PASSED ") );
Serial << passed;
Serial.println( F(" tests.") );
if (failed) {
Serial.print( F("FAILED ") );
Serial << failed;
Serial.println( F(" tests.") );
} else {
Serial << F("------ Samples ------\nResults format:\n ");
trace_header( Serial );
Serial << '\n';
#ifdef NMEAGPS_STATS
gps.statistics.init();
#endif
traceSample( validGGA );
traceSample( validGGA2 );
traceSample( validRMC );
traceSample( validRMC2 );
traceSample( validRMC3 );
traceSample( validGLL );
traceSample( mtk1 );
traceSample( mtk2 );
traceSample( mtk3 );
traceSample( mtk4 );
traceSample( mtk5 );
traceSample( mtk6, false );
traceSample( mtk7, false );
traceSample( mtk7a, false );
traceSample( mtk8 );
traceSample( mtk9 );
traceSample( mtk10 );
traceSample( mtk11 );
if (!gps.fix().valid.date ||
(gps.fix().dateTime.date != 21) ||
(gps.fix().dateTime.month != 9) ||
(gps.fix().dateTime.year != 15) ||
!gps.fix().valid.time ||
(gps.fix().dateTime.hours != 22) ||
(gps.fix().dateTime.minutes != 56) ||
(gps.fix().dateTime.seconds != 27))
Serial << F("******** ZDA not parsed correctly **********\n");
/**
* This next section displays incremental longitudes.
* If you have defined USE_FLOAT in Streamers.cpp, this will show
* how the conversion to /float/ causes loss of accuracy compared
* to the /uint32_t/ values.
*/
Serial << F("--- floating point conversion tests ---\n\n");
traceSample( fpGGA00 );
traceSample( fpGGA01 );
traceSample( fpGGA02 );
traceSample( fpGGA03 );
traceSample( fpGGA04 );
traceSample( fpGGA05 );
traceSample( fpGGA06 );
traceSample( fpGGA07 );
traceSample( fpGGA08 );
traceSample( fpGGA09 );
traceSample( fpGGA10 );
}
for (;;);
}

View File

@@ -0,0 +1,188 @@
#include <NMEAGPS.h>
//======================================================================
// Program: NMEAtimezone.ino
//
// Description: This program shows how to offset the GPS dateTime member
// into your specific timezone. GPS devices do not know which
// timezone they are in, so they always report a UTC time. This
// is the same as GMT.
//
// Prerequisites:
// 1) NMEA.ino works with your device
// 2) GPS_FIX_TIME is enabled in GPSfix_cfg.h
// 3) NMEAGPS_PARSE_RMC is enabled in NMEAGPS_cfg.h. You could use
// any sentence that contains a time field. Be sure to change the
// "if" statement in GPSloop from RMC to your selected sentence.
//
// 'Serial' is for debug output to the Serial Monitor window.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
static NMEAGPS gps; // This parses received characters
static gps_fix fix; // This contains all the parsed pieces
//--------------------------
// CHECK CONFIGURATION
#if !defined(GPS_FIX_TIME) | !defined(GPS_FIX_DATE)
#error You must define GPS_FIX_TIME and DATE in GPSfix_cfg.h!
#endif
#if !defined(NMEAGPS_PARSE_RMC) & !defined(NMEAGPS_PARSE_ZDA)
#error You must define NMEAGPS_PARSE_RMC or ZDA in NMEAGPS_cfg.h!
#endif
#include <GPSport.h>
//--------------------------
// Set these values to the offset of your timezone from GMT
static const int32_t zone_hours = -5L; // EST
static const int32_t zone_minutes = 0L; // usually zero
static const NeoGPS::clock_t zone_offset =
zone_hours * NeoGPS::SECONDS_PER_HOUR +
zone_minutes * NeoGPS::SECONDS_PER_MINUTE;
// Uncomment one DST changeover rule, or define your own:
#define USA_DST
//#define EU_DST
#if defined(USA_DST)
static const uint8_t springMonth = 3;
static const uint8_t springDate = 14; // latest 2nd Sunday
static const uint8_t springHour = 2;
static const uint8_t fallMonth = 11;
static const uint8_t fallDate = 7; // latest 1st Sunday
static const uint8_t fallHour = 2;
#define CALCULATE_DST
#elif defined(EU_DST)
static const uint8_t springMonth = 3;
static const uint8_t springDate = 31; // latest last Sunday
static const uint8_t springHour = 1;
static const uint8_t fallMonth = 10;
static const uint8_t fallDate = 31; // latest last Sunday
static const uint8_t fallHour = 1;
#define CALCULATE_DST
#endif
//--------------------------
void adjustTime( NeoGPS::time_t & dt )
{
NeoGPS::clock_t seconds = dt; // convert date/time structure to seconds
#ifdef CALCULATE_DST
// Calculate DST changeover times once per reset and year!
static NeoGPS::time_t changeover;
static NeoGPS::clock_t springForward, fallBack;
if ((springForward == 0) || (changeover.year != dt.year)) {
// Calculate the spring changeover time (seconds)
changeover.year = dt.year;
changeover.month = springMonth;
changeover.date = springDate;
changeover.hours = springHour;
changeover.minutes = 0;
changeover.seconds = 0;
changeover.set_day();
// Step back to a Sunday, if day != SUNDAY
changeover.date -= (changeover.day - NeoGPS::time_t::SUNDAY);
springForward = (NeoGPS::clock_t) changeover;
// Calculate the fall changeover time (seconds)
changeover.month = fallMonth;
changeover.date = fallDate;
changeover.hours = fallHour - 1; // to account for the "apparent" DST +1
changeover.set_day();
// Step back to a Sunday, if day != SUNDAY
changeover.date -= (changeover.day - NeoGPS::time_t::SUNDAY);
fallBack = (NeoGPS::clock_t) changeover;
}
#endif
// First, offset from UTC to the local timezone
seconds += zone_offset;
#ifdef CALCULATE_DST
// Then add an hour if DST is in effect
if ((springForward <= seconds) && (seconds < fallBack))
seconds += NeoGPS::SECONDS_PER_HOUR;
#endif
dt = seconds; // convert seconds back to a date/time structure
} // adjustTime
//--------------------------
static void GPSloop()
{
while (gps.available( gpsPort )) {
fix = gps.read();
// Display the local time
if (fix.valid.time && fix.valid.date) {
adjustTime( fix.dateTime );
DEBUG_PORT << fix.dateTime;
}
DEBUG_PORT.println();
}
} // GPSloop
//--------------------------
#ifdef NMEAGPS_INTERRUPT_PROCESSING
static void GPSisr( uint8_t c )
{
gps.handle( c );
}
#endif
//--------------------------
void setup()
{
DEBUG_PORT.begin(9600);
while (!DEBUG_PORT)
;
DEBUG_PORT.print( F("NMEAtimezone.INO: started\n") );
DEBUG_PORT.println( F("Looking for GPS device on " GPS_PORT_NAME ) );
DEBUG_PORT.println( F("Local time") );
DEBUG_PORT.flush();
gpsPort.begin( 9600 );
#ifdef NMEAGPS_INTERRUPT_PROCESSING
gpsPort.attachInterrupt( GPSisr );
#endif
}
//--------------------------
void loop()
{
GPSloop();
}

View File

@@ -0,0 +1,156 @@
#include <NeoGPS_cfg.h>
#include <ublox/ubxNMEA.h>
//======================================================================
// Program: PUBX.ino
//
// Description: This program parses NMEA proprietary messages from
// ublox devices. It is an extension of NMEA.ino.
//
// Prerequisites:
// 1) You have a ublox GPS device
// 2) NMEA.ino works with your device
// 3) You have installed ubxNMEA.H and ubxNMEA.CPP
// 4) At least one NMEA standard or proprietary sentence has been enabled.
// 5) Implicit Merging is disabled.
//
// Serial is for debug output to the Serial Monitor window.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <GPSport.h>
#include <Streamers.h>
//------------------------------------------------------------
// Check that the config files are set up properly
#if !defined( NMEAGPS_PARSE_GGA ) & !defined( NMEAGPS_PARSE_GLL ) & \
!defined( NMEAGPS_PARSE_GSA ) & !defined( NMEAGPS_PARSE_GSV ) & \
!defined( NMEAGPS_PARSE_RMC ) & !defined( NMEAGPS_PARSE_VTG ) & \
!defined( NMEAGPS_PARSE_ZDA ) & !defined( NMEAGPS_PARSE_GST ) & \
!defined( NMEAGPS_PARSE_PUBX_00 ) & !defined( NMEAGPS_PARSE_PUBX_04 )
#error No NMEA sentences enabled: no fix data available for fusing.
#endif
#if !defined( NMEAGPS_PARSE_PUBX_00 ) & !defined( NMEAGPS_PARSE_PUBX_04 )
#error No PUBX messages enabled! You must enable one or more in ubxNMEA.h!
#endif
#ifndef NMEAGPS_DERIVED_TYPES
#error You must "#define NMEAGPS_DERIVED_TYPES" in NMEAGPS_cfg.h!
#endif
#ifndef NMEAGPS_EXPLICIT_MERGING
#error You must define NMEAGPS_EXPLICIT_MERGING in NMEAGPS_cfg.h
#endif
#ifdef NMEAGPS_INTERRUPT_PROCESSING
#error You must *NOT* define NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h!
#endif
//------------------------------------------------------------
static ubloxNMEA gps; // This parses received characters
static gps_fix merged;
//----------------------------------------------------------------
static void poll()
{
#if defined( NMEAGPS_PARSE_PUBX_00 )
gps.send_P( &gpsPort, F("PUBX,00") );
#endif
#if defined( NMEAGPS_PARSE_PUBX_04 )
gps.send_P( &gpsPort, F("PUBX,04") );
#endif
}
//----------------------------------------------------------------
static void doSomeWork()
{
// Print all the things!
trace_all( DEBUG_PORT, gps, merged );
// Ask for the proprietary messages again
poll();
} // doSomeWork
//------------------------------------
static void GPSloop()
{
while (gps.available( gpsPort )) {
merged = gps.read();
doSomeWork();
}
} // GPSloop
//--------------------------
void setup()
{
DEBUG_PORT.begin(9600);
while (!DEBUG_PORT)
;
DEBUG_PORT.print( F("PUBX: started\n") );
DEBUG_PORT.print( F("fix object size = ") );
DEBUG_PORT.println( sizeof(gps.fix()) );
DEBUG_PORT.print( F("ubloxNMEA object size = ") );
DEBUG_PORT.println( sizeof(gps) );
DEBUG_PORT.println( F("Looking for GPS device on " GPS_PORT_NAME) );
#ifndef NMEAGPS_PARSE_PUBX_00
if (LAST_SENTENCE_IN_INTERVAL == (NMEAGPS::nmea_msg_t) ubloxNMEA::PUBX_00) {
DEBUG_PORT.println( F("ERROR! LAST_SENTENCE_IN_INTERVAL PUBX_00 not enabled!\n"
" Either change LAST_SENTENCE or enable PUBX_00") );
for(;;);
}
#endif
#ifndef NMEAGPS_PARSE_PUBX_04
if (LAST_SENTENCE_IN_INTERVAL == (NMEAGPS::nmea_msg_t) ubloxNMEA::PUBX_04) {
DEBUG_PORT.println( F("ERROR! LAST_SENTENCE_IN_INTERVAL PUBX_04 not enabled!\n"
" Either change LAST_SENTENCE or enable PUBX_04") );
for(;;);
}
#endif
trace_header( DEBUG_PORT );
DEBUG_PORT.flush();
gpsPort.begin(9600);
// Ask for the special PUBX sentences
poll();
}
//--------------------------
void loop()
{
GPSloop();
}

View File

@@ -0,0 +1,137 @@
#include <NMEAGPS.h>
//======================================================================
// Program: SyncTime.ino
//
// Description: This program shows how to update the sub-second
// part of a clock's seconds. You can adjust the clock update
// interval to be as small as 9ms. It will calculate the
// correct ms offset from each GPS second.
//
// Prerequisites:
// 1) NMEA.ino works with your device
// 2) GPS_FIX_TIME is enabled in GPSfix_cfg.h
// 3) NMEAGPS_PARSE_RMC is enabled in NMEAGPS_cfg.h. You could use
// any sentence that contains a time field. Be sure to change the
// "if" statement in GPSloop from RMC to your selected sentence.
//
// 'Serial' is for debug output to the Serial Monitor window.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <GPSport.h>
static NMEAGPS gps;
static gps_fix fix;
#if !defined(GPS_FIX_TIME)
#error You must define GPS_FIX_TIME in GPSfix_cfg.h!
#endif
#if !defined(NMEAGPS_PARSE_RMC) & \
!defined(NMEAGPS_PARSE_GLL) & \
!defined(NMEAGPS_PARSE_GGA) & \
!defined(NMEAGPS_PARSE_GST)
#error You must define NMEAGPS_PARSE_RMC, GLL, GGA or GST in NMEAGPS_cfg.h!
#endif
#if !defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL) & \
!defined(NMEAGPS_TIMESTAMP_FROM_PPS)
#error You must define NMEAGPS_TIMESTAMP_FROM_INTERVAL or PPS in NMEAGPS_cfg.h!
#endif
#if defined(NMEAGPS_TIMESTAMP_FROM_PPS)
#warning You must modify this sketch to call gps.UTCsecondStart at the PPS rising edge (see NMEAGPS.h comments).
#endif
#ifdef NMEAGPS_INTERRUPT_PROCESSING
#error You must *NOT* define NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h!
#endif
//----------------------------------------------------------------
static const uint32_t CLOCK_INTERVAL_MS = 100UL;
static uint32_t lastShowTime = CLOCK_INTERVAL_MS+1; // First time never matches
//----------------------------------------------------------------
static void showTime( uint16_t subs, uint16_t factor = 100 /* hundredths */ )
{
uint8_t showSeconds = fix.dateTime.seconds;
// Step by seconds until we're in the current UTC second
while (subs >= 1000UL) {
subs -= 1000UL;
if (showSeconds < 59)
showSeconds++;
else
showSeconds = 0;
//DEBUG_PORT.print( '+' );
}
DEBUG_PORT.print( showSeconds );
DEBUG_PORT.print( '.' );
// Leading zeroes
for (;;) {
factor /= 10;
if ((factor < 10) || (subs >= factor))
break;
DEBUG_PORT.print( '0' );
}
DEBUG_PORT.println( subs );
} // showTime
//--------------------------
void setup()
{
DEBUG_PORT.begin(9600);
while (!DEBUG_PORT)
;
DEBUG_PORT.print( F("SyncTime.INO: started\n") );
DEBUG_PORT.println( F("Looking for GPS device on " GPS_PORT_NAME) );
DEBUG_PORT.println( F("Local time seconds.milliseconds") );
DEBUG_PORT.flush();
gpsPort.begin( 9600 );
}
//--------------------------
void loop()
{
while (gps.available( gpsPort )) {
fix = gps.read();
}
if (fix.valid.time) {
uint32_t UTCms = gps.UTCms();
if (((UTCms % CLOCK_INTERVAL_MS) == 0) && (UTCms != lastShowTime)) {
showTime( UTCms, 1000 );
lastShowTime = UTCms;
}
}
}

View File

@@ -0,0 +1,198 @@
#include <NMEAGPS.h>
NMEAGPS gps;
//======================================================================
// Program: SyncTime.ino
//
// Description: This program displays all GPS fields in the default configuration
// in a tabular display. To be comparable to other libraries' tabular displays,
// you must also enable HDOP in GPSfix_cfg.h.
//
// Most NeoGPS examples display *all* configured GPS fields in a CSV format
// (e.g., NMEA.ino).
//
// Prerequisites:
// 1) NMEA.ino works with your device (correct TX/RX pins and baud rate)
// 2) GPS_FIX_HDOP is defined in GPSfix_cfg.h
//
// 'Serial' is for debug output to the Serial Monitor window.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <GPSport.h>
//-----------------
// Check configuration
#ifndef GPS_FIX_HDOP
#error You must uncomment GPS_FIX_HDOP in GPSfix_cfg.h!
#endif
//-----------------
static const NeoGPS::Location_t London( 51.508131, -0.128002 );
void setup()
{
DEBUG_PORT.begin(9600);
DEBUG_PORT.println
(
F( "Testing NeoGPS library\n\n"
"Sats HDOP Latitude Longitude Date Time Alt Speed Heading -- To London -- Chars Sentences Errors\n"
" (deg) (deg) (m) Dist Dir\n" )
);
repeat( '-', 133 );
gpsPort.begin(9600);
}
//-----------------
void loop()
{
if (gps.available( gpsPort )) {
gps_fix fix = gps.read();
float bearingToLondon = fix.location.BearingToDegrees( London );
bool validDT = fix.valid.date & fix.valid.time;
print( fix.satellites , fix.valid.satellites, 3 );
print( fix.hdop/1000.0 , fix.valid.hdop , 6, 2 );
print( fix.latitude () , fix.valid.location , 10, 6 );
print( fix.longitude() , fix.valid.location , 11, 6 );
print( fix.dateTime , validDT , 20 );
print( fix.altitude () , fix.valid.altitude , 7, 2 );
print( fix.speed_kph() , fix.valid.speed , 7, 2 );
print( fix.heading () , fix.valid.heading , 7, 2 );
print( compassDir( fix.heading () ) , fix.valid.heading , 4 );
print( fix.location.DistanceKm( London ), fix.valid.location , 5 );
print( bearingToLondon , fix.valid.location , 7, 2 );
print( compassDir( bearingToLondon ) , fix.valid.location , 4 );
print( gps.statistics.chars , true, 10 );
print( gps.statistics.ok , true, 6 );
print( gps.statistics.errors, true, 6 );
DEBUG_PORT.println();
}
}
//-----------------
// Print utilities
static void repeat( char c, int8_t len )
{
for (int8_t i=0; i<len; i++)
DEBUG_PORT.write( c );
}
static void printInvalid( int8_t len )
{
DEBUG_PORT.write( ' ' );
repeat( '*', abs(len)-1 );
}
static void print( float val, bool valid, int8_t len, int8_t prec )
{
if (!valid) {
printInvalid( len );
} else {
char s[16];
dtostrf( val, len, prec, s );
DEBUG_PORT.print( s );
}
}
static void print( int32_t val, bool valid, int8_t len )
{
if (!valid) {
printInvalid( len );
} else {
char s[16];
ltoa( val, s, 10 );
repeat( ' ', len - strlen(s) );
DEBUG_PORT.print( s );
}
}
static void print( const __FlashStringHelper *str, bool valid, int8_t len )
{
if (!valid) {
printInvalid( len );
} else {
int slen = strlen_P( (const char *) str );
repeat( ' ', len-slen );
DEBUG_PORT.print( str );
}
}
static void print( const NeoGPS::time_t & dt, bool valid, int8_t len )
{
if (!valid) {
printInvalid( len );
} else {
DEBUG_PORT.write( ' ' );
Serial << dt; // this "streaming" operator outputs date and time
}
}
//------------------------------------------------------------
// This snippet is from NMEAaverage. It keeps all the
// compass direction strings in FLASH memory, saving RAM.
const char nCD [] PROGMEM = "N";
const char nneCD[] PROGMEM = "NNE";
const char neCD [] PROGMEM = "NE";
const char eneCD[] PROGMEM = "ENE";
const char eCD [] PROGMEM = "E";
const char eseCD[] PROGMEM = "ESE";
const char seCD [] PROGMEM = "SE";
const char sseCD[] PROGMEM = "SSE";
const char sCD [] PROGMEM = "S";
const char sswCD[] PROGMEM = "SSW";
const char swCD [] PROGMEM = "SW";
const char wswCD[] PROGMEM = "WSW";
const char wCD [] PROGMEM = "W";
const char wnwCD[] PROGMEM = "WNW";
const char nwCD [] PROGMEM = "NW";
const char nnwCD[] PROGMEM = "NNW";
const char * const dirStrings[] PROGMEM =
{ nCD, nneCD, neCD, eneCD, eCD, eseCD, seCD, sseCD,
sCD, sswCD, swCD, wswCD, wCD, wnwCD, nwCD, nnwCD };
const __FlashStringHelper *compassDir( uint16_t bearing ) // degrees CW from N
{
const int16_t directions = sizeof(dirStrings)/sizeof(dirStrings[0]);
const int16_t degreesPerDir = 360 / directions;
int8_t dir = (bearing + degreesPerDir/2) / degreesPerDir;
while (dir < 0)
dir += directions;
while (dir >= directions)
dir -= directions;
return (const __FlashStringHelper *) pgm_read_ptr( &dirStrings[ dir ] );
} // compassDir

View File

@@ -0,0 +1,403 @@
#include <NeoGPS_cfg.h>
#include <ublox/ubxGPS.h>
//======================================================================
// Program: ublox.ino
//
// Prerequisites:
// 1) You have a ublox GPS device
// 2) PUBX.ino works with your device
// 3) You have installed the ubxGPS.* and ubxmsg.* files.
// 4) At least one UBX message has been enabled in ubxGPS.h.
// 5) Implicit Merging is disabled in NMEAGPS_cfg.h.
//
// Description: This program parses UBX binary protocal messages from
// ublox devices. It shows how to acquire the information necessary
// to use the GPS Time-Of-Week in many UBX messages. As an offset
// from midnight Sunday morning (GPS time), you also need the current
// UTC time (this is *not* GPS time) and the current number of GPS
// leap seconds.
//
// Serial is for debug output to the Serial Monitor window.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <GPSport.h>
#include <Streamers.h>
//------------------------------------------------------------
// Check that the config files are set up properly
#ifndef NMEAGPS_DERIVED_TYPES
#error You must "#define NMEAGPS_DERIVED_TYPES" in NMEAGPS_cfg.h!
#endif
#if !defined(UBLOX_PARSE_STATUS) & !defined(UBLOX_PARSE_TIMEGPS) & \
!defined(UBLOX_PARSE_TIMEUTC) & !defined(UBLOX_PARSE_POSLLH) & \
!defined(UBLOX_PARSE_VELNED) & !defined(UBLOX_PARSE_SVINFO) & \
!defined(UBLOX_PARSE_DOP)
#error No UBX binary messages enabled: no fix data available for fusing.
#endif
#if defined(UBLOX_PARSE_DOP) & \
( !defined(GPS_FIX_HDOP) & \
!defined(GPS_FIX_VDOP) & \
!defined(GPS_FIX_PDOP) )
#warning UBX DOP message is enabled, but all GPS_fix DOP members are disabled.
#endif
#ifndef NMEAGPS_RECOGNIZE_ALL
// Resetting the messages with ublox::configNMEA requires that
// all message types are recognized (i.e., the enum has all
// values).
#error You must "#define NMEAGPS_RECOGNIZE_ALL" in NMEAGPS_cfg.h!
#endif
//-----------------------------------------------------------------
// Derive a class to add the state machine for starting up:
// 1) The status must change to something other than NONE.
// 2) The GPS leap seconds must be received
// 3) The UTC time must be received
// 4) All configured messages are "requested"
// (i.e., "enabled" in the ublox device)
// Then, all configured messages are parsed and explicitly merged.
class MyGPS : public ubloxGPS
{
public:
enum
{
GETTING_STATUS,
GETTING_LEAP_SECONDS,
GETTING_UTC,
RUNNING
}
state NEOGPS_BF(8);
MyGPS( Stream *device ) : ubloxGPS( device )
{
state = GETTING_STATUS;
}
//--------------------------
void get_status()
{
static bool acquiring = false;
if (fix().status == gps_fix::STATUS_NONE) {
static uint32_t dotPrint;
bool requestNavStatus = false;
if (!acquiring) {
acquiring = true;
dotPrint = millis();
DEBUG_PORT.print( F("Acquiring...") );
requestNavStatus = true;
} else if (millis() - dotPrint > 1000UL) {
dotPrint = millis();
DEBUG_PORT << '.';
static uint8_t requestPeriod;
if ((++requestPeriod & 0x07) == 0)
requestNavStatus = true;
}
if (requestNavStatus)
// Turn on the UBX status message
enable_msg( ublox::UBX_NAV, ublox::UBX_NAV_STATUS );
} else {
if (acquiring)
DEBUG_PORT << '\n';
DEBUG_PORT << F("Acquired status: ") << (uint8_t) fix().status << '\n';
#if defined(GPS_FIX_TIME) & defined(GPS_FIX_DATE) & \
defined(UBLOX_PARSE_TIMEGPS)
if (!enable_msg( ublox::UBX_NAV, ublox::UBX_NAV_TIMEGPS ))
DEBUG_PORT.println( F("enable TIMEGPS failed!") );
state = GETTING_LEAP_SECONDS;
#else
start_running();
state = RUNNING;
#endif
}
} // get_status
//--------------------------
void get_leap_seconds()
{
#if defined(GPS_FIX_TIME) & defined(GPS_FIX_DATE) & \
defined(UBLOX_PARSE_TIMEGPS)
if (GPSTime::leap_seconds != 0) {
DEBUG_PORT << F("Acquired leap seconds: ") << GPSTime::leap_seconds << '\n';
if (!disable_msg( ublox::UBX_NAV, ublox::UBX_NAV_TIMEGPS ))
DEBUG_PORT.println( F("disable TIMEGPS failed!") );
#if defined(UBLOX_PARSE_TIMEUTC)
if (!enable_msg( ublox::UBX_NAV, ublox::UBX_NAV_TIMEUTC ))
DEBUG_PORT.println( F("enable TIMEUTC failed!") );
state = GETTING_UTC;
#else
start_running();
#endif
}
#endif
} // get_leap_seconds
//--------------------------
void get_utc()
{
#if defined(GPS_FIX_TIME) & defined(GPS_FIX_DATE) & \
defined(UBLOX_PARSE_TIMEUTC)
lock();
bool safe = is_safe();
NeoGPS::clock_t sow = GPSTime::start_of_week();
NeoGPS::time_t utc = fix().dateTime;
unlock();
if (safe && (sow != 0)) {
DEBUG_PORT << F("Acquired UTC: ") << utc << '\n';
DEBUG_PORT << F("Acquired Start-of-Week: ") << sow << '\n';
start_running();
}
#endif
} // get_utc
//--------------------------
void start_running()
{
bool enabled_msg_with_time = false;
#if (defined(GPS_FIX_LOCATION) | \
defined(GPS_FIX_LOCATION_DMS) | \
defined(GPS_FIX_ALTITUDE)) & \
defined(UBLOX_PARSE_POSLLH)
if (!enable_msg( ublox::UBX_NAV, ublox::UBX_NAV_POSLLH ))
DEBUG_PORT.println( F("enable POSLLH failed!") );
enabled_msg_with_time = true;
#endif
#if (defined(GPS_FIX_SPEED) | defined(GPS_FIX_HEADING)) & \
defined(UBLOX_PARSE_VELNED)
if (!enable_msg( ublox::UBX_NAV, ublox::UBX_NAV_VELNED ))
DEBUG_PORT.println( F("enable VELNED failed!") );
enabled_msg_with_time = true;
#endif
#if defined(UBLOX_PARSE_DOP)
if (!enable_msg( ublox::UBX_NAV, ublox::UBX_NAV_DOP ))
DEBUG_PORT.println( F("enable DOP failed!") );
else
DEBUG_PORT.println( F("enabled DOP.") );
enabled_msg_with_time = true;
#endif
#if (defined(GPS_FIX_SATELLITES) | defined(NMEAGPS_PARSE_SATELLITES)) & \
defined(UBLOX_PARSE_SVINFO)
if (!enable_msg( ublox::UBX_NAV, ublox::UBX_NAV_SVINFO ))
DEBUG_PORT.println( F("enable SVINFO failed!") );
enabled_msg_with_time = true;
#endif
#if defined(UBLOX_PARSE_TIMEUTC)
#if defined(GPS_FIX_TIME) & defined(GPS_FIX_DATE)
if (enabled_msg_with_time &&
!disable_msg( ublox::UBX_NAV, ublox::UBX_NAV_TIMEUTC ))
DEBUG_PORT.println( F("disable TIMEUTC failed!") );
#elif defined(GPS_FIX_TIME) | defined(GPS_FIX_DATE)
// If both aren't defined, we can't convert TOW to UTC,
// so ask for the separate UTC message.
if (!enable_msg( ublox::UBX_NAV, ublox::UBX_NAV_TIMEUTC ))
DEBUG_PORT.println( F("enable TIMEUTC failed!") );
#endif
#endif
state = RUNNING;
trace_header( DEBUG_PORT );
} // start_running
//--------------------------
bool running()
{
switch (state) {
case GETTING_STATUS : get_status (); break;
case GETTING_LEAP_SECONDS: get_leap_seconds(); break;
case GETTING_UTC : get_utc (); break;
}
return (state == RUNNING);
} // running
} NEOGPS_PACKED;
// Construct the GPS object and hook it to the appropriate serial device
static MyGPS gps( &gpsPort );
#ifdef NMEAGPS_INTERRUPT_PROCESSING
static void GPSisr( uint8_t c )
{
gps.handle( c );
}
#endif
//--------------------------
static void configNMEA( uint8_t rate )
{
for (uint8_t i=NMEAGPS::NMEA_FIRST_MSG; i<=NMEAGPS::NMEA_LAST_MSG; i++) {
ublox::configNMEA( gps, (NMEAGPS::nmea_msg_t) i, rate );
}
}
//--------------------------
static void disableUBX()
{
gps.disable_msg( ublox::UBX_NAV, ublox::UBX_NAV_TIMEGPS );
gps.disable_msg( ublox::UBX_NAV, ublox::UBX_NAV_TIMEUTC );
gps.disable_msg( ublox::UBX_NAV, ublox::UBX_NAV_VELNED );
gps.disable_msg( ublox::UBX_NAV, ublox::UBX_NAV_POSLLH );
gps.disable_msg( ublox::UBX_NAV, ublox::UBX_NAV_DOP );
}
//--------------------------
void setup()
{
// Start the normal trace output
DEBUG_PORT.begin(9600);
while (!DEBUG_PORT)
;
DEBUG_PORT.print( F("ublox binary protocol example started.\n") );
DEBUG_PORT << F("fix object size = ") << sizeof(gps.fix()) << '\n';
DEBUG_PORT << F("ubloxGPS object size = ") << sizeof(ubloxGPS) << '\n';
DEBUG_PORT << F("MyGPS object size = ") << sizeof(gps) << '\n';
DEBUG_PORT.println( F("Looking for GPS device on " GPS_PORT_NAME) );
DEBUG_PORT.flush();
// Start the UART for the GPS device
#ifdef NMEAGPS_INTERRUPT_PROCESSING
gpsPort.attachInterrupt( GPSisr );
#endif
gpsPort.begin(9600);
// Turn off the preconfigured NMEA standard messages
configNMEA( 0 );
// Turn off things that may be left on by a previous build
disableUBX();
#if 0
// Test a Neo M8 message -- should be rejected by Neo-6 and Neo7
ublox::cfg_nmea_v1_t test;
test.always_output_pos = false; // invalid or failed
test.output_invalid_pos = false;
test.output_invalid_time= false;
test.output_invalid_date= false;
test.use_GPS_only = false;
test.output_heading = false; // even if frozen
test.__not_used__ = false;
test.nmea_version = ublox::cfg_nmea_v1_t::NMEA_V_4_0;
test.num_sats_per_talker_id = ublox::cfg_nmea_v1_t::SV_PER_TALKERID_UNLIMITED;
test.compatibility_mode = false;
test.considering_mode = true;
test.max_line_length_82 = false;
test.__not_used_1__ = 0;
test.filter_gps = false;
test.filter_sbas = false;
test.__not_used_2__= 0;
test.filter_qzss = false;
test.filter_glonass= false;
test.filter_beidou = false;
test.__not_used_3__= 0;
test.proprietary_sat_numbering = false;
test.main_talker_id = ublox::cfg_nmea_v1_t::MAIN_TALKER_ID_GP;
test.gsv_uses_main_talker_id = true;
test.beidou_talker_id[0] = 'G';
test.beidou_talker_id[1] = 'P';
DEBUG_PORT << F("CFG_NMEA result = ") << gps.send( test );
#endif
while (!gps.running())
if (gps.available( gpsPort ))
gps.read();
}
//--------------------------
void loop()
{
if (gps.available( gpsPort ))
trace_all( DEBUG_PORT, gps, gps.read() );
// If the user types something, reset the message configuration
// back to a normal set of NMEA messages. This makes it
// convenient to switch to another example program that
// expects a typical set of messages. This also saves
// putting those config messages in every other example.
if (DEBUG_PORT.available()) {
do { DEBUG_PORT.read(); } while (DEBUG_PORT.available());
DEBUG_PORT.println( F("Stopping...") );
configNMEA( 1 );
disableUBX();
gpsPort.flush();
gpsPort.end();
DEBUG_PORT.println( F("STOPPED.") );
for (;;);
}
}

View File

@@ -0,0 +1,369 @@
#include <NMEAGPS.h>
#include <NeoTeeStream.h>
//======================================================================
// Program: NMEA.ino
//
// Description: This program sends ublox commands to enable and disable
// NMEA sentences, set the update rate to 1Hz, 5Hz or 10Hz, and set the
// baud rate to 9600 or 115200.
//
// Enter the following commands through the Serial Monitor window:
//
// '1' - send NMEA PUBX text command to enable all sentences
// '0' - send NMEA PUBX text command to disable all sentences except GLL
// 'd' - send UBX binary command to disable all sentences except GLL
// 'r1' - send UBX binary command to set update rate to 1Hz
// 'r5' - send UBX binary command to set update rate to 5Hz
// 'r0' - send UBX binary command to set update rate to 10Hz
// 'r6' - send UBX binary command to set update rate to 16Hz
// '5' - send NMEA PUBX text command to set baud rate to 115200
// '7' - send NMEA PUBX text command to set baud rate to 57600
// '3' - send NMEA PUBX text command to set baud rate to 38400
// '9' - send NMEA PUBX text command to set baud rate to 9600
// 'e' - toggle echo of all characters received from GPS device.
//
// CAUTION: If your Serial Monitor window baud rate is less than the GPS baud
// rate, turning echo ON will cause the sketch to lose some or all
// GPS data and/or fixes.
//
// NOTE: All NMEA PUBX text commands are also echoed to the debug port.
//
// Prerequisites:
// 1) Your GPS device has been correctly powered.
// Be careful when connecting 3.3V devices.
// 2) Your GPS device is correctly connected to an Arduino serial port.
// See GPSport.h for the default connections.
// 3) You know the default baud rate of your GPS device.
// If 9600 does not work, use NMEAdiagnostic.ino to
// scan for the correct baud rate.
// 4) LAST_SENTENCE_IN_INTERVAL is defined to be the following in NMEAGPS_cfg.h:
//
// #include <stdint.h>
// extern uint8_t LastSentenceInInterval; // a variable!
// #define LAST_SENTENCE_IN_INTERVAL \
// ((NMEAGPS::nmea_msg_t) LastSentenceInInterval)
//
// This is a replacement for the typical
//
// #define LAST_SENTENCE_IN_INTERVAL NMEAGPS::NMEA_GLL
//
// This allows the sketch to choose the last sentence *at run time*, not
// compile time. This is necessary because this sketch can send
// configuration commands that change which sentences are enabled at run
// time. The storage for the "externed" variable is below.
//
// 'Serial' is for debug output to the Serial Monitor window.
//
// License:
// Copyright (C) 2014-2017, SlashDevin
//
// This file is part of NeoGPS
//
// NeoGPS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// NeoGPS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with NeoGPS. If not, see <http://www.gnu.org/licenses/>.
//
//======================================================================
#include <GPSport.h>
#include <Streamers.h>
static NMEAGPS gps;
static gps_fix fix_data;
uint8_t LastSentenceInInterval = 0xFF; // storage for the run-time selection
static char lastChar; // last command char
static bool echoing = false;
// Use NeoTee to echo the NMEA text commands to the Serial Monitor window
Stream *both[2] = { &DEBUG_PORT, &gpsPort };
NeoTeeStream tee( both, sizeof(both)/sizeof(both[0]) );
//-------------------------------------------
// U-blox UBX binary commands
const unsigned char ubxRate1Hz[] PROGMEM =
{ 0x06,0x08,0x06,0x00,0xE8,0x03,0x01,0x00,0x01,0x00 };
const unsigned char ubxRate5Hz[] PROGMEM =
{ 0x06,0x08,0x06,0x00,200,0x00,0x01,0x00,0x01,0x00 };
const unsigned char ubxRate10Hz[] PROGMEM =
{ 0x06,0x08,0x06,0x00,100,0x00,0x01,0x00,0x01,0x00 };
const unsigned char ubxRate16Hz[] PROGMEM =
{ 0x06,0x08,0x06,0x00,50,0x00,0x01,0x00,0x01,0x00 };
// Disable specific NMEA sentences
const unsigned char ubxDisableGGA[] PROGMEM =
{ 0x06,0x01,0x08,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableGLL[] PROGMEM =
{ 0x06,0x01,0x08,0x00,0xF0,0x01,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableGSA[] PROGMEM =
{ 0x06,0x01,0x08,0x00,0xF0,0x02,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableGSV[] PROGMEM =
{ 0x06,0x01,0x08,0x00,0xF0,0x03,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableRMC[] PROGMEM =
{ 0x06,0x01,0x08,0x00,0xF0,0x04,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableVTG[] PROGMEM =
{ 0x06,0x01,0x08,0x00,0xF0,0x05,0x00,0x00,0x00,0x00,0x00,0x01 };
const unsigned char ubxDisableZDA[] PROGMEM =
{ 0x06,0x01,0x08,0x00,0xF0,0x08,0x00,0x00,0x00,0x00,0x00,0x01 };
//--------------------------
void sendUBX( const unsigned char *progmemBytes, size_t len )
{
gpsPort.write( 0xB5 ); // SYNC1
gpsPort.write( 0x62 ); // SYNC2
uint8_t a = 0, b = 0;
while (len-- > 0) {
uint8_t c = pgm_read_byte( progmemBytes++ );
a += c;
b += a;
gpsPort.write( c );
}
gpsPort.write( a ); // CHECKSUM A
gpsPort.write( b ); // CHECKSUM B
} // sendUBX
//-------------------------------------------
// U-blox NMEA text commands
const char disableRMC[] PROGMEM = "PUBX,40,RMC,0,0,0,0,0,0";
const char disableGLL[] PROGMEM = "PUBX,40,GLL,0,0,0,0,0,0";
const char disableGSV[] PROGMEM = "PUBX,40,GSV,0,0,0,0,0,0";
const char disableGSA[] PROGMEM = "PUBX,40,GSA,0,0,0,0,0,0";
const char disableGGA[] PROGMEM = "PUBX,40,GGA,0,0,0,0,0,0";
const char disableVTG[] PROGMEM = "PUBX,40,VTG,0,0,0,0,0,0";
const char disableZDA[] PROGMEM = "PUBX,40,ZDA,0,0,0,0,0,0";
const char enableRMC[] PROGMEM = "PUBX,40,RMC,0,1,0,0,0,0";
const char enableGLL[] PROGMEM = "PUBX,40,GLL,0,1,0,0,0,0";
const char enableGSV[] PROGMEM = "PUBX,40,GSV,0,1,0,0,0,0";
const char enableGSA[] PROGMEM = "PUBX,40,GSA,0,1,0,0,0,0";
const char enableGGA[] PROGMEM = "PUBX,40,GGA,0,1,0,0,0,0";
const char enableVTG[] PROGMEM = "PUBX,40,VTG,0,1,0,0,0,0";
const char enableZDA[] PROGMEM = "PUBX,40,ZDA,0,1,0,0,0,0";
const char baud9600 [] PROGMEM = "PUBX,41,1,3,3,9600,0";
const char baud38400 [] PROGMEM = "PUBX,41,1,3,3,38400,0";
const char baud57600 [] PROGMEM = "PUBX,41,1,3,3,57600,0";
const char baud115200[] PROGMEM = "PUBX,41,1,3,3,115200,0";
//--------------------------
const uint32_t COMMAND_DELAY = 250;
void changeBaud( const char *textCommand, unsigned long baud )
{
gps.send_P( &tee, (const __FlashStringHelper *) disableRMC );
delay( COMMAND_DELAY );
// gps.send_P( &tee, (const __FlashStringHelper *) disableGLL );
// delay( COMMAND_DELAY );
gps.send_P( &tee, (const __FlashStringHelper *) disableGSV );
delay( COMMAND_DELAY );
gps.send_P( &tee, (const __FlashStringHelper *) disableGSA );
delay( COMMAND_DELAY );
gps.send_P( &tee, (const __FlashStringHelper *) disableGGA );
delay( COMMAND_DELAY );
gps.send_P( &tee, (const __FlashStringHelper *) disableVTG );
delay( COMMAND_DELAY );
gps.send_P( &tee, (const __FlashStringHelper *) disableZDA );
delay( 500 );
gps.send_P( &tee, (const __FlashStringHelper *) textCommand );
gpsPort.flush();
gpsPort.end();
DEBUG_PORT.print( F("All sentences disabled for baud rate ") );
DEBUG_PORT.print( baud );
DEBUG_PORT.println( F(" change. Enter '1' to reenable sentences.") );
delay( 500 );
gpsPort.begin( baud );
} // changeBaud
//------------------------------------
static void doSomeWork()
{
// Print all the things!
trace_all( DEBUG_PORT, gps, fix_data );
} // doSomeWork
//--------------------------
void setup()
{
DEBUG_PORT.begin(9600);
while (!DEBUG_PORT)
;
DEBUG_PORT.print( F("ubloxRate.INO: started\n") );
DEBUG_PORT.println( F("Looking for GPS device on " GPS_PORT_NAME) );
#ifdef NMEAGPS_INTERRUPT_PROCESSING
#error You must *NOT* define NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h!
#endif
#if !defined( NMEAGPS_PARSE_GGA ) & !defined( NMEAGPS_PARSE_GLL ) & \
!defined( NMEAGPS_PARSE_GSA ) & !defined( NMEAGPS_PARSE_GSV ) & \
!defined( NMEAGPS_PARSE_RMC ) & !defined( NMEAGPS_PARSE_VTG ) & \
!defined( NMEAGPS_PARSE_ZDA ) & !defined( NMEAGPS_PARSE_GST )
DEBUG_PORT.println( F("\nWARNING: No NMEA sentences are enabled: no fix data will be displayed.") );
#else
if (gps.merging == NMEAGPS::NO_MERGING) {
DEBUG_PORT.print ( F("\nWARNING: displaying data from ") );
DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) );
DEBUG_PORT.print ( F(" sentences ONLY, and only if ") );
DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) );
DEBUG_PORT.println( F(" is enabled.\n"
" Other sentences may be parsed, but their data will not be displayed.") );
}
#endif
if (LastSentenceInInterval != LAST_SENTENCE_IN_INTERVAL) {
DEBUG_PORT.println(
F("LAST_SENTENCE_IN_INTERVAL is not properly defined in NMEAGPS_cfg.h!\n"
" See Prerequisite 4 above") );
}
LastSentenceInInterval = NMEAGPS::NMEA_GLL;
trace_header( DEBUG_PORT );
DEBUG_PORT.flush();
gpsPort.begin( 9600 );
}
void loop()
{
// Check for commands
if (DEBUG_PORT.available()) {
char c = DEBUG_PORT.read();
switch (c) {
case '0':
if (lastChar == 'r') {
sendUBX( ubxRate10Hz, sizeof(ubxRate10Hz) );
} else {
gps.send_P( &tee, (const __FlashStringHelper *) disableRMC );
delay( COMMAND_DELAY );
gps.send_P( &tee, (const __FlashStringHelper *) enableGLL );
delay( COMMAND_DELAY );
gps.send_P( &tee, (const __FlashStringHelper *) disableGSV );
delay( COMMAND_DELAY );
gps.send_P( &tee, (const __FlashStringHelper *) disableGSA );
delay( COMMAND_DELAY );
gps.send_P( &tee, (const __FlashStringHelper *) disableGGA );
delay( COMMAND_DELAY );
gps.send_P( &tee, (const __FlashStringHelper *) disableVTG );
delay( COMMAND_DELAY );
gps.send_P( &tee, (const __FlashStringHelper *) disableZDA );
LastSentenceInInterval = NMEAGPS::NMEA_GLL;
}
break;
case '1':
if (lastChar == 'r') {
sendUBX( ubxRate1Hz, sizeof(ubxRate1Hz) );
} else {
gps.send_P( &tee, (const __FlashStringHelper *) enableRMC );
delay( COMMAND_DELAY );
gps.send_P( &tee, (const __FlashStringHelper *) enableGLL );
delay( COMMAND_DELAY );
gps.send_P( &tee, (const __FlashStringHelper *) enableGSV );
delay( COMMAND_DELAY );
gps.send_P( &tee, (const __FlashStringHelper *) enableGSA );
delay( COMMAND_DELAY );
gps.send_P( &tee, (const __FlashStringHelper *) enableGGA );
delay( COMMAND_DELAY );
gps.send_P( &tee, (const __FlashStringHelper *) enableVTG );
delay( COMMAND_DELAY );
gps.send_P( &tee, (const __FlashStringHelper *) enableZDA );
LastSentenceInInterval = NMEAGPS::NMEA_ZDA;
}
break;
case '3':
changeBaud( baud38400, 38400UL );
break;
case '5':
if (lastChar == 'r') {
sendUBX( ubxRate5Hz, sizeof(ubxRate5Hz) );
} else
changeBaud( baud115200, 115200UL );
break;
case '6':
if (lastChar == 'r') {
sendUBX( ubxRate16Hz, sizeof(ubxRate16Hz) );
}
break;
case '7':
changeBaud( baud57600, 57600UL );
break;
case '9':
changeBaud( baud9600, 9600UL );
break;
case 'd':
sendUBX( ubxDisableRMC, sizeof(ubxDisableRMC) );
delay( COMMAND_DELAY );
//sendUBX( ubxDisableGLL, sizeof(ubxDisableGLL) );
sendUBX( ubxDisableGSV, sizeof(ubxDisableGSV) );
delay( COMMAND_DELAY );
sendUBX( ubxDisableGSA, sizeof(ubxDisableGSA) );
delay( COMMAND_DELAY );
sendUBX( ubxDisableGGA, sizeof(ubxDisableGGA) );
delay( COMMAND_DELAY );
sendUBX( ubxDisableVTG, sizeof(ubxDisableVTG) );
delay( COMMAND_DELAY );
sendUBX( ubxDisableZDA, sizeof(ubxDisableZDA) );
LastSentenceInInterval = NMEAGPS::NMEA_GLL;
break;
case 'e':
echoing = !echoing;
break;
default: break;
}
lastChar = c;
}
// Check for GPS data
if (echoing) {
// Use advanced character-oriented methods to echo received characters to
// the Serial Monitor window.
if (gpsPort.available()) {
char c = gpsPort.read();
DEBUG_PORT.write( c );
gps.handle( c );
if (gps.available()) {
fix_data = gps.read();
doSomeWork();
}
}
} else {
// Use the normal fix-oriented methods to display fixes
if (gps.available( gpsPort )) {
fix_data = gps.read();
doSomeWork();
}
}
}