mirror of
https://github.com/OSURoboticsClub/Rover_2017_2018.git
synced 2025-11-09 02:31:14 +00:00
Added non-final versions of iris and tower firmware.
This commit is contained in:
168
software/firmware/libraries/NeoGPS/examples/NMEA/NMEA.ino
Normal file
168
software/firmware/libraries/NeoGPS/examples/NMEA/NMEA.ino
Normal 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();
|
||||
}
|
||||
107
software/firmware/libraries/NeoGPS/examples/NMEAGSV/NMEAGSV.ino
Normal file
107
software/firmware/libraries/NeoGPS/examples/NMEAGSV/NMEAGSV.ino
Normal 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
|
||||
@@ -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
|
||||
@@ -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!") );
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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() {}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
183
software/firmware/libraries/NeoGPS/examples/NMEAloc/NMEAloc.ino
Normal file
183
software/firmware/libraries/NeoGPS/examples/NMEAloc/NMEAloc.ino
Normal 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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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!
|
||||
}
|
||||
}
|
||||
@@ -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() );
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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 (;;);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
156
software/firmware/libraries/NeoGPS/examples/PUBX/PUBX.ino
Normal file
156
software/firmware/libraries/NeoGPS/examples/PUBX/PUBX.ino
Normal 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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
198
software/firmware/libraries/NeoGPS/examples/Tabular/Tabular.ino
Normal file
198
software/firmware/libraries/NeoGPS/examples/Tabular/Tabular.ino
Normal 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
|
||||
403
software/firmware/libraries/NeoGPS/examples/ublox/ublox.ino
Normal file
403
software/firmware/libraries/NeoGPS/examples/ublox/ublox.ino
Normal 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 (;;);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user