mirror of
https://github.com/OSURoboticsClub/Rover_2017_2018.git
synced 2025-11-09 10:41:15 +00:00
Added non-final versions of iris and tower firmware.
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
#ifndef GPS_FIX_CFG
|
||||
#define GPS_FIX_CFG
|
||||
|
||||
/**
|
||||
* Enable/disable the storage for the members of a fix.
|
||||
*
|
||||
* Disabling a member prevents it from being parsed from a received message.
|
||||
* The disabled member cannot be accessed or stored, and its validity flag
|
||||
* would not be available. It will not be declared, and code that uses that
|
||||
* member will not compile.
|
||||
*
|
||||
* DATE and TIME are somewhat coupled in that they share a single `time_t`,
|
||||
* but they have separate validity flags.
|
||||
*
|
||||
* See also note regarding the DOP members, below.
|
||||
*
|
||||
*/
|
||||
|
||||
#define GPS_FIX_DATE
|
||||
#define GPS_FIX_TIME
|
||||
#define GPS_FIX_LOCATION
|
||||
//#define GPS_FIX_LOCATION_DMS
|
||||
//#define GPS_FIX_ALTITUDE
|
||||
//#define GPS_FIX_SPEED
|
||||
//#define GPS_FIX_HEADING
|
||||
//#define GPS_FIX_SATELLITES
|
||||
//#define GPS_FIX_HDOP
|
||||
//#define GPS_FIX_VDOP
|
||||
//#define GPS_FIX_PDOP
|
||||
//#define GPS_FIX_LAT_ERR
|
||||
//#define GPS_FIX_LON_ERR
|
||||
//#define GPS_FIX_ALT_ERR
|
||||
//#define GPS_FIX_GEOID_HEIGHT
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,286 @@
|
||||
#ifndef NMEAGPS_CFG_H
|
||||
#define NMEAGPS_CFG_H
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable the parsing of specific sentences.
|
||||
//
|
||||
// Configuring out a sentence prevents it from being recognized; it
|
||||
// will be completely ignored. (See also NMEAGPS_RECOGNIZE_ALL, below)
|
||||
//
|
||||
// FYI: Only RMC and ZDA contain date information. Other
|
||||
// sentences contain time information. Both date and time are
|
||||
// required if you will be doing time_t-to-clock_t operations.
|
||||
|
||||
//#define NMEAGPS_PARSE_GGA
|
||||
//#define NMEAGPS_PARSE_GLL
|
||||
//#define NMEAGPS_PARSE_GSA
|
||||
//#define NMEAGPS_PARSE_GSV
|
||||
//#define NMEAGPS_PARSE_GST
|
||||
#define NMEAGPS_PARSE_RMC
|
||||
//#define NMEAGPS_PARSE_VTG
|
||||
//#define NMEAGPS_PARSE_ZDA
|
||||
|
||||
//------------------------------------------------------
|
||||
// Select which sentence is sent *last* by your GPS device
|
||||
// in each update interval. This can be used by your sketch
|
||||
// to determine when the GPS quiet time begins, and thus
|
||||
// when you can perform "some" time-consuming operations.
|
||||
|
||||
#define LAST_SENTENCE_IN_INTERVAL NMEAGPS::NMEA_RMC
|
||||
|
||||
// If the NMEA_LAST_SENTENCE_IN_INTERVAL is not chosen
|
||||
// correctly, GPS data may be lost because the sketch
|
||||
// takes too long elsewhere when this sentence is received.
|
||||
// Also, fix members may contain information from different
|
||||
// time intervals (i.e., they are not coherent).
|
||||
//
|
||||
// If you don't know which sentence is the last one,
|
||||
// use NMEAorder.ino to list them. You do not have to select
|
||||
// the last sentence the device sends if you have disabled
|
||||
// it. Just select the last sentence that you have *enabled*.
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/Disable coherency:
|
||||
//
|
||||
// If you need each fix to contain information that is only
|
||||
// from the current update interval, you should uncomment
|
||||
// this define. At the beginning of the next interval,
|
||||
// the accumulating fix will start out empty. When
|
||||
// the LAST_SENTENCE_IN_INTERVAL arrives, the valid
|
||||
// fields will be coherent.
|
||||
|
||||
//#define NMEAGPS_COHERENT
|
||||
|
||||
// With IMPLICIT merging, fix() will be emptied when the
|
||||
// next sentence begins.
|
||||
//
|
||||
// With EXPLICIT or NO merging, the fix() was already
|
||||
// being initialized.
|
||||
//
|
||||
// If you use the fix-oriented methods available() and read(),
|
||||
// they will empty the current fix for you automatically.
|
||||
//
|
||||
// If you use the character-oriented method decode(), you should
|
||||
// empty the accumulating fix by testing and clearing the
|
||||
// 'intervalComplete' flag in the same way that available() does.
|
||||
|
||||
//------------------------------------------------------
|
||||
// Choose how multiple sentences are merged:
|
||||
// 1) No merging
|
||||
// Each sentence fills out its own fix; there could be
|
||||
// multiple sentences per interval.
|
||||
// 2) EXPLICIT_MERGING
|
||||
// All sentences in an interval are *safely* merged into one fix.
|
||||
// NMEAGPS_FIX_MAX must be >= 1.
|
||||
// An interval is defined by NMEA_LAST_SENTENCE_IN_INTERVAL.
|
||||
// 3) IMPLICIT_MERGING
|
||||
// All sentences in an interval are merged into one fix, with
|
||||
// possible data loss. If a received sentence is rejected for
|
||||
// any reason (e.g., a checksum error), all the values are suspect.
|
||||
// The fix will be cleared; no members will be valid until new
|
||||
// sentences are received and accepted. This uses less RAM.
|
||||
// An interval is defined by NMEA_LAST_SENTENCE_IN_INTERVAL.
|
||||
// Uncomment zero or one:
|
||||
|
||||
#define NMEAGPS_EXPLICIT_MERGING
|
||||
//#define NMEAGPS_IMPLICIT_MERGING
|
||||
|
||||
#ifdef NMEAGPS_IMPLICIT_MERGING
|
||||
#define NMEAGPS_MERGING NMEAGPS::IMPLICIT_MERGING
|
||||
|
||||
// When accumulating, nothing is done to the fix at the
|
||||
// beginning of every sentence...
|
||||
#ifdef NMEAGPS_COHERENT
|
||||
// ...unless COHERENT is enabled and a new interval is starting
|
||||
#define NMEAGPS_INIT_FIX(m) \
|
||||
if (intervalComplete()) { intervalComplete( false ); m.valid.init(); }
|
||||
#else
|
||||
#define NMEAGPS_INIT_FIX(m)
|
||||
#endif
|
||||
|
||||
// ...but we invalidate one part when it starts to get parsed. It *may* get
|
||||
// validated when the parsing is finished.
|
||||
#define NMEAGPS_INVALIDATE(m) m_fix.valid.m = false
|
||||
|
||||
#else
|
||||
|
||||
#ifdef NMEAGPS_EXPLICIT_MERGING
|
||||
#define NMEAGPS_MERGING NMEAGPS::EXPLICIT_MERGING
|
||||
#else
|
||||
#define NMEAGPS_MERGING NMEAGPS::NO_MERGING
|
||||
#define NMEAGPS_NO_MERGING
|
||||
#endif
|
||||
|
||||
// When NOT accumulating, invalidate the entire fix at the
|
||||
// beginning of every sentence
|
||||
#define NMEAGPS_INIT_FIX(m) m.valid.init()
|
||||
|
||||
// ...so the individual parts do not need to be invalidated as they are parsed
|
||||
#define NMEAGPS_INVALIDATE(m)
|
||||
|
||||
#endif
|
||||
|
||||
#if ( defined(NMEAGPS_NO_MERGING) + \
|
||||
defined(NMEAGPS_IMPLICIT_MERGING) + \
|
||||
defined(NMEAGPS_EXPLICIT_MERGING) ) > 1
|
||||
#error Only one MERGING technique should be enabled in NMEAGPS_cfg.h!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Define the fix buffer size. The NMEAGPS object will hold on to
|
||||
// this many fixes before an overrun occurs. This can be zero,
|
||||
// but you have to be more careful about using gps.fix() structure,
|
||||
// because it will be modified as characters are received.
|
||||
|
||||
#define NMEAGPS_FIX_MAX 1
|
||||
|
||||
#if defined(NMEAGPS_EXPLICIT_MERGING) && (NMEAGPS_FIX_MAX == 0)
|
||||
#error You must define FIX_MAX >= 1 to allow EXPLICIT merging in NMEAGPS_cfg.h
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/Disable interrupt-style processing of GPS characters
|
||||
// If you are using one of the NeoXXSerial libraries,
|
||||
// to attachInterrupt, this must be defined.
|
||||
// Otherwise, it must be commented out.
|
||||
|
||||
//#define NMEAGPS_INTERRUPT_PROCESSING
|
||||
|
||||
#ifdef NMEAGPS_INTERRUPT_PROCESSING
|
||||
#define NMEAGPS_PROCESSING_STYLE NMEAGPS::PS_INTERRUPT
|
||||
#else
|
||||
#define NMEAGPS_PROCESSING_STYLE NMEAGPS::PS_POLLING
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable the talker ID, manufacturer ID and proprietary message processing.
|
||||
//
|
||||
// First, some background information. There are two kinds of NMEA sentences:
|
||||
//
|
||||
// 1. Standard NMEA sentences begin with "$ttccc", where
|
||||
// "tt" is the talker ID, and
|
||||
// "ccc" is the variable-length sentence type (i.e., command).
|
||||
//
|
||||
// For example, "$GPGLL,..." is a GLL sentence (Geographic Lat/Long)
|
||||
// transmitted by talker "GP". This is the most common talker ID. Some
|
||||
// devices may report "$GNGLL,..." when a mix of GPS and non-GPS
|
||||
// satellites have been used to determine the GLL data.
|
||||
//
|
||||
// 2. Proprietary NMEA sentences (i.e., those unique to a particular
|
||||
// manufacturer) begin with "$Pmmmccc", where
|
||||
// "P" is the NMEA-defined prefix indicator for proprietary messages,
|
||||
// "mmm" is the 3-character manufacturer ID, and
|
||||
// "ccc" is the variable-length sentence type (it can be empty).
|
||||
//
|
||||
// No validation of manufacturer ID and talker ID is performed in this
|
||||
// base class. For example, although "GP" is a common talker ID, it is not
|
||||
// guaranteed to be transmitted by your particular device, and it IS NOT
|
||||
// REQUIRED. If you need validation of these IDs, or you need to use the
|
||||
// extra information provided by some devices, you have two independent
|
||||
// options:
|
||||
//
|
||||
// 1. Enable SAVING the ID: When /decode/ returns DECODE_COMPLETED, the
|
||||
// /talker_id/ and/or /mfr_id/ members will contain ID bytes. The entire
|
||||
// sentence will be parsed, perhaps modifying members of /fix/. You should
|
||||
// enable one or both IDs if you want the information in all sentences *and*
|
||||
// you also want to know the ID bytes. This adds two bytes of RAM for the
|
||||
// talker ID, and 3 bytes of RAM for the manufacturer ID.
|
||||
//
|
||||
// 2. Enable PARSING the ID: The virtual /parse_talker_id/ and
|
||||
// /parse_mfr_id/ will receive each ID character as it is parsed. If it
|
||||
// is not a valid ID, return /false/ to abort processing the rest of the
|
||||
// sentence. No CPU time will be wasted on the invalid sentence, and no
|
||||
// /fix/ members will be modified. You should enable this if you want to
|
||||
// ignore some IDs. You must override /parse_talker_id/ and/or
|
||||
// /parse_mfr_id/ in a derived class.
|
||||
//
|
||||
|
||||
//#define NMEAGPS_SAVE_TALKER_ID
|
||||
//#define NMEAGPS_PARSE_TALKER_ID
|
||||
|
||||
//#define NMEAGPS_PARSE_PROPRIETARY
|
||||
#ifdef NMEAGPS_PARSE_PROPRIETARY
|
||||
//#define NMEAGPS_SAVE_MFR_ID
|
||||
#define NMEAGPS_PARSE_MFR_ID
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable tracking the current satellite array and,
|
||||
// optionally, all the info for each satellite.
|
||||
//
|
||||
|
||||
//#define NMEAGPS_PARSE_SATELLITES
|
||||
//#define NMEAGPS_PARSE_SATELLITE_INFO
|
||||
|
||||
#ifdef NMEAGPS_PARSE_SATELLITES
|
||||
#define NMEAGPS_MAX_SATELLITES (20)
|
||||
|
||||
#ifndef GPS_FIX_SATELLITES
|
||||
#error GPS_FIX_SATELLITES must be defined in GPSfix.h!
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(NMEAGPS_PARSE_SATELLITE_INFO) & \
|
||||
!defined(NMEAGPS_PARSE_SATELLITES)
|
||||
#error NMEAGPS_PARSE_SATELLITES must be defined!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable gathering interface statistics:
|
||||
// CRC errors and number of sentences received
|
||||
|
||||
#define NMEAGPS_STATS
|
||||
|
||||
//------------------------------------------------------
|
||||
// Configuration item for allowing derived types of NMEAGPS.
|
||||
// If you derive classes from NMEAGPS, you *must* define NMEAGPS_DERIVED_TYPES.
|
||||
// If not defined, virtuals are not used, with a slight size (2 bytes) and
|
||||
// execution time savings.
|
||||
|
||||
//#define NMEAGPS_DERIVED_TYPES
|
||||
|
||||
#ifdef NMEAGPS_DERIVED_TYPES
|
||||
#define NMEAGPS_VIRTUAL virtual
|
||||
#else
|
||||
#define NMEAGPS_VIRTUAL
|
||||
#endif
|
||||
|
||||
//-----------------------------------
|
||||
// See if DERIVED_TYPES is required
|
||||
#if (defined(NMEAGPS_PARSE_TALKER_ID) | defined(NMEAGPS_PARSE_MFR_ID)) & \
|
||||
!defined(NMEAGPS_DERIVED_TYPES)
|
||||
#error You must define NMEAGPS_DERIVED_TYPES in NMEAGPS.h in order to parse Talker and/or Mfr IDs!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Some devices may omit trailing commas at the end of some
|
||||
// sentences. This may prevent the last field from being
|
||||
// parsed correctly, because the parser for some types keep
|
||||
// the value in an intermediate state until the complete
|
||||
// field is received (e.g., parseDDDMM, parseFloat and
|
||||
// parseZDA).
|
||||
//
|
||||
// Enabling this will inject a simulated comma when the end
|
||||
// of a sentence is received and the last field parser
|
||||
// indicated that it still needs one.
|
||||
|
||||
//#define NMEAGPS_COMMA_NEEDED
|
||||
|
||||
//------------------------------------------------------
|
||||
// Some applications may want to recognize a sentence type
|
||||
// without actually parsing any of the fields. Uncommenting
|
||||
// this define will allow the nmeaMessage member to be set
|
||||
// when *any* standard message is seen, even though that
|
||||
// message is not enabled by a NMEAGPS_PARSE_xxx define above.
|
||||
// No valid flags will be true for those sentences.
|
||||
|
||||
#define NMEAGPS_RECOGNIZE_ALL
|
||||
|
||||
//------------------------------------------------------
|
||||
// Sometimes, a little extra space is needed to parse an intermediate form.
|
||||
// This config items enables extra space.
|
||||
|
||||
//#define NMEAGPS_PARSING_SCRATCHPAD
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
#ifndef NEOGPS_CFG
|
||||
#define NEOGPS_CFG
|
||||
|
||||
/**
|
||||
* Enable/disable packed data structures.
|
||||
*
|
||||
* Enabling packed data structures will use two less-portable language
|
||||
* features of GCC to reduce RAM requirements. Although it was expected to slightly increase execution time and code size, the reverse is true on 8-bit AVRs: the code is smaller and faster with packing enabled.
|
||||
*
|
||||
* Disabling packed data structures will be very portable to other
|
||||
* platforms. NeoGPS configurations will use slightly more RAM, and on
|
||||
* 8-bit AVRs, the speed is slightly slower, and the code is slightly
|
||||
* larger. There may be no choice but to disable packing on processors
|
||||
* that do not support packed structures.
|
||||
*
|
||||
* There may also be compiler-specific switches that affect packing and the
|
||||
* code which accesses packed members. YMMV.
|
||||
**/
|
||||
|
||||
#ifdef __AVR__
|
||||
#define NEOGPS_PACKED_DATA
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Based on the above define, choose which set of packing macros should
|
||||
// be used in the rest of the NeoGPS package. Do not change these defines.
|
||||
|
||||
#ifdef NEOGPS_PACKED_DATA
|
||||
|
||||
// This is for specifying the number of bits to be used for a
|
||||
// member of a struct. Booleans are typically one bit.
|
||||
#define NEOGPS_BF(b) :b
|
||||
|
||||
// This is for requesting the compiler to pack the struct or class members
|
||||
// "as closely as possible". This is a compiler-dependent interpretation.
|
||||
#define NEOGPS_PACKED __attribute__((packed))
|
||||
|
||||
#else
|
||||
|
||||
// Let the compiler do whatever it wants.
|
||||
|
||||
#define NEOGPS_PACKED
|
||||
#define NEOGPS_BF(b)
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Accommodate C++ compiler and IDE changes.
|
||||
*
|
||||
* Declaring constants as class data instead of instance data helps avoid
|
||||
* collisions with #define names, and allows the compiler to perform more
|
||||
* checks on their usage.
|
||||
*
|
||||
* Until C++ 10 and IDE 1.6.8, initialized class data constants
|
||||
* were declared like this:
|
||||
*
|
||||
* static const <valued types> = <constant-value>;
|
||||
*
|
||||
* Now, non-simple types (e.g., float) must be declared as
|
||||
*
|
||||
* static constexpr <nonsimple-types> = <expression-treated-as-const>;
|
||||
*
|
||||
* The good news is that this allows the compiler to optimize out an
|
||||
* expression that is "promised" to be "evaluatable" as a constant.
|
||||
* The bad news is that it introduces a new language keyword, and the old
|
||||
* code raises an error.
|
||||
*
|
||||
* TODO: Evaluate the requirement for the "static" keyword.
|
||||
* TODO: Evaluate using a C++ version preprocessor symbol for the #if.
|
||||
*
|
||||
* The CONST_CLASS_DATA define will expand to the appropriate keywords.
|
||||
*
|
||||
*/
|
||||
|
||||
#if ARDUINO < 10606
|
||||
|
||||
#define CONST_CLASS_DATA static const
|
||||
|
||||
#else
|
||||
|
||||
#define CONST_CLASS_DATA static constexpr
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef GPS_FIX_CFG
|
||||
#define GPS_FIX_CFG
|
||||
|
||||
/**
|
||||
* Enable/disable the storage for the members of a fix.
|
||||
*
|
||||
* Disabling a member prevents it from being parsed from a received message.
|
||||
* The disabled member cannot be accessed or stored, and its validity flag
|
||||
* would not be available. It will not be declared, and code that uses that
|
||||
* member will not compile.
|
||||
*
|
||||
* DATE and TIME are somewhat coupled in that they share a single `time_t`,
|
||||
* but they have separate validity flags.
|
||||
*
|
||||
* See also note regarding the DOP members, below.
|
||||
*
|
||||
*/
|
||||
|
||||
#define GPS_FIX_DATE
|
||||
#define GPS_FIX_TIME
|
||||
#define GPS_FIX_LOCATION
|
||||
#define GPS_FIX_LOCATION_DMS
|
||||
#define GPS_FIX_ALTITUDE
|
||||
#define GPS_FIX_SPEED
|
||||
#define GPS_FIX_HEADING
|
||||
#define GPS_FIX_SATELLITES
|
||||
#define GPS_FIX_HDOP
|
||||
#define GPS_FIX_VDOP
|
||||
#define GPS_FIX_PDOP
|
||||
#define GPS_FIX_LAT_ERR
|
||||
#define GPS_FIX_LON_ERR
|
||||
#define GPS_FIX_ALT_ERR
|
||||
#define GPS_FIX_GEOID_HEIGHT
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,286 @@
|
||||
#ifndef NMEAGPS_CFG_H
|
||||
#define NMEAGPS_CFG_H
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable the parsing of specific sentences.
|
||||
//
|
||||
// Configuring out a sentence prevents it from being recognized; it
|
||||
// will be completely ignored. (See also NMEAGPS_RECOGNIZE_ALL, below)
|
||||
//
|
||||
// FYI: Only RMC and ZDA contain date information. Other
|
||||
// sentences contain time information. Both date and time are
|
||||
// required if you will be doing time_t-to-clock_t operations.
|
||||
|
||||
#define NMEAGPS_PARSE_GGA
|
||||
#define NMEAGPS_PARSE_GLL
|
||||
#define NMEAGPS_PARSE_GSA
|
||||
#define NMEAGPS_PARSE_GSV
|
||||
#define NMEAGPS_PARSE_GST
|
||||
#define NMEAGPS_PARSE_RMC
|
||||
#define NMEAGPS_PARSE_VTG
|
||||
#define NMEAGPS_PARSE_ZDA
|
||||
|
||||
//------------------------------------------------------
|
||||
// Select which sentence is sent *last* by your GPS device
|
||||
// in each update interval. This can be used by your sketch
|
||||
// to determine when the GPS quiet time begins, and thus
|
||||
// when you can perform "some" time-consuming operations.
|
||||
|
||||
#define LAST_SENTENCE_IN_INTERVAL NMEAGPS::NMEA_RMC
|
||||
|
||||
// If the NMEA_LAST_SENTENCE_IN_INTERVAL is not chosen
|
||||
// correctly, GPS data may be lost because the sketch
|
||||
// takes too long elsewhere when this sentence is received.
|
||||
// Also, fix members may contain information from different
|
||||
// time intervals (i.e., they are not coherent).
|
||||
//
|
||||
// If you don't know which sentence is the last one,
|
||||
// use NMEAorder.ino to list them. You do not have to select
|
||||
// the last sentence the device sends if you have disabled
|
||||
// it. Just select the last sentence that you have *enabled*.
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/Disable coherency:
|
||||
//
|
||||
// If you need each fix to contain information that is only
|
||||
// from the current update interval, you should uncomment
|
||||
// this define. At the beginning of the next interval,
|
||||
// the accumulating fix will start out empty. When
|
||||
// the LAST_SENTENCE_IN_INTERVAL arrives, the valid
|
||||
// fields will be coherent.
|
||||
|
||||
//#define NMEAGPS_COHERENT
|
||||
|
||||
// With IMPLICIT merging, fix() will be emptied when the
|
||||
// next sentence begins.
|
||||
//
|
||||
// With EXPLICIT or NO merging, the fix() was already
|
||||
// being initialized.
|
||||
//
|
||||
// If you use the fix-oriented methods available() and read(),
|
||||
// they will empty the current fix for you automatically.
|
||||
//
|
||||
// If you use the character-oriented method decode(), you should
|
||||
// empty the accumulating fix by testing and clearing the
|
||||
// 'intervalComplete' flag in the same way that available() does.
|
||||
|
||||
//------------------------------------------------------
|
||||
// Choose how multiple sentences are merged:
|
||||
// 1) No merging
|
||||
// Each sentence fills out its own fix; there could be
|
||||
// multiple sentences per interval.
|
||||
// 2) EXPLICIT_MERGING
|
||||
// All sentences in an interval are *safely* merged into one fix.
|
||||
// NMEAGPS_FIX_MAX must be >= 1.
|
||||
// An interval is defined by NMEA_LAST_SENTENCE_IN_INTERVAL.
|
||||
// 3) IMPLICIT_MERGING
|
||||
// All sentences in an interval are merged into one fix, with
|
||||
// possible data loss. If a received sentence is rejected for
|
||||
// any reason (e.g., a checksum error), all the values are suspect.
|
||||
// The fix will be cleared; no members will be valid until new
|
||||
// sentences are received and accepted. This uses less RAM.
|
||||
// An interval is defined by NMEA_LAST_SENTENCE_IN_INTERVAL.
|
||||
// Uncomment zero or one:
|
||||
|
||||
#define NMEAGPS_EXPLICIT_MERGING
|
||||
//#define NMEAGPS_IMPLICIT_MERGING
|
||||
|
||||
#ifdef NMEAGPS_IMPLICIT_MERGING
|
||||
#define NMEAGPS_MERGING NMEAGPS::IMPLICIT_MERGING
|
||||
|
||||
// When accumulating, nothing is done to the fix at the
|
||||
// beginning of every sentence...
|
||||
#ifdef NMEAGPS_COHERENT
|
||||
// ...unless COHERENT is enabled and a new interval is starting
|
||||
#define NMEAGPS_INIT_FIX(m) \
|
||||
if (intervalComplete()) { intervalComplete( false ); m.valid.init(); }
|
||||
#else
|
||||
#define NMEAGPS_INIT_FIX(m)
|
||||
#endif
|
||||
|
||||
// ...but we invalidate one part when it starts to get parsed. It *may* get
|
||||
// validated when the parsing is finished.
|
||||
#define NMEAGPS_INVALIDATE(m) m_fix.valid.m = false
|
||||
|
||||
#else
|
||||
|
||||
#ifdef NMEAGPS_EXPLICIT_MERGING
|
||||
#define NMEAGPS_MERGING NMEAGPS::EXPLICIT_MERGING
|
||||
#else
|
||||
#define NMEAGPS_MERGING NMEAGPS::NO_MERGING
|
||||
#define NMEAGPS_NO_MERGING
|
||||
#endif
|
||||
|
||||
// When NOT accumulating, invalidate the entire fix at the
|
||||
// beginning of every sentence
|
||||
#define NMEAGPS_INIT_FIX(m) m.valid.init()
|
||||
|
||||
// ...so the individual parts do not need to be invalidated as they are parsed
|
||||
#define NMEAGPS_INVALIDATE(m)
|
||||
|
||||
#endif
|
||||
|
||||
#if ( defined(NMEAGPS_NO_MERGING) + \
|
||||
defined(NMEAGPS_IMPLICIT_MERGING) + \
|
||||
defined(NMEAGPS_EXPLICIT_MERGING) ) > 1
|
||||
#error Only one MERGING technique should be enabled in NMEAGPS_cfg.h!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Define the fix buffer size. The NMEAGPS object will hold on to
|
||||
// this many fixes before an overrun occurs. This can be zero,
|
||||
// but you have to be more careful about using gps.fix() structure,
|
||||
// because it will be modified as characters are received.
|
||||
|
||||
#define NMEAGPS_FIX_MAX 1
|
||||
|
||||
#if defined(NMEAGPS_EXPLICIT_MERGING) && (NMEAGPS_FIX_MAX == 0)
|
||||
#error You must define FIX_MAX >= 1 to allow EXPLICIT merging in NMEAGPS_cfg.h
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/Disable interrupt-style processing of GPS characters
|
||||
// If you are using one of the NeoXXSerial libraries,
|
||||
// to attachInterrupt, this must be defined.
|
||||
// Otherwise, it must be commented out.
|
||||
|
||||
//#define NMEAGPS_INTERRUPT_PROCESSING
|
||||
|
||||
#ifdef NMEAGPS_INTERRUPT_PROCESSING
|
||||
#define NMEAGPS_PROCESSING_STYLE NMEAGPS::PS_INTERRUPT
|
||||
#else
|
||||
#define NMEAGPS_PROCESSING_STYLE NMEAGPS::PS_POLLING
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable the talker ID, manufacturer ID and proprietary message processing.
|
||||
//
|
||||
// First, some background information. There are two kinds of NMEA sentences:
|
||||
//
|
||||
// 1. Standard NMEA sentences begin with "$ttccc", where
|
||||
// "tt" is the talker ID, and
|
||||
// "ccc" is the variable-length sentence type (i.e., command).
|
||||
//
|
||||
// For example, "$GPGLL,..." is a GLL sentence (Geographic Lat/Long)
|
||||
// transmitted by talker "GP". This is the most common talker ID. Some
|
||||
// devices may report "$GNGLL,..." when a mix of GPS and non-GPS
|
||||
// satellites have been used to determine the GLL data.
|
||||
//
|
||||
// 2. Proprietary NMEA sentences (i.e., those unique to a particular
|
||||
// manufacturer) begin with "$Pmmmccc", where
|
||||
// "P" is the NMEA-defined prefix indicator for proprietary messages,
|
||||
// "mmm" is the 3-character manufacturer ID, and
|
||||
// "ccc" is the variable-length sentence type (it can be empty).
|
||||
//
|
||||
// No validation of manufacturer ID and talker ID is performed in this
|
||||
// base class. For example, although "GP" is a common talker ID, it is not
|
||||
// guaranteed to be transmitted by your particular device, and it IS NOT
|
||||
// REQUIRED. If you need validation of these IDs, or you need to use the
|
||||
// extra information provided by some devices, you have two independent
|
||||
// options:
|
||||
//
|
||||
// 1. Enable SAVING the ID: When /decode/ returns DECODE_COMPLETED, the
|
||||
// /talker_id/ and/or /mfr_id/ members will contain ID bytes. The entire
|
||||
// sentence will be parsed, perhaps modifying members of /fix/. You should
|
||||
// enable one or both IDs if you want the information in all sentences *and*
|
||||
// you also want to know the ID bytes. This adds two bytes of RAM for the
|
||||
// talker ID, and 3 bytes of RAM for the manufacturer ID.
|
||||
//
|
||||
// 2. Enable PARSING the ID: The virtual /parse_talker_id/ and
|
||||
// /parse_mfr_id/ will receive each ID character as it is parsed. If it
|
||||
// is not a valid ID, return /false/ to abort processing the rest of the
|
||||
// sentence. No CPU time will be wasted on the invalid sentence, and no
|
||||
// /fix/ members will be modified. You should enable this if you want to
|
||||
// ignore some IDs. You must override /parse_talker_id/ and/or
|
||||
// /parse_mfr_id/ in a derived class.
|
||||
//
|
||||
|
||||
//#define NMEAGPS_SAVE_TALKER_ID
|
||||
//#define NMEAGPS_PARSE_TALKER_ID
|
||||
|
||||
//#define NMEAGPS_PARSE_PROPRIETARY
|
||||
#ifdef NMEAGPS_PARSE_PROPRIETARY
|
||||
//#define NMEAGPS_SAVE_MFR_ID
|
||||
#define NMEAGPS_PARSE_MFR_ID
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable tracking the current satellite array and,
|
||||
// optionally, all the info for each satellite.
|
||||
//
|
||||
|
||||
#define NMEAGPS_PARSE_SATELLITES
|
||||
#define NMEAGPS_PARSE_SATELLITE_INFO
|
||||
|
||||
#ifdef NMEAGPS_PARSE_SATELLITES
|
||||
#define NMEAGPS_MAX_SATELLITES (20)
|
||||
|
||||
#ifndef GPS_FIX_SATELLITES
|
||||
#error GPS_FIX_SATELLITES must be defined in GPSfix.h!
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(NMEAGPS_PARSE_SATELLITE_INFO) & \
|
||||
!defined(NMEAGPS_PARSE_SATELLITES)
|
||||
#error NMEAGPS_PARSE_SATELLITES must be defined!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable gathering interface statistics:
|
||||
// CRC errors and number of sentences received
|
||||
|
||||
#define NMEAGPS_STATS
|
||||
|
||||
//------------------------------------------------------
|
||||
// Configuration item for allowing derived types of NMEAGPS.
|
||||
// If you derive classes from NMEAGPS, you *must* define NMEAGPS_DERIVED_TYPES.
|
||||
// If not defined, virtuals are not used, with a slight size (2 bytes) and
|
||||
// execution time savings.
|
||||
|
||||
//#define NMEAGPS_DERIVED_TYPES
|
||||
|
||||
#ifdef NMEAGPS_DERIVED_TYPES
|
||||
#define NMEAGPS_VIRTUAL virtual
|
||||
#else
|
||||
#define NMEAGPS_VIRTUAL
|
||||
#endif
|
||||
|
||||
//-----------------------------------
|
||||
// See if DERIVED_TYPES is required
|
||||
#if (defined(NMEAGPS_PARSE_TALKER_ID) | defined(NMEAGPS_PARSE_MFR_ID)) & \
|
||||
!defined(NMEAGPS_DERIVED_TYPES)
|
||||
#error You must define NMEAGPS_DERIVED_TYPES in NMEAGPS.h in order to parse Talker and/or Mfr IDs!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Some devices may omit trailing commas at the end of some
|
||||
// sentences. This may prevent the last field from being
|
||||
// parsed correctly, because the parser for some types keep
|
||||
// the value in an intermediate state until the complete
|
||||
// field is received (e.g., parseDDDMM, parseFloat and
|
||||
// parseZDA).
|
||||
//
|
||||
// Enabling this will inject a simulated comma when the end
|
||||
// of a sentence is received and the last field parser
|
||||
// indicated that it still needs one.
|
||||
|
||||
//#define NMEAGPS_COMMA_NEEDED
|
||||
|
||||
//------------------------------------------------------
|
||||
// Some applications may want to recognize a sentence type
|
||||
// without actually parsing any of the fields. Uncommenting
|
||||
// this define will allow the nmeaMessage member to be set
|
||||
// when *any* standard message is seen, even though that
|
||||
// message is not enabled by a NMEAGPS_PARSE_xxx define above.
|
||||
// No valid flags will be true for those sentences.
|
||||
|
||||
#define NMEAGPS_RECOGNIZE_ALL
|
||||
|
||||
//------------------------------------------------------
|
||||
// Sometimes, a little extra space is needed to parse an intermediate form.
|
||||
// This config items enables extra space.
|
||||
|
||||
#define NMEAGPS_PARSING_SCRATCHPAD
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
#ifndef NEOGPS_CFG
|
||||
#define NEOGPS_CFG
|
||||
|
||||
/**
|
||||
* Enable/disable packed data structures.
|
||||
*
|
||||
* Enabling packed data structures will use two less-portable language
|
||||
* features of GCC to reduce RAM requirements. Although it was expected to slightly increase execution time and code size, the reverse is true on 8-bit AVRs: the code is smaller and faster with packing enabled.
|
||||
*
|
||||
* Disabling packed data structures will be very portable to other
|
||||
* platforms. NeoGPS configurations will use slightly more RAM, and on
|
||||
* 8-bit AVRs, the speed is slightly slower, and the code is slightly
|
||||
* larger. There may be no choice but to disable packing on processors
|
||||
* that do not support packed structures.
|
||||
*
|
||||
* There may also be compiler-specific switches that affect packing and the
|
||||
* code which accesses packed members. YMMV.
|
||||
**/
|
||||
|
||||
#ifdef __AVR__
|
||||
#define NEOGPS_PACKED_DATA
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Based on the above define, choose which set of packing macros should
|
||||
// be used in the rest of the NeoGPS package. Do not change these defines.
|
||||
|
||||
#ifdef NEOGPS_PACKED_DATA
|
||||
|
||||
// This is for specifying the number of bits to be used for a
|
||||
// member of a struct. Booleans are typically one bit.
|
||||
#define NEOGPS_BF(b) :b
|
||||
|
||||
// This is for requesting the compiler to pack the struct or class members
|
||||
// "as closely as possible". This is a compiler-dependent interpretation.
|
||||
#define NEOGPS_PACKED __attribute__((packed))
|
||||
|
||||
#else
|
||||
|
||||
// Let the compiler do whatever it wants.
|
||||
|
||||
#define NEOGPS_PACKED
|
||||
#define NEOGPS_BF(b)
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Accommodate C++ compiler and IDE changes.
|
||||
*
|
||||
* Declaring constants as class data instead of instance data helps avoid
|
||||
* collisions with #define names, and allows the compiler to perform more
|
||||
* checks on their usage.
|
||||
*
|
||||
* Until C++ 10 and IDE 1.6.8, initialized class data constants
|
||||
* were declared like this:
|
||||
*
|
||||
* static const <valued types> = <constant-value>;
|
||||
*
|
||||
* Now, non-simple types (e.g., float) must be declared as
|
||||
*
|
||||
* static constexpr <nonsimple-types> = <expression-treated-as-const>;
|
||||
*
|
||||
* The good news is that this allows the compiler to optimize out an
|
||||
* expression that is "promised" to be "evaluatable" as a constant.
|
||||
* The bad news is that it introduces a new language keyword, and the old
|
||||
* code raises an error.
|
||||
*
|
||||
* TODO: Evaluate the requirement for the "static" keyword.
|
||||
* TODO: Evaluate using a C++ version preprocessor symbol for the #if.
|
||||
*
|
||||
* The CONST_CLASS_DATA define will expand to the appropriate keywords.
|
||||
*
|
||||
*/
|
||||
|
||||
#if ARDUINO < 10606
|
||||
|
||||
#define CONST_CLASS_DATA static const
|
||||
|
||||
#else
|
||||
|
||||
#define CONST_CLASS_DATA static constexpr
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef GPS_FIX_CFG
|
||||
#define GPS_FIX_CFG
|
||||
|
||||
/**
|
||||
* Enable/disable the storage for the members of a fix.
|
||||
*
|
||||
* Disabling a member prevents it from being parsed from a received message.
|
||||
* The disabled member cannot be accessed or stored, and its validity flag
|
||||
* would not be available. It will not be declared, and code that uses that
|
||||
* member will not compile.
|
||||
*
|
||||
* DATE and TIME are somewhat coupled in that they share a single `time_t`,
|
||||
* but they have separate validity flags.
|
||||
*
|
||||
* See also note regarding the DOP members, below.
|
||||
*
|
||||
*/
|
||||
|
||||
//#define GPS_FIX_DATE
|
||||
//#define GPS_FIX_TIME
|
||||
//#define GPS_FIX_LOCATION
|
||||
//#define GPS_FIX_LOCATION_DMS
|
||||
//#define GPS_FIX_ALTITUDE
|
||||
//#define GPS_FIX_SPEED
|
||||
//#define GPS_FIX_HEADING
|
||||
//#define GPS_FIX_SATELLITES
|
||||
//#define GPS_FIX_HDOP
|
||||
//#define GPS_FIX_VDOP
|
||||
//#define GPS_FIX_PDOP
|
||||
//#define GPS_FIX_LAT_ERR
|
||||
//#define GPS_FIX_LON_ERR
|
||||
//#define GPS_FIX_ALT_ERR
|
||||
//#define GPS_FIX_GEOID_HEIGHT
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,286 @@
|
||||
#ifndef NMEAGPS_CFG_H
|
||||
#define NMEAGPS_CFG_H
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable the parsing of specific sentences.
|
||||
//
|
||||
// Configuring out a sentence prevents it from being recognized; it
|
||||
// will be completely ignored. (See also NMEAGPS_RECOGNIZE_ALL, below)
|
||||
//
|
||||
// FYI: Only RMC and ZDA contain date information. Other
|
||||
// sentences contain time information. Both date and time are
|
||||
// required if you will be doing time_t-to-clock_t operations.
|
||||
|
||||
//#define NMEAGPS_PARSE_GGA
|
||||
//#define NMEAGPS_PARSE_GLL
|
||||
//#define NMEAGPS_PARSE_GSA
|
||||
//#define NMEAGPS_PARSE_GSV
|
||||
//#define NMEAGPS_PARSE_GST
|
||||
#define NMEAGPS_PARSE_RMC
|
||||
//#define NMEAGPS_PARSE_VTG
|
||||
//#define NMEAGPS_PARSE_ZDA
|
||||
|
||||
//------------------------------------------------------
|
||||
// Select which sentence is sent *last* by your GPS device
|
||||
// in each update interval. This can be used by your sketch
|
||||
// to determine when the GPS quiet time begins, and thus
|
||||
// when you can perform "some" time-consuming operations.
|
||||
|
||||
#define LAST_SENTENCE_IN_INTERVAL NMEAGPS::NMEA_RMC
|
||||
|
||||
// If the NMEA_LAST_SENTENCE_IN_INTERVAL is not chosen
|
||||
// correctly, GPS data may be lost because the sketch
|
||||
// takes too long elsewhere when this sentence is received.
|
||||
// Also, fix members may contain information from different
|
||||
// time intervals (i.e., they are not coherent).
|
||||
//
|
||||
// If you don't know which sentence is the last one,
|
||||
// use NMEAorder.ino to list them. You do not have to select
|
||||
// the last sentence the device sends if you have disabled
|
||||
// it. Just select the last sentence that you have *enabled*.
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/Disable coherency:
|
||||
//
|
||||
// If you need each fix to contain information that is only
|
||||
// from the current update interval, you should uncomment
|
||||
// this define. At the beginning of the next interval,
|
||||
// the accumulating fix will start out empty. When
|
||||
// the LAST_SENTENCE_IN_INTERVAL arrives, the valid
|
||||
// fields will be coherent.
|
||||
|
||||
//#define NMEAGPS_COHERENT
|
||||
|
||||
// With IMPLICIT merging, fix() will be emptied when the
|
||||
// next sentence begins.
|
||||
//
|
||||
// With EXPLICIT or NO merging, the fix() was already
|
||||
// being initialized.
|
||||
//
|
||||
// If you use the fix-oriented methods available() and read(),
|
||||
// they will empty the current fix for you automatically.
|
||||
//
|
||||
// If you use the character-oriented method decode(), you should
|
||||
// empty the accumulating fix by testing and clearing the
|
||||
// 'intervalComplete' flag in the same way that available() does.
|
||||
|
||||
//------------------------------------------------------
|
||||
// Choose how multiple sentences are merged:
|
||||
// 1) No merging
|
||||
// Each sentence fills out its own fix; there could be
|
||||
// multiple sentences per interval.
|
||||
// 2) EXPLICIT_MERGING
|
||||
// All sentences in an interval are *safely* merged into one fix.
|
||||
// NMEAGPS_FIX_MAX must be >= 1.
|
||||
// An interval is defined by NMEA_LAST_SENTENCE_IN_INTERVAL.
|
||||
// 3) IMPLICIT_MERGING
|
||||
// All sentences in an interval are merged into one fix, with
|
||||
// possible data loss. If a received sentence is rejected for
|
||||
// any reason (e.g., a checksum error), all the values are suspect.
|
||||
// The fix will be cleared; no members will be valid until new
|
||||
// sentences are received and accepted. This uses less RAM.
|
||||
// An interval is defined by NMEA_LAST_SENTENCE_IN_INTERVAL.
|
||||
// Uncomment zero or one:
|
||||
|
||||
#define NMEAGPS_EXPLICIT_MERGING
|
||||
//#define NMEAGPS_IMPLICIT_MERGING
|
||||
|
||||
#ifdef NMEAGPS_IMPLICIT_MERGING
|
||||
#define NMEAGPS_MERGING NMEAGPS::IMPLICIT_MERGING
|
||||
|
||||
// When accumulating, nothing is done to the fix at the
|
||||
// beginning of every sentence...
|
||||
#ifdef NMEAGPS_COHERENT
|
||||
// ...unless COHERENT is enabled and a new interval is starting
|
||||
#define NMEAGPS_INIT_FIX(m) \
|
||||
if (intervalComplete()) { intervalComplete( false ); m.valid.init(); }
|
||||
#else
|
||||
#define NMEAGPS_INIT_FIX(m)
|
||||
#endif
|
||||
|
||||
// ...but we invalidate one part when it starts to get parsed. It *may* get
|
||||
// validated when the parsing is finished.
|
||||
#define NMEAGPS_INVALIDATE(m) m_fix.valid.m = false
|
||||
|
||||
#else
|
||||
|
||||
#ifdef NMEAGPS_EXPLICIT_MERGING
|
||||
#define NMEAGPS_MERGING NMEAGPS::EXPLICIT_MERGING
|
||||
#else
|
||||
#define NMEAGPS_MERGING NMEAGPS::NO_MERGING
|
||||
#define NMEAGPS_NO_MERGING
|
||||
#endif
|
||||
|
||||
// When NOT accumulating, invalidate the entire fix at the
|
||||
// beginning of every sentence
|
||||
#define NMEAGPS_INIT_FIX(m) m.valid.init()
|
||||
|
||||
// ...so the individual parts do not need to be invalidated as they are parsed
|
||||
#define NMEAGPS_INVALIDATE(m)
|
||||
|
||||
#endif
|
||||
|
||||
#if ( defined(NMEAGPS_NO_MERGING) + \
|
||||
defined(NMEAGPS_IMPLICIT_MERGING) + \
|
||||
defined(NMEAGPS_EXPLICIT_MERGING) ) > 1
|
||||
#error Only one MERGING technique should be enabled in NMEAGPS_cfg.h!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Define the fix buffer size. The NMEAGPS object will hold on to
|
||||
// this many fixes before an overrun occurs. This can be zero,
|
||||
// but you have to be more careful about using gps.fix() structure,
|
||||
// because it will be modified as characters are received.
|
||||
|
||||
#define NMEAGPS_FIX_MAX 1
|
||||
|
||||
#if defined(NMEAGPS_EXPLICIT_MERGING) && (NMEAGPS_FIX_MAX == 0)
|
||||
#error You must define FIX_MAX >= 1 to allow EXPLICIT merging in NMEAGPS_cfg.h
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/Disable interrupt-style processing of GPS characters
|
||||
// If you are using one of the NeoXXSerial libraries,
|
||||
// to attachInterrupt, this must be defined.
|
||||
// Otherwise, it must be commented out.
|
||||
|
||||
//#define NMEAGPS_INTERRUPT_PROCESSING
|
||||
|
||||
#ifdef NMEAGPS_INTERRUPT_PROCESSING
|
||||
#define NMEAGPS_PROCESSING_STYLE NMEAGPS::PS_INTERRUPT
|
||||
#else
|
||||
#define NMEAGPS_PROCESSING_STYLE NMEAGPS::PS_POLLING
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable the talker ID, manufacturer ID and proprietary message processing.
|
||||
//
|
||||
// First, some background information. There are two kinds of NMEA sentences:
|
||||
//
|
||||
// 1. Standard NMEA sentences begin with "$ttccc", where
|
||||
// "tt" is the talker ID, and
|
||||
// "ccc" is the variable-length sentence type (i.e., command).
|
||||
//
|
||||
// For example, "$GPGLL,..." is a GLL sentence (Geographic Lat/Long)
|
||||
// transmitted by talker "GP". This is the most common talker ID. Some
|
||||
// devices may report "$GNGLL,..." when a mix of GPS and non-GPS
|
||||
// satellites have been used to determine the GLL data.
|
||||
//
|
||||
// 2. Proprietary NMEA sentences (i.e., those unique to a particular
|
||||
// manufacturer) begin with "$Pmmmccc", where
|
||||
// "P" is the NMEA-defined prefix indicator for proprietary messages,
|
||||
// "mmm" is the 3-character manufacturer ID, and
|
||||
// "ccc" is the variable-length sentence type (it can be empty).
|
||||
//
|
||||
// No validation of manufacturer ID and talker ID is performed in this
|
||||
// base class. For example, although "GP" is a common talker ID, it is not
|
||||
// guaranteed to be transmitted by your particular device, and it IS NOT
|
||||
// REQUIRED. If you need validation of these IDs, or you need to use the
|
||||
// extra information provided by some devices, you have two independent
|
||||
// options:
|
||||
//
|
||||
// 1. Enable SAVING the ID: When /decode/ returns DECODE_COMPLETED, the
|
||||
// /talker_id/ and/or /mfr_id/ members will contain ID bytes. The entire
|
||||
// sentence will be parsed, perhaps modifying members of /fix/. You should
|
||||
// enable one or both IDs if you want the information in all sentences *and*
|
||||
// you also want to know the ID bytes. This adds two bytes of RAM for the
|
||||
// talker ID, and 3 bytes of RAM for the manufacturer ID.
|
||||
//
|
||||
// 2. Enable PARSING the ID: The virtual /parse_talker_id/ and
|
||||
// /parse_mfr_id/ will receive each ID character as it is parsed. If it
|
||||
// is not a valid ID, return /false/ to abort processing the rest of the
|
||||
// sentence. No CPU time will be wasted on the invalid sentence, and no
|
||||
// /fix/ members will be modified. You should enable this if you want to
|
||||
// ignore some IDs. You must override /parse_talker_id/ and/or
|
||||
// /parse_mfr_id/ in a derived class.
|
||||
//
|
||||
|
||||
//#define NMEAGPS_SAVE_TALKER_ID
|
||||
//#define NMEAGPS_PARSE_TALKER_ID
|
||||
|
||||
//#define NMEAGPS_PARSE_PROPRIETARY
|
||||
#ifdef NMEAGPS_PARSE_PROPRIETARY
|
||||
//#define NMEAGPS_SAVE_MFR_ID
|
||||
#define NMEAGPS_PARSE_MFR_ID
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable tracking the current satellite array and,
|
||||
// optionally, all the info for each satellite.
|
||||
//
|
||||
|
||||
//#define NMEAGPS_PARSE_SATELLITES
|
||||
//#define NMEAGPS_PARSE_SATELLITE_INFO
|
||||
|
||||
#ifdef NMEAGPS_PARSE_SATELLITES
|
||||
#define NMEAGPS_MAX_SATELLITES (20)
|
||||
|
||||
#ifndef GPS_FIX_SATELLITES
|
||||
#error GPS_FIX_SATELLITES must be defined in GPSfix.h!
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(NMEAGPS_PARSE_SATELLITE_INFO) & \
|
||||
!defined(NMEAGPS_PARSE_SATELLITES)
|
||||
#error NMEAGPS_PARSE_SATELLITES must be defined!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable gathering interface statistics:
|
||||
// CRC errors and number of sentences received
|
||||
|
||||
//#define NMEAGPS_STATS
|
||||
|
||||
//------------------------------------------------------
|
||||
// Configuration item for allowing derived types of NMEAGPS.
|
||||
// If you derive classes from NMEAGPS, you *must* define NMEAGPS_DERIVED_TYPES.
|
||||
// If not defined, virtuals are not used, with a slight size (2 bytes) and
|
||||
// execution time savings.
|
||||
|
||||
//#define NMEAGPS_DERIVED_TYPES
|
||||
|
||||
#ifdef NMEAGPS_DERIVED_TYPES
|
||||
#define NMEAGPS_VIRTUAL virtual
|
||||
#else
|
||||
#define NMEAGPS_VIRTUAL
|
||||
#endif
|
||||
|
||||
//-----------------------------------
|
||||
// See if DERIVED_TYPES is required
|
||||
#if (defined(NMEAGPS_PARSE_TALKER_ID) | defined(NMEAGPS_PARSE_MFR_ID)) & \
|
||||
!defined(NMEAGPS_DERIVED_TYPES)
|
||||
#error You must define NMEAGPS_DERIVED_TYPES in NMEAGPS.h in order to parse Talker and/or Mfr IDs!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Some devices may omit trailing commas at the end of some
|
||||
// sentences. This may prevent the last field from being
|
||||
// parsed correctly, because the parser for some types keep
|
||||
// the value in an intermediate state until the complete
|
||||
// field is received (e.g., parseDDDMM, parseFloat and
|
||||
// parseZDA).
|
||||
//
|
||||
// Enabling this will inject a simulated comma when the end
|
||||
// of a sentence is received and the last field parser
|
||||
// indicated that it still needs one.
|
||||
|
||||
//#define NMEAGPS_COMMA_NEEDED
|
||||
|
||||
//------------------------------------------------------
|
||||
// Some applications may want to recognize a sentence type
|
||||
// without actually parsing any of the fields. Uncommenting
|
||||
// this define will allow the nmeaMessage member to be set
|
||||
// when *any* standard message is seen, even though that
|
||||
// message is not enabled by a NMEAGPS_PARSE_xxx define above.
|
||||
// No valid flags will be true for those sentences.
|
||||
|
||||
//#define NMEAGPS_RECOGNIZE_ALL
|
||||
|
||||
//------------------------------------------------------
|
||||
// Sometimes, a little extra space is needed to parse an intermediate form.
|
||||
// This config items enables extra space.
|
||||
|
||||
//#define NMEAGPS_PARSING_SCRATCHPAD
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
#ifndef NEOGPS_CFG
|
||||
#define NEOGPS_CFG
|
||||
|
||||
/**
|
||||
* Enable/disable packed data structures.
|
||||
*
|
||||
* Enabling packed data structures will use two less-portable language
|
||||
* features of GCC to reduce RAM requirements. Although it was expected to slightly increase execution time and code size, the reverse is true on 8-bit AVRs: the code is smaller and faster with packing enabled.
|
||||
*
|
||||
* Disabling packed data structures will be very portable to other
|
||||
* platforms. NeoGPS configurations will use slightly more RAM, and on
|
||||
* 8-bit AVRs, the speed is slightly slower, and the code is slightly
|
||||
* larger. There may be no choice but to disable packing on processors
|
||||
* that do not support packed structures.
|
||||
*
|
||||
* There may also be compiler-specific switches that affect packing and the
|
||||
* code which accesses packed members. YMMV.
|
||||
**/
|
||||
|
||||
#ifdef __AVR__
|
||||
#define NEOGPS_PACKED_DATA
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Based on the above define, choose which set of packing macros should
|
||||
// be used in the rest of the NeoGPS package. Do not change these defines.
|
||||
|
||||
#ifdef NEOGPS_PACKED_DATA
|
||||
|
||||
// This is for specifying the number of bits to be used for a
|
||||
// member of a struct. Booleans are typically one bit.
|
||||
#define NEOGPS_BF(b) :b
|
||||
|
||||
// This is for requesting the compiler to pack the struct or class members
|
||||
// "as closely as possible". This is a compiler-dependent interpretation.
|
||||
#define NEOGPS_PACKED __attribute__((packed))
|
||||
|
||||
#else
|
||||
|
||||
// Let the compiler do whatever it wants.
|
||||
|
||||
#define NEOGPS_PACKED
|
||||
#define NEOGPS_BF(b)
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Accommodate C++ compiler and IDE changes.
|
||||
*
|
||||
* Declaring constants as class data instead of instance data helps avoid
|
||||
* collisions with #define names, and allows the compiler to perform more
|
||||
* checks on their usage.
|
||||
*
|
||||
* Until C++ 10 and IDE 1.6.8, initialized class data constants
|
||||
* were declared like this:
|
||||
*
|
||||
* static const <valued types> = <constant-value>;
|
||||
*
|
||||
* Now, non-simple types (e.g., float) must be declared as
|
||||
*
|
||||
* static constexpr <nonsimple-types> = <expression-treated-as-const>;
|
||||
*
|
||||
* The good news is that this allows the compiler to optimize out an
|
||||
* expression that is "promised" to be "evaluatable" as a constant.
|
||||
* The bad news is that it introduces a new language keyword, and the old
|
||||
* code raises an error.
|
||||
*
|
||||
* TODO: Evaluate the requirement for the "static" keyword.
|
||||
* TODO: Evaluate using a C++ version preprocessor symbol for the #if.
|
||||
*
|
||||
* The CONST_CLASS_DATA define will expand to the appropriate keywords.
|
||||
*
|
||||
*/
|
||||
|
||||
#if ARDUINO < 10606
|
||||
|
||||
#define CONST_CLASS_DATA static const
|
||||
|
||||
#else
|
||||
|
||||
#define CONST_CLASS_DATA static constexpr
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef GPS_FIX_CFG
|
||||
#define GPS_FIX_CFG
|
||||
|
||||
/**
|
||||
* Enable/disable the storage for the members of a fix.
|
||||
*
|
||||
* Disabling a member prevents it from being parsed from a received message.
|
||||
* The disabled member cannot be accessed or stored, and its validity flag
|
||||
* would not be available. It will not be declared, and code that uses that
|
||||
* member will not compile.
|
||||
*
|
||||
* DATE and TIME are somewhat coupled in that they share a single `time_t`,
|
||||
* but they have separate validity flags.
|
||||
*
|
||||
* See also note regarding the DOP members, below.
|
||||
*
|
||||
*/
|
||||
|
||||
#define GPS_FIX_DATE
|
||||
#define GPS_FIX_TIME
|
||||
#define GPS_FIX_LOCATION
|
||||
//#define GPS_FIX_LOCATION_DMS
|
||||
#define GPS_FIX_ALTITUDE
|
||||
#define GPS_FIX_SPEED
|
||||
#define GPS_FIX_HEADING
|
||||
#define GPS_FIX_SATELLITES
|
||||
//#define GPS_FIX_HDOP
|
||||
//#define GPS_FIX_VDOP
|
||||
//#define GPS_FIX_PDOP
|
||||
//#define GPS_FIX_LAT_ERR
|
||||
//#define GPS_FIX_LON_ERR
|
||||
//#define GPS_FIX_ALT_ERR
|
||||
//#define GPS_FIX_GEOID_HEIGHT
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,286 @@
|
||||
#ifndef NMEAGPS_CFG_H
|
||||
#define NMEAGPS_CFG_H
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable the parsing of specific sentences.
|
||||
//
|
||||
// Configuring out a sentence prevents it from being recognized; it
|
||||
// will be completely ignored. (See also NMEAGPS_RECOGNIZE_ALL, below)
|
||||
//
|
||||
// FYI: Only RMC and ZDA contain date information. Other
|
||||
// sentences contain time information. Both date and time are
|
||||
// required if you will be doing time_t-to-clock_t operations.
|
||||
|
||||
#define NMEAGPS_PARSE_GGA
|
||||
//#define NMEAGPS_PARSE_GLL
|
||||
//#define NMEAGPS_PARSE_GSA
|
||||
//#define NMEAGPS_PARSE_GSV
|
||||
//#define NMEAGPS_PARSE_GST
|
||||
#define NMEAGPS_PARSE_RMC
|
||||
//#define NMEAGPS_PARSE_VTG
|
||||
//#define NMEAGPS_PARSE_ZDA
|
||||
|
||||
//------------------------------------------------------
|
||||
// Select which sentence is sent *last* by your GPS device
|
||||
// in each update interval. This can be used by your sketch
|
||||
// to determine when the GPS quiet time begins, and thus
|
||||
// when you can perform "some" time-consuming operations.
|
||||
|
||||
#define LAST_SENTENCE_IN_INTERVAL NMEAGPS::NMEA_RMC
|
||||
|
||||
// If the NMEA_LAST_SENTENCE_IN_INTERVAL is not chosen
|
||||
// correctly, GPS data may be lost because the sketch
|
||||
// takes too long elsewhere when this sentence is received.
|
||||
// Also, fix members may contain information from different
|
||||
// time intervals (i.e., they are not coherent).
|
||||
//
|
||||
// If you don't know which sentence is the last one,
|
||||
// use NMEAorder.ino to list them. You do not have to select
|
||||
// the last sentence the device sends if you have disabled
|
||||
// it. Just select the last sentence that you have *enabled*.
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/Disable coherency:
|
||||
//
|
||||
// If you need each fix to contain information that is only
|
||||
// from the current update interval, you should uncomment
|
||||
// this define. At the beginning of the next interval,
|
||||
// the accumulating fix will start out empty. When
|
||||
// the LAST_SENTENCE_IN_INTERVAL arrives, the valid
|
||||
// fields will be coherent.
|
||||
|
||||
//#define NMEAGPS_COHERENT
|
||||
|
||||
// With IMPLICIT merging, fix() will be emptied when the
|
||||
// next sentence begins.
|
||||
//
|
||||
// With EXPLICIT or NO merging, the fix() was already
|
||||
// being initialized.
|
||||
//
|
||||
// If you use the fix-oriented methods available() and read(),
|
||||
// they will empty the current fix for you automatically.
|
||||
//
|
||||
// If you use the character-oriented method decode(), you should
|
||||
// empty the accumulating fix by testing and clearing the
|
||||
// 'intervalComplete' flag in the same way that available() does.
|
||||
|
||||
//------------------------------------------------------
|
||||
// Choose how multiple sentences are merged:
|
||||
// 1) No merging
|
||||
// Each sentence fills out its own fix; there could be
|
||||
// multiple sentences per interval.
|
||||
// 2) EXPLICIT_MERGING
|
||||
// All sentences in an interval are *safely* merged into one fix.
|
||||
// NMEAGPS_FIX_MAX must be >= 1.
|
||||
// An interval is defined by NMEA_LAST_SENTENCE_IN_INTERVAL.
|
||||
// 3) IMPLICIT_MERGING
|
||||
// All sentences in an interval are merged into one fix, with
|
||||
// possible data loss. If a received sentence is rejected for
|
||||
// any reason (e.g., a checksum error), all the values are suspect.
|
||||
// The fix will be cleared; no members will be valid until new
|
||||
// sentences are received and accepted. This uses less RAM.
|
||||
// An interval is defined by NMEA_LAST_SENTENCE_IN_INTERVAL.
|
||||
// Uncomment zero or one:
|
||||
|
||||
#define NMEAGPS_EXPLICIT_MERGING
|
||||
//#define NMEAGPS_IMPLICIT_MERGING
|
||||
|
||||
#ifdef NMEAGPS_IMPLICIT_MERGING
|
||||
#define NMEAGPS_MERGING NMEAGPS::IMPLICIT_MERGING
|
||||
|
||||
// When accumulating, nothing is done to the fix at the
|
||||
// beginning of every sentence...
|
||||
#ifdef NMEAGPS_COHERENT
|
||||
// ...unless COHERENT is enabled and a new interval is starting
|
||||
#define NMEAGPS_INIT_FIX(m) \
|
||||
if (intervalComplete()) { intervalComplete( false ); m.valid.init(); }
|
||||
#else
|
||||
#define NMEAGPS_INIT_FIX(m)
|
||||
#endif
|
||||
|
||||
// ...but we invalidate one part when it starts to get parsed. It *may* get
|
||||
// validated when the parsing is finished.
|
||||
#define NMEAGPS_INVALIDATE(m) m_fix.valid.m = false
|
||||
|
||||
#else
|
||||
|
||||
#ifdef NMEAGPS_EXPLICIT_MERGING
|
||||
#define NMEAGPS_MERGING NMEAGPS::EXPLICIT_MERGING
|
||||
#else
|
||||
#define NMEAGPS_MERGING NMEAGPS::NO_MERGING
|
||||
#define NMEAGPS_NO_MERGING
|
||||
#endif
|
||||
|
||||
// When NOT accumulating, invalidate the entire fix at the
|
||||
// beginning of every sentence
|
||||
#define NMEAGPS_INIT_FIX(m) m.valid.init()
|
||||
|
||||
// ...so the individual parts do not need to be invalidated as they are parsed
|
||||
#define NMEAGPS_INVALIDATE(m)
|
||||
|
||||
#endif
|
||||
|
||||
#if ( defined(NMEAGPS_NO_MERGING) + \
|
||||
defined(NMEAGPS_IMPLICIT_MERGING) + \
|
||||
defined(NMEAGPS_EXPLICIT_MERGING) ) > 1
|
||||
#error Only one MERGING technique should be enabled in NMEAGPS_cfg.h!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Define the fix buffer size. The NMEAGPS object will hold on to
|
||||
// this many fixes before an overrun occurs. This can be zero,
|
||||
// but you have to be more careful about using gps.fix() structure,
|
||||
// because it will be modified as characters are received.
|
||||
|
||||
#define NMEAGPS_FIX_MAX 1
|
||||
|
||||
#if defined(NMEAGPS_EXPLICIT_MERGING) && (NMEAGPS_FIX_MAX == 0)
|
||||
#error You must define FIX_MAX >= 1 to allow EXPLICIT merging in NMEAGPS_cfg.h
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/Disable interrupt-style processing of GPS characters
|
||||
// If you are using one of the NeoXXSerial libraries,
|
||||
// to attachInterrupt, this must be defined.
|
||||
// Otherwise, it must be commented out.
|
||||
|
||||
//#define NMEAGPS_INTERRUPT_PROCESSING
|
||||
|
||||
#ifdef NMEAGPS_INTERRUPT_PROCESSING
|
||||
#define NMEAGPS_PROCESSING_STYLE NMEAGPS::PS_INTERRUPT
|
||||
#else
|
||||
#define NMEAGPS_PROCESSING_STYLE NMEAGPS::PS_POLLING
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable the talker ID, manufacturer ID and proprietary message processing.
|
||||
//
|
||||
// First, some background information. There are two kinds of NMEA sentences:
|
||||
//
|
||||
// 1. Standard NMEA sentences begin with "$ttccc", where
|
||||
// "tt" is the talker ID, and
|
||||
// "ccc" is the variable-length sentence type (i.e., command).
|
||||
//
|
||||
// For example, "$GPGLL,..." is a GLL sentence (Geographic Lat/Long)
|
||||
// transmitted by talker "GP". This is the most common talker ID. Some
|
||||
// devices may report "$GNGLL,..." when a mix of GPS and non-GPS
|
||||
// satellites have been used to determine the GLL data.
|
||||
//
|
||||
// 2. Proprietary NMEA sentences (i.e., those unique to a particular
|
||||
// manufacturer) begin with "$Pmmmccc", where
|
||||
// "P" is the NMEA-defined prefix indicator for proprietary messages,
|
||||
// "mmm" is the 3-character manufacturer ID, and
|
||||
// "ccc" is the variable-length sentence type (it can be empty).
|
||||
//
|
||||
// No validation of manufacturer ID and talker ID is performed in this
|
||||
// base class. For example, although "GP" is a common talker ID, it is not
|
||||
// guaranteed to be transmitted by your particular device, and it IS NOT
|
||||
// REQUIRED. If you need validation of these IDs, or you need to use the
|
||||
// extra information provided by some devices, you have two independent
|
||||
// options:
|
||||
//
|
||||
// 1. Enable SAVING the ID: When /decode/ returns DECODE_COMPLETED, the
|
||||
// /talker_id/ and/or /mfr_id/ members will contain ID bytes. The entire
|
||||
// sentence will be parsed, perhaps modifying members of /fix/. You should
|
||||
// enable one or both IDs if you want the information in all sentences *and*
|
||||
// you also want to know the ID bytes. This adds two bytes of RAM for the
|
||||
// talker ID, and 3 bytes of RAM for the manufacturer ID.
|
||||
//
|
||||
// 2. Enable PARSING the ID: The virtual /parse_talker_id/ and
|
||||
// /parse_mfr_id/ will receive each ID character as it is parsed. If it
|
||||
// is not a valid ID, return /false/ to abort processing the rest of the
|
||||
// sentence. No CPU time will be wasted on the invalid sentence, and no
|
||||
// /fix/ members will be modified. You should enable this if you want to
|
||||
// ignore some IDs. You must override /parse_talker_id/ and/or
|
||||
// /parse_mfr_id/ in a derived class.
|
||||
//
|
||||
|
||||
//#define NMEAGPS_SAVE_TALKER_ID
|
||||
//#define NMEAGPS_PARSE_TALKER_ID
|
||||
|
||||
//#define NMEAGPS_PARSE_PROPRIETARY
|
||||
#ifdef NMEAGPS_PARSE_PROPRIETARY
|
||||
//#define NMEAGPS_SAVE_MFR_ID
|
||||
#define NMEAGPS_PARSE_MFR_ID
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable tracking the current satellite array and,
|
||||
// optionally, all the info for each satellite.
|
||||
//
|
||||
|
||||
//#define NMEAGPS_PARSE_SATELLITES
|
||||
//#define NMEAGPS_PARSE_SATELLITE_INFO
|
||||
|
||||
#ifdef NMEAGPS_PARSE_SATELLITES
|
||||
#define NMEAGPS_MAX_SATELLITES (20)
|
||||
|
||||
#ifndef GPS_FIX_SATELLITES
|
||||
#error GPS_FIX_SATELLITES must be defined in GPSfix.h!
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(NMEAGPS_PARSE_SATELLITE_INFO) & \
|
||||
!defined(NMEAGPS_PARSE_SATELLITES)
|
||||
#error NMEAGPS_PARSE_SATELLITES must be defined!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable gathering interface statistics:
|
||||
// CRC errors and number of sentences received
|
||||
|
||||
#define NMEAGPS_STATS
|
||||
|
||||
//------------------------------------------------------
|
||||
// Configuration item for allowing derived types of NMEAGPS.
|
||||
// If you derive classes from NMEAGPS, you *must* define NMEAGPS_DERIVED_TYPES.
|
||||
// If not defined, virtuals are not used, with a slight size (2 bytes) and
|
||||
// execution time savings.
|
||||
|
||||
//#define NMEAGPS_DERIVED_TYPES
|
||||
|
||||
#ifdef NMEAGPS_DERIVED_TYPES
|
||||
#define NMEAGPS_VIRTUAL virtual
|
||||
#else
|
||||
#define NMEAGPS_VIRTUAL
|
||||
#endif
|
||||
|
||||
//-----------------------------------
|
||||
// See if DERIVED_TYPES is required
|
||||
#if (defined(NMEAGPS_PARSE_TALKER_ID) | defined(NMEAGPS_PARSE_MFR_ID)) & \
|
||||
!defined(NMEAGPS_DERIVED_TYPES)
|
||||
#error You must define NMEAGPS_DERIVED_TYPES in NMEAGPS.h in order to parse Talker and/or Mfr IDs!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Some devices may omit trailing commas at the end of some
|
||||
// sentences. This may prevent the last field from being
|
||||
// parsed correctly, because the parser for some types keep
|
||||
// the value in an intermediate state until the complete
|
||||
// field is received (e.g., parseDDDMM, parseFloat and
|
||||
// parseZDA).
|
||||
//
|
||||
// Enabling this will inject a simulated comma when the end
|
||||
// of a sentence is received and the last field parser
|
||||
// indicated that it still needs one.
|
||||
|
||||
//#define NMEAGPS_COMMA_NEEDED
|
||||
|
||||
//------------------------------------------------------
|
||||
// Some applications may want to recognize a sentence type
|
||||
// without actually parsing any of the fields. Uncommenting
|
||||
// this define will allow the nmeaMessage member to be set
|
||||
// when *any* standard message is seen, even though that
|
||||
// message is not enabled by a NMEAGPS_PARSE_xxx define above.
|
||||
// No valid flags will be true for those sentences.
|
||||
|
||||
#define NMEAGPS_RECOGNIZE_ALL
|
||||
|
||||
//------------------------------------------------------
|
||||
// Sometimes, a little extra space is needed to parse an intermediate form.
|
||||
// This config items enables extra space.
|
||||
|
||||
//#define NMEAGPS_PARSING_SCRATCHPAD
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
#ifndef NEOGPS_CFG
|
||||
#define NEOGPS_CFG
|
||||
|
||||
/**
|
||||
* Enable/disable packed data structures.
|
||||
*
|
||||
* Enabling packed data structures will use two less-portable language
|
||||
* features of GCC to reduce RAM requirements. Although it was expected to slightly increase execution time and code size, the reverse is true on 8-bit AVRs: the code is smaller and faster with packing enabled.
|
||||
*
|
||||
* Disabling packed data structures will be very portable to other
|
||||
* platforms. NeoGPS configurations will use slightly more RAM, and on
|
||||
* 8-bit AVRs, the speed is slightly slower, and the code is slightly
|
||||
* larger. There may be no choice but to disable packing on processors
|
||||
* that do not support packed structures.
|
||||
*
|
||||
* There may also be compiler-specific switches that affect packing and the
|
||||
* code which accesses packed members. YMMV.
|
||||
**/
|
||||
|
||||
#ifdef __AVR__
|
||||
#define NEOGPS_PACKED_DATA
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Based on the above define, choose which set of packing macros should
|
||||
// be used in the rest of the NeoGPS package. Do not change these defines.
|
||||
|
||||
#ifdef NEOGPS_PACKED_DATA
|
||||
|
||||
// This is for specifying the number of bits to be used for a
|
||||
// member of a struct. Booleans are typically one bit.
|
||||
#define NEOGPS_BF(b) :b
|
||||
|
||||
// This is for requesting the compiler to pack the struct or class members
|
||||
// "as closely as possible". This is a compiler-dependent interpretation.
|
||||
#define NEOGPS_PACKED __attribute__((packed))
|
||||
|
||||
#else
|
||||
|
||||
// Let the compiler do whatever it wants.
|
||||
|
||||
#define NEOGPS_PACKED
|
||||
#define NEOGPS_BF(b)
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Accommodate C++ compiler and IDE changes.
|
||||
*
|
||||
* Declaring constants as class data instead of instance data helps avoid
|
||||
* collisions with #define names, and allows the compiler to perform more
|
||||
* checks on their usage.
|
||||
*
|
||||
* Until C++ 10 and IDE 1.6.8, initialized class data constants
|
||||
* were declared like this:
|
||||
*
|
||||
* static const <valued types> = <constant-value>;
|
||||
*
|
||||
* Now, non-simple types (e.g., float) must be declared as
|
||||
*
|
||||
* static constexpr <nonsimple-types> = <expression-treated-as-const>;
|
||||
*
|
||||
* The good news is that this allows the compiler to optimize out an
|
||||
* expression that is "promised" to be "evaluatable" as a constant.
|
||||
* The bad news is that it introduces a new language keyword, and the old
|
||||
* code raises an error.
|
||||
*
|
||||
* TODO: Evaluate the requirement for the "static" keyword.
|
||||
* TODO: Evaluate using a C++ version preprocessor symbol for the #if.
|
||||
*
|
||||
* The CONST_CLASS_DATA define will expand to the appropriate keywords.
|
||||
*
|
||||
*/
|
||||
|
||||
#if ARDUINO < 10606
|
||||
|
||||
#define CONST_CLASS_DATA static const
|
||||
|
||||
#else
|
||||
|
||||
#define CONST_CLASS_DATA static constexpr
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef GPS_FIX_CFG
|
||||
#define GPS_FIX_CFG
|
||||
|
||||
/**
|
||||
* Enable/disable the storage for the members of a fix.
|
||||
*
|
||||
* Disabling a member prevents it from being parsed from a received message.
|
||||
* The disabled member cannot be accessed or stored, and its validity flag
|
||||
* would not be available. It will not be declared, and code that uses that
|
||||
* member will not compile.
|
||||
*
|
||||
* DATE and TIME are somewhat coupled in that they share a single `time_t`,
|
||||
* but they have separate validity flags.
|
||||
*
|
||||
* See also note regarding the DOP members, below.
|
||||
*
|
||||
*/
|
||||
|
||||
#define GPS_FIX_DATE
|
||||
#define GPS_FIX_TIME
|
||||
#define GPS_FIX_LOCATION
|
||||
//#define GPS_FIX_LOCATION_DMS
|
||||
#define GPS_FIX_ALTITUDE
|
||||
#define GPS_FIX_SPEED
|
||||
#define GPS_FIX_HEADING
|
||||
#define GPS_FIX_SATELLITES
|
||||
//#define GPS_FIX_HDOP
|
||||
//#define GPS_FIX_VDOP
|
||||
//#define GPS_FIX_PDOP
|
||||
//#define GPS_FIX_LAT_ERR
|
||||
//#define GPS_FIX_LON_ERR
|
||||
//#define GPS_FIX_ALT_ERR
|
||||
//#define GPS_FIX_GEOID_HEIGHT
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,286 @@
|
||||
#ifndef NMEAGPS_CFG_H
|
||||
#define NMEAGPS_CFG_H
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable the parsing of specific sentences.
|
||||
//
|
||||
// Configuring out a sentence prevents it from being recognized; it
|
||||
// will be completely ignored. (See also NMEAGPS_RECOGNIZE_ALL, below)
|
||||
//
|
||||
// FYI: Only RMC and ZDA contain date information. Other
|
||||
// sentences contain time information. Both date and time are
|
||||
// required if you will be doing time_t-to-clock_t operations.
|
||||
|
||||
//#define NMEAGPS_PARSE_GGA
|
||||
//#define NMEAGPS_PARSE_GLL
|
||||
//#define NMEAGPS_PARSE_GSA
|
||||
//#define NMEAGPS_PARSE_GSV
|
||||
//#define NMEAGPS_PARSE_GST
|
||||
//#define NMEAGPS_PARSE_RMC
|
||||
//#define NMEAGPS_PARSE_VTG
|
||||
//#define NMEAGPS_PARSE_ZDA
|
||||
|
||||
//------------------------------------------------------
|
||||
// Select which sentence is sent *last* by your GPS device
|
||||
// in each update interval. This can be used by your sketch
|
||||
// to determine when the GPS quiet time begins, and thus
|
||||
// when you can perform "some" time-consuming operations.
|
||||
|
||||
#define LAST_SENTENCE_IN_INTERVAL (nmea_msg_t) NMEA_LAST_MSG+5 /* ubloxNMEA::PUBX_04 */
|
||||
|
||||
// If the NMEA_LAST_SENTENCE_IN_INTERVAL is not chosen
|
||||
// correctly, GPS data may be lost because the sketch
|
||||
// takes too long elsewhere when this sentence is received.
|
||||
// Also, fix members may contain information from different
|
||||
// time intervals (i.e., they are not coherent).
|
||||
//
|
||||
// If you don't know which sentence is the last one,
|
||||
// use NMEAorder.ino to list them. You do not have to select
|
||||
// the last sentence the device sends if you have disabled
|
||||
// it. Just select the last sentence that you have *enabled*.
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/Disable coherency:
|
||||
//
|
||||
// If you need each fix to contain information that is only
|
||||
// from the current update interval, you should uncomment
|
||||
// this define. At the beginning of the next interval,
|
||||
// the accumulating fix will start out empty. When
|
||||
// the LAST_SENTENCE_IN_INTERVAL arrives, the valid
|
||||
// fields will be coherent.
|
||||
|
||||
//#define NMEAGPS_COHERENT
|
||||
|
||||
// With IMPLICIT merging, fix() will be emptied when the
|
||||
// next sentence begins.
|
||||
//
|
||||
// With EXPLICIT or NO merging, the fix() was already
|
||||
// being initialized.
|
||||
//
|
||||
// If you use the fix-oriented methods available() and read(),
|
||||
// they will empty the current fix for you automatically.
|
||||
//
|
||||
// If you use the character-oriented method decode(), you should
|
||||
// empty the accumulating fix by testing and clearing the
|
||||
// 'intervalComplete' flag in the same way that available() does.
|
||||
|
||||
//------------------------------------------------------
|
||||
// Choose how multiple sentences are merged:
|
||||
// 1) No merging
|
||||
// Each sentence fills out its own fix; there could be
|
||||
// multiple sentences per interval.
|
||||
// 2) EXPLICIT_MERGING
|
||||
// All sentences in an interval are *safely* merged into one fix.
|
||||
// NMEAGPS_FIX_MAX must be >= 1.
|
||||
// An interval is defined by NMEA_LAST_SENTENCE_IN_INTERVAL.
|
||||
// 3) IMPLICIT_MERGING
|
||||
// All sentences in an interval are merged into one fix, with
|
||||
// possible data loss. If a received sentence is rejected for
|
||||
// any reason (e.g., a checksum error), all the values are suspect.
|
||||
// The fix will be cleared; no members will be valid until new
|
||||
// sentences are received and accepted. This uses less RAM.
|
||||
// An interval is defined by NMEA_LAST_SENTENCE_IN_INTERVAL.
|
||||
// Uncomment zero or one:
|
||||
|
||||
#define NMEAGPS_EXPLICIT_MERGING
|
||||
//#define NMEAGPS_IMPLICIT_MERGING
|
||||
|
||||
#ifdef NMEAGPS_IMPLICIT_MERGING
|
||||
#define NMEAGPS_MERGING NMEAGPS::IMPLICIT_MERGING
|
||||
|
||||
// When accumulating, nothing is done to the fix at the
|
||||
// beginning of every sentence...
|
||||
#ifdef NMEAGPS_COHERENT
|
||||
// ...unless COHERENT is enabled and a new interval is starting
|
||||
#define NMEAGPS_INIT_FIX(m) \
|
||||
if (intervalComplete()) { intervalComplete( false ); m.valid.init(); }
|
||||
#else
|
||||
#define NMEAGPS_INIT_FIX(m)
|
||||
#endif
|
||||
|
||||
// ...but we invalidate one part when it starts to get parsed. It *may* get
|
||||
// validated when the parsing is finished.
|
||||
#define NMEAGPS_INVALIDATE(m) m_fix.valid.m = false
|
||||
|
||||
#else
|
||||
|
||||
#ifdef NMEAGPS_EXPLICIT_MERGING
|
||||
#define NMEAGPS_MERGING NMEAGPS::EXPLICIT_MERGING
|
||||
#else
|
||||
#define NMEAGPS_MERGING NMEAGPS::NO_MERGING
|
||||
#define NMEAGPS_NO_MERGING
|
||||
#endif
|
||||
|
||||
// When NOT accumulating, invalidate the entire fix at the
|
||||
// beginning of every sentence
|
||||
#define NMEAGPS_INIT_FIX(m) m.valid.init()
|
||||
|
||||
// ...so the individual parts do not need to be invalidated as they are parsed
|
||||
#define NMEAGPS_INVALIDATE(m)
|
||||
|
||||
#endif
|
||||
|
||||
#if ( defined(NMEAGPS_NO_MERGING) + \
|
||||
defined(NMEAGPS_IMPLICIT_MERGING) + \
|
||||
defined(NMEAGPS_EXPLICIT_MERGING) ) > 1
|
||||
#error Only one MERGING technique should be enabled in NMEAGPS_cfg.h!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Define the fix buffer size. The NMEAGPS object will hold on to
|
||||
// this many fixes before an overrun occurs. This can be zero,
|
||||
// but you have to be more careful about using gps.fix() structure,
|
||||
// because it will be modified as characters are received.
|
||||
|
||||
#define NMEAGPS_FIX_MAX 1
|
||||
|
||||
#if defined(NMEAGPS_EXPLICIT_MERGING) && (NMEAGPS_FIX_MAX == 0)
|
||||
#error You must define FIX_MAX >= 1 to allow EXPLICIT merging in NMEAGPS_cfg.h
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/Disable interrupt-style processing of GPS characters
|
||||
// If you are using one of the NeoXXSerial libraries,
|
||||
// to attachInterrupt, this must be defined.
|
||||
// Otherwise, it must be commented out.
|
||||
|
||||
//#define NMEAGPS_INTERRUPT_PROCESSING
|
||||
|
||||
#ifdef NMEAGPS_INTERRUPT_PROCESSING
|
||||
#define NMEAGPS_PROCESSING_STYLE NMEAGPS::PS_INTERRUPT
|
||||
#else
|
||||
#define NMEAGPS_PROCESSING_STYLE NMEAGPS::PS_POLLING
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable the talker ID, manufacturer ID and proprietary message processing.
|
||||
//
|
||||
// First, some background information. There are two kinds of NMEA sentences:
|
||||
//
|
||||
// 1. Standard NMEA sentences begin with "$ttccc", where
|
||||
// "tt" is the talker ID, and
|
||||
// "ccc" is the variable-length sentence type (i.e., command).
|
||||
//
|
||||
// For example, "$GPGLL,..." is a GLL sentence (Geographic Lat/Long)
|
||||
// transmitted by talker "GP". This is the most common talker ID. Some
|
||||
// devices may report "$GNGLL,..." when a mix of GPS and non-GPS
|
||||
// satellites have been used to determine the GLL data.
|
||||
//
|
||||
// 2. Proprietary NMEA sentences (i.e., those unique to a particular
|
||||
// manufacturer) begin with "$Pmmmccc", where
|
||||
// "P" is the NMEA-defined prefix indicator for proprietary messages,
|
||||
// "mmm" is the 3-character manufacturer ID, and
|
||||
// "ccc" is the variable-length sentence type (it can be empty).
|
||||
//
|
||||
// No validation of manufacturer ID and talker ID is performed in this
|
||||
// base class. For example, although "GP" is a common talker ID, it is not
|
||||
// guaranteed to be transmitted by your particular device, and it IS NOT
|
||||
// REQUIRED. If you need validation of these IDs, or you need to use the
|
||||
// extra information provided by some devices, you have two independent
|
||||
// options:
|
||||
//
|
||||
// 1. Enable SAVING the ID: When /decode/ returns DECODE_COMPLETED, the
|
||||
// /talker_id/ and/or /mfr_id/ members will contain ID bytes. The entire
|
||||
// sentence will be parsed, perhaps modifying members of /fix/. You should
|
||||
// enable one or both IDs if you want the information in all sentences *and*
|
||||
// you also want to know the ID bytes. This adds two bytes of RAM for the
|
||||
// talker ID, and 3 bytes of RAM for the manufacturer ID.
|
||||
//
|
||||
// 2. Enable PARSING the ID: The virtual /parse_talker_id/ and
|
||||
// /parse_mfr_id/ will receive each ID character as it is parsed. If it
|
||||
// is not a valid ID, return /false/ to abort processing the rest of the
|
||||
// sentence. No CPU time will be wasted on the invalid sentence, and no
|
||||
// /fix/ members will be modified. You should enable this if you want to
|
||||
// ignore some IDs. You must override /parse_talker_id/ and/or
|
||||
// /parse_mfr_id/ in a derived class.
|
||||
//
|
||||
|
||||
//#define NMEAGPS_SAVE_TALKER_ID
|
||||
//#define NMEAGPS_PARSE_TALKER_ID
|
||||
|
||||
#define NMEAGPS_PARSE_PROPRIETARY
|
||||
#ifdef NMEAGPS_PARSE_PROPRIETARY
|
||||
//#define NMEAGPS_SAVE_MFR_ID
|
||||
#define NMEAGPS_PARSE_MFR_ID
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable tracking the current satellite array and,
|
||||
// optionally, all the info for each satellite.
|
||||
//
|
||||
|
||||
//#define NMEAGPS_PARSE_SATELLITES
|
||||
//#define NMEAGPS_PARSE_SATELLITE_INFO
|
||||
|
||||
#ifdef NMEAGPS_PARSE_SATELLITES
|
||||
#define NMEAGPS_MAX_SATELLITES (20)
|
||||
|
||||
#ifndef GPS_FIX_SATELLITES
|
||||
#error GPS_FIX_SATELLITES must be defined in GPSfix.h!
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(NMEAGPS_PARSE_SATELLITE_INFO) & \
|
||||
!defined(NMEAGPS_PARSE_SATELLITES)
|
||||
#error NMEAGPS_PARSE_SATELLITES must be defined!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable gathering interface statistics:
|
||||
// CRC errors and number of sentences received
|
||||
|
||||
//#define NMEAGPS_STATS
|
||||
|
||||
//------------------------------------------------------
|
||||
// Configuration item for allowing derived types of NMEAGPS.
|
||||
// If you derive classes from NMEAGPS, you *must* define NMEAGPS_DERIVED_TYPES.
|
||||
// If not defined, virtuals are not used, with a slight size (2 bytes) and
|
||||
// execution time savings.
|
||||
|
||||
#define NMEAGPS_DERIVED_TYPES
|
||||
|
||||
#ifdef NMEAGPS_DERIVED_TYPES
|
||||
#define NMEAGPS_VIRTUAL virtual
|
||||
#else
|
||||
#define NMEAGPS_VIRTUAL
|
||||
#endif
|
||||
|
||||
//-----------------------------------
|
||||
// See if DERIVED_TYPES is required
|
||||
#if (defined(NMEAGPS_PARSE_TALKER_ID) | defined(NMEAGPS_PARSE_MFR_ID)) & \
|
||||
!defined(NMEAGPS_DERIVED_TYPES)
|
||||
#error You must define NMEAGPS_DERIVED_TYPES in NMEAGPS.h in order to parse Talker and/or Mfr IDs!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Some devices may omit trailing commas at the end of some
|
||||
// sentences. This may prevent the last field from being
|
||||
// parsed correctly, because the parser for some types keep
|
||||
// the value in an intermediate state until the complete
|
||||
// field is received (e.g., parseDDDMM, parseFloat and
|
||||
// parseZDA).
|
||||
//
|
||||
// Enabling this will inject a simulated comma when the end
|
||||
// of a sentence is received and the last field parser
|
||||
// indicated that it still needs one.
|
||||
|
||||
//#define NMEAGPS_COMMA_NEEDED
|
||||
|
||||
//------------------------------------------------------
|
||||
// Some applications may want to recognize a sentence type
|
||||
// without actually parsing any of the fields. Uncommenting
|
||||
// this define will allow the nmeaMessage member to be set
|
||||
// when *any* standard message is seen, even though that
|
||||
// message is not enabled by a NMEAGPS_PARSE_xxx define above.
|
||||
// No valid flags will be true for those sentences.
|
||||
|
||||
//#define NMEAGPS_RECOGNIZE_ALL
|
||||
|
||||
//------------------------------------------------------
|
||||
// Sometimes, a little extra space is needed to parse an intermediate form.
|
||||
// This config items enables extra space.
|
||||
|
||||
//#define NMEAGPS_PARSING_SCRATCHPAD
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
#ifndef NEOGPS_CFG
|
||||
#define NEOGPS_CFG
|
||||
|
||||
/**
|
||||
* Enable/disable packed data structures.
|
||||
*
|
||||
* Enabling packed data structures will use two less-portable language
|
||||
* features of GCC to reduce RAM requirements. Although it was expected to slightly increase execution time and code size, the reverse is true on 8-bit AVRs: the code is smaller and faster with packing enabled.
|
||||
*
|
||||
* Disabling packed data structures will be very portable to other
|
||||
* platforms. NeoGPS configurations will use slightly more RAM, and on
|
||||
* 8-bit AVRs, the speed is slightly slower, and the code is slightly
|
||||
* larger. There may be no choice but to disable packing on processors
|
||||
* that do not support packed structures.
|
||||
*
|
||||
* There may also be compiler-specific switches that affect packing and the
|
||||
* code which accesses packed members. YMMV.
|
||||
**/
|
||||
|
||||
#ifdef __AVR__
|
||||
#define NEOGPS_PACKED_DATA
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Based on the above define, choose which set of packing macros should
|
||||
// be used in the rest of the NeoGPS package. Do not change these defines.
|
||||
|
||||
#ifdef NEOGPS_PACKED_DATA
|
||||
|
||||
// This is for specifying the number of bits to be used for a
|
||||
// member of a struct. Booleans are typically one bit.
|
||||
#define NEOGPS_BF(b) :b
|
||||
|
||||
// This is for requesting the compiler to pack the struct or class members
|
||||
// "as closely as possible". This is a compiler-dependent interpretation.
|
||||
#define NEOGPS_PACKED __attribute__((packed))
|
||||
|
||||
#else
|
||||
|
||||
// Let the compiler do whatever it wants.
|
||||
|
||||
#define NEOGPS_PACKED
|
||||
#define NEOGPS_BF(b)
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Accommodate C++ compiler and IDE changes.
|
||||
*
|
||||
* Declaring constants as class data instead of instance data helps avoid
|
||||
* collisions with #define names, and allows the compiler to perform more
|
||||
* checks on their usage.
|
||||
*
|
||||
* Until C++ 10 and IDE 1.6.8, initialized class data constants
|
||||
* were declared like this:
|
||||
*
|
||||
* static const <valued types> = <constant-value>;
|
||||
*
|
||||
* Now, non-simple types (e.g., float) must be declared as
|
||||
*
|
||||
* static constexpr <nonsimple-types> = <expression-treated-as-const>;
|
||||
*
|
||||
* The good news is that this allows the compiler to optimize out an
|
||||
* expression that is "promised" to be "evaluatable" as a constant.
|
||||
* The bad news is that it introduces a new language keyword, and the old
|
||||
* code raises an error.
|
||||
*
|
||||
* TODO: Evaluate the requirement for the "static" keyword.
|
||||
* TODO: Evaluate using a C++ version preprocessor symbol for the #if.
|
||||
*
|
||||
* The CONST_CLASS_DATA define will expand to the appropriate keywords.
|
||||
*
|
||||
*/
|
||||
|
||||
#if ARDUINO < 10606
|
||||
|
||||
#define CONST_CLASS_DATA static const
|
||||
|
||||
#else
|
||||
|
||||
#define CONST_CLASS_DATA static constexpr
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef GPS_FIX_CFG
|
||||
#define GPS_FIX_CFG
|
||||
|
||||
/**
|
||||
* Enable/disable the storage for the members of a fix.
|
||||
*
|
||||
* Disabling a member prevents it from being parsed from a received message.
|
||||
* The disabled member cannot be accessed or stored, and its validity flag
|
||||
* would not be available. It will not be declared, and code that uses that
|
||||
* member will not compile.
|
||||
*
|
||||
* DATE and TIME are somewhat coupled in that they share a single `time_t`,
|
||||
* but they have separate validity flags.
|
||||
*
|
||||
* See also note regarding the DOP members, below.
|
||||
*
|
||||
*/
|
||||
|
||||
//#define GPS_FIX_DATE
|
||||
//#define GPS_FIX_TIME
|
||||
//#define GPS_FIX_LOCATION
|
||||
//#define GPS_FIX_LOCATION_DMS
|
||||
//#define GPS_FIX_ALTITUDE
|
||||
#define GPS_FIX_SPEED
|
||||
//#define GPS_FIX_HEADING
|
||||
//#define GPS_FIX_SATELLITES
|
||||
//#define GPS_FIX_HDOP
|
||||
//#define GPS_FIX_VDOP
|
||||
//#define GPS_FIX_PDOP
|
||||
//#define GPS_FIX_LAT_ERR
|
||||
//#define GPS_FIX_LON_ERR
|
||||
//#define GPS_FIX_ALT_ERR
|
||||
//#define GPS_FIX_GEOID_HEIGHT
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,286 @@
|
||||
#ifndef NMEAGPS_CFG_H
|
||||
#define NMEAGPS_CFG_H
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable the parsing of specific sentences.
|
||||
//
|
||||
// Configuring out a sentence prevents it from being recognized; it
|
||||
// will be completely ignored. (See also NMEAGPS_RECOGNIZE_ALL, below)
|
||||
//
|
||||
// FYI: Only RMC and ZDA contain date information. Other
|
||||
// sentences contain time information. Both date and time are
|
||||
// required if you will be doing time_t-to-clock_t operations.
|
||||
|
||||
//#define NMEAGPS_PARSE_GGA
|
||||
//#define NMEAGPS_PARSE_GLL
|
||||
//#define NMEAGPS_PARSE_GSA
|
||||
//#define NMEAGPS_PARSE_GSV
|
||||
//#define NMEAGPS_PARSE_GST
|
||||
#define NMEAGPS_PARSE_RMC
|
||||
//#define NMEAGPS_PARSE_VTG
|
||||
//#define NMEAGPS_PARSE_ZDA
|
||||
|
||||
//------------------------------------------------------
|
||||
// Select which sentence is sent *last* by your GPS device
|
||||
// in each update interval. This can be used by your sketch
|
||||
// to determine when the GPS quiet time begins, and thus
|
||||
// when you can perform "some" time-consuming operations.
|
||||
|
||||
#define LAST_SENTENCE_IN_INTERVAL NMEAGPS::NMEA_RMC
|
||||
|
||||
// If the NMEA_LAST_SENTENCE_IN_INTERVAL is not chosen
|
||||
// correctly, GPS data may be lost because the sketch
|
||||
// takes too long elsewhere when this sentence is received.
|
||||
// Also, fix members may contain information from different
|
||||
// time intervals (i.e., they are not coherent).
|
||||
//
|
||||
// If you don't know which sentence is the last one,
|
||||
// use NMEAorder.ino to list them. You do not have to select
|
||||
// the last sentence the device sends if you have disabled
|
||||
// it. Just select the last sentence that you have *enabled*.
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/Disable coherency:
|
||||
//
|
||||
// If you need each fix to contain information that is only
|
||||
// from the current update interval, you should uncomment
|
||||
// this define. At the beginning of the next interval,
|
||||
// the accumulating fix will start out empty. When
|
||||
// the LAST_SENTENCE_IN_INTERVAL arrives, the valid
|
||||
// fields will be coherent.
|
||||
|
||||
//#define NMEAGPS_COHERENT
|
||||
|
||||
// With IMPLICIT merging, fix() will be emptied when the
|
||||
// next sentence begins.
|
||||
//
|
||||
// With EXPLICIT or NO merging, the fix() was already
|
||||
// being initialized.
|
||||
//
|
||||
// If you use the fix-oriented methods available() and read(),
|
||||
// they will empty the current fix for you automatically.
|
||||
//
|
||||
// If you use the character-oriented method decode(), you should
|
||||
// empty the accumulating fix by testing and clearing the
|
||||
// 'intervalComplete' flag in the same way that available() does.
|
||||
|
||||
//------------------------------------------------------
|
||||
// Choose how multiple sentences are merged:
|
||||
// 1) No merging
|
||||
// Each sentence fills out its own fix; there could be
|
||||
// multiple sentences per interval.
|
||||
// 2) EXPLICIT_MERGING
|
||||
// All sentences in an interval are *safely* merged into one fix.
|
||||
// NMEAGPS_FIX_MAX must be >= 1.
|
||||
// An interval is defined by NMEA_LAST_SENTENCE_IN_INTERVAL.
|
||||
// 3) IMPLICIT_MERGING
|
||||
// All sentences in an interval are merged into one fix, with
|
||||
// possible data loss. If a received sentence is rejected for
|
||||
// any reason (e.g., a checksum error), all the values are suspect.
|
||||
// The fix will be cleared; no members will be valid until new
|
||||
// sentences are received and accepted. This uses less RAM.
|
||||
// An interval is defined by NMEA_LAST_SENTENCE_IN_INTERVAL.
|
||||
// Uncomment zero or one:
|
||||
|
||||
#define NMEAGPS_EXPLICIT_MERGING
|
||||
//#define NMEAGPS_IMPLICIT_MERGING
|
||||
|
||||
#ifdef NMEAGPS_IMPLICIT_MERGING
|
||||
#define NMEAGPS_MERGING NMEAGPS::IMPLICIT_MERGING
|
||||
|
||||
// When accumulating, nothing is done to the fix at the
|
||||
// beginning of every sentence...
|
||||
#ifdef NMEAGPS_COHERENT
|
||||
// ...unless COHERENT is enabled and a new interval is starting
|
||||
#define NMEAGPS_INIT_FIX(m) \
|
||||
if (intervalComplete()) { intervalComplete( false ); m.valid.init(); }
|
||||
#else
|
||||
#define NMEAGPS_INIT_FIX(m)
|
||||
#endif
|
||||
|
||||
// ...but we invalidate one part when it starts to get parsed. It *may* get
|
||||
// validated when the parsing is finished.
|
||||
#define NMEAGPS_INVALIDATE(m) m_fix.valid.m = false
|
||||
|
||||
#else
|
||||
|
||||
#ifdef NMEAGPS_EXPLICIT_MERGING
|
||||
#define NMEAGPS_MERGING NMEAGPS::EXPLICIT_MERGING
|
||||
#else
|
||||
#define NMEAGPS_MERGING NMEAGPS::NO_MERGING
|
||||
#define NMEAGPS_NO_MERGING
|
||||
#endif
|
||||
|
||||
// When NOT accumulating, invalidate the entire fix at the
|
||||
// beginning of every sentence
|
||||
#define NMEAGPS_INIT_FIX(m) m.valid.init()
|
||||
|
||||
// ...so the individual parts do not need to be invalidated as they are parsed
|
||||
#define NMEAGPS_INVALIDATE(m)
|
||||
|
||||
#endif
|
||||
|
||||
#if ( defined(NMEAGPS_NO_MERGING) + \
|
||||
defined(NMEAGPS_IMPLICIT_MERGING) + \
|
||||
defined(NMEAGPS_EXPLICIT_MERGING) ) > 1
|
||||
#error Only one MERGING technique should be enabled in NMEAGPS_cfg.h!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Define the fix buffer size. The NMEAGPS object will hold on to
|
||||
// this many fixes before an overrun occurs. This can be zero,
|
||||
// but you have to be more careful about using gps.fix() structure,
|
||||
// because it will be modified as characters are received.
|
||||
|
||||
#define NMEAGPS_FIX_MAX 1
|
||||
|
||||
#if defined(NMEAGPS_EXPLICIT_MERGING) && (NMEAGPS_FIX_MAX == 0)
|
||||
#error You must define FIX_MAX >= 1 to allow EXPLICIT merging in NMEAGPS_cfg.h
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/Disable interrupt-style processing of GPS characters
|
||||
// If you are using one of the NeoXXSerial libraries,
|
||||
// to attachInterrupt, this must be defined.
|
||||
// Otherwise, it must be commented out.
|
||||
|
||||
//#define NMEAGPS_INTERRUPT_PROCESSING
|
||||
|
||||
#ifdef NMEAGPS_INTERRUPT_PROCESSING
|
||||
#define NMEAGPS_PROCESSING_STYLE NMEAGPS::PS_INTERRUPT
|
||||
#else
|
||||
#define NMEAGPS_PROCESSING_STYLE NMEAGPS::PS_POLLING
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable the talker ID, manufacturer ID and proprietary message processing.
|
||||
//
|
||||
// First, some background information. There are two kinds of NMEA sentences:
|
||||
//
|
||||
// 1. Standard NMEA sentences begin with "$ttccc", where
|
||||
// "tt" is the talker ID, and
|
||||
// "ccc" is the variable-length sentence type (i.e., command).
|
||||
//
|
||||
// For example, "$GPGLL,..." is a GLL sentence (Geographic Lat/Long)
|
||||
// transmitted by talker "GP". This is the most common talker ID. Some
|
||||
// devices may report "$GNGLL,..." when a mix of GPS and non-GPS
|
||||
// satellites have been used to determine the GLL data.
|
||||
//
|
||||
// 2. Proprietary NMEA sentences (i.e., those unique to a particular
|
||||
// manufacturer) begin with "$Pmmmccc", where
|
||||
// "P" is the NMEA-defined prefix indicator for proprietary messages,
|
||||
// "mmm" is the 3-character manufacturer ID, and
|
||||
// "ccc" is the variable-length sentence type (it can be empty).
|
||||
//
|
||||
// No validation of manufacturer ID and talker ID is performed in this
|
||||
// base class. For example, although "GP" is a common talker ID, it is not
|
||||
// guaranteed to be transmitted by your particular device, and it IS NOT
|
||||
// REQUIRED. If you need validation of these IDs, or you need to use the
|
||||
// extra information provided by some devices, you have two independent
|
||||
// options:
|
||||
//
|
||||
// 1. Enable SAVING the ID: When /decode/ returns DECODE_COMPLETED, the
|
||||
// /talker_id/ and/or /mfr_id/ members will contain ID bytes. The entire
|
||||
// sentence will be parsed, perhaps modifying members of /fix/. You should
|
||||
// enable one or both IDs if you want the information in all sentences *and*
|
||||
// you also want to know the ID bytes. This adds two bytes of RAM for the
|
||||
// talker ID, and 3 bytes of RAM for the manufacturer ID.
|
||||
//
|
||||
// 2. Enable PARSING the ID: The virtual /parse_talker_id/ and
|
||||
// /parse_mfr_id/ will receive each ID character as it is parsed. If it
|
||||
// is not a valid ID, return /false/ to abort processing the rest of the
|
||||
// sentence. No CPU time will be wasted on the invalid sentence, and no
|
||||
// /fix/ members will be modified. You should enable this if you want to
|
||||
// ignore some IDs. You must override /parse_talker_id/ and/or
|
||||
// /parse_mfr_id/ in a derived class.
|
||||
//
|
||||
|
||||
//#define NMEAGPS_SAVE_TALKER_ID
|
||||
//#define NMEAGPS_PARSE_TALKER_ID
|
||||
|
||||
//#define NMEAGPS_PARSE_PROPRIETARY
|
||||
#ifdef NMEAGPS_PARSE_PROPRIETARY
|
||||
//#define NMEAGPS_SAVE_MFR_ID
|
||||
#define NMEAGPS_PARSE_MFR_ID
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable tracking the current satellite array and,
|
||||
// optionally, all the info for each satellite.
|
||||
//
|
||||
|
||||
//#define NMEAGPS_PARSE_SATELLITES
|
||||
//#define NMEAGPS_PARSE_SATELLITE_INFO
|
||||
|
||||
#ifdef NMEAGPS_PARSE_SATELLITES
|
||||
#define NMEAGPS_MAX_SATELLITES (20)
|
||||
|
||||
#ifndef GPS_FIX_SATELLITES
|
||||
#error GPS_FIX_SATELLITES must be defined in GPSfix.h!
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(NMEAGPS_PARSE_SATELLITE_INFO) & \
|
||||
!defined(NMEAGPS_PARSE_SATELLITES)
|
||||
#error NMEAGPS_PARSE_SATELLITES must be defined!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Enable/disable gathering interface statistics:
|
||||
// CRC errors and number of sentences received
|
||||
|
||||
//#define NMEAGPS_STATS
|
||||
|
||||
//------------------------------------------------------
|
||||
// Configuration item for allowing derived types of NMEAGPS.
|
||||
// If you derive classes from NMEAGPS, you *must* define NMEAGPS_DERIVED_TYPES.
|
||||
// If not defined, virtuals are not used, with a slight size (2 bytes) and
|
||||
// execution time savings.
|
||||
|
||||
//#define NMEAGPS_DERIVED_TYPES
|
||||
|
||||
#ifdef NMEAGPS_DERIVED_TYPES
|
||||
#define NMEAGPS_VIRTUAL virtual
|
||||
#else
|
||||
#define NMEAGPS_VIRTUAL
|
||||
#endif
|
||||
|
||||
//-----------------------------------
|
||||
// See if DERIVED_TYPES is required
|
||||
#if (defined(NMEAGPS_PARSE_TALKER_ID) | defined(NMEAGPS_PARSE_MFR_ID)) & \
|
||||
!defined(NMEAGPS_DERIVED_TYPES)
|
||||
#error You must define NMEAGPS_DERIVED_TYPES in NMEAGPS.h in order to parse Talker and/or Mfr IDs!
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------
|
||||
// Some devices may omit trailing commas at the end of some
|
||||
// sentences. This may prevent the last field from being
|
||||
// parsed correctly, because the parser for some types keep
|
||||
// the value in an intermediate state until the complete
|
||||
// field is received (e.g., parseDDDMM, parseFloat and
|
||||
// parseZDA).
|
||||
//
|
||||
// Enabling this will inject a simulated comma when the end
|
||||
// of a sentence is received and the last field parser
|
||||
// indicated that it still needs one.
|
||||
|
||||
//#define NMEAGPS_COMMA_NEEDED
|
||||
|
||||
//------------------------------------------------------
|
||||
// Some applications may want to recognize a sentence type
|
||||
// without actually parsing any of the fields. Uncommenting
|
||||
// this define will allow the nmeaMessage member to be set
|
||||
// when *any* standard message is seen, even though that
|
||||
// message is not enabled by a NMEAGPS_PARSE_xxx define above.
|
||||
// No valid flags will be true for those sentences.
|
||||
|
||||
//#define NMEAGPS_RECOGNIZE_ALL
|
||||
|
||||
//------------------------------------------------------
|
||||
// Sometimes, a little extra space is needed to parse an intermediate form.
|
||||
// This config items enables extra space.
|
||||
|
||||
//#define NMEAGPS_PARSING_SCRATCHPAD
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
#ifndef NEOGPS_CFG
|
||||
#define NEOGPS_CFG
|
||||
|
||||
/**
|
||||
* Enable/disable packed data structures.
|
||||
*
|
||||
* Enabling packed data structures will use two less-portable language
|
||||
* features of GCC to reduce RAM requirements. Although it was expected to slightly increase execution time and code size, the reverse is true on 8-bit AVRs: the code is smaller and faster with packing enabled.
|
||||
*
|
||||
* Disabling packed data structures will be very portable to other
|
||||
* platforms. NeoGPS configurations will use slightly more RAM, and on
|
||||
* 8-bit AVRs, the speed is slightly slower, and the code is slightly
|
||||
* larger. There may be no choice but to disable packing on processors
|
||||
* that do not support packed structures.
|
||||
*
|
||||
* There may also be compiler-specific switches that affect packing and the
|
||||
* code which accesses packed members. YMMV.
|
||||
**/
|
||||
|
||||
#ifdef __AVR__
|
||||
#define NEOGPS_PACKED_DATA
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Based on the above define, choose which set of packing macros should
|
||||
// be used in the rest of the NeoGPS package. Do not change these defines.
|
||||
|
||||
#ifdef NEOGPS_PACKED_DATA
|
||||
|
||||
// This is for specifying the number of bits to be used for a
|
||||
// member of a struct. Booleans are typically one bit.
|
||||
#define NEOGPS_BF(b) :b
|
||||
|
||||
// This is for requesting the compiler to pack the struct or class members
|
||||
// "as closely as possible". This is a compiler-dependent interpretation.
|
||||
#define NEOGPS_PACKED __attribute__((packed))
|
||||
|
||||
#else
|
||||
|
||||
// Let the compiler do whatever it wants.
|
||||
|
||||
#define NEOGPS_PACKED
|
||||
#define NEOGPS_BF(b)
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Accommodate C++ compiler and IDE changes.
|
||||
*
|
||||
* Declaring constants as class data instead of instance data helps avoid
|
||||
* collisions with #define names, and allows the compiler to perform more
|
||||
* checks on their usage.
|
||||
*
|
||||
* Until C++ 10 and IDE 1.6.8, initialized class data constants
|
||||
* were declared like this:
|
||||
*
|
||||
* static const <valued types> = <constant-value>;
|
||||
*
|
||||
* Now, non-simple types (e.g., float) must be declared as
|
||||
*
|
||||
* static constexpr <nonsimple-types> = <expression-treated-as-const>;
|
||||
*
|
||||
* The good news is that this allows the compiler to optimize out an
|
||||
* expression that is "promised" to be "evaluatable" as a constant.
|
||||
* The bad news is that it introduces a new language keyword, and the old
|
||||
* code raises an error.
|
||||
*
|
||||
* TODO: Evaluate the requirement for the "static" keyword.
|
||||
* TODO: Evaluate using a C++ version preprocessor symbol for the #if.
|
||||
*
|
||||
* The CONST_CLASS_DATA define will expand to the appropriate keywords.
|
||||
*
|
||||
*/
|
||||
|
||||
#if ARDUINO < 10606
|
||||
|
||||
#define CONST_CLASS_DATA static const
|
||||
|
||||
#else
|
||||
|
||||
#define CONST_CLASS_DATA static constexpr
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
Acknowledgements
|
||||
==========
|
||||
Mikal Hart's [TinyGPS](https://github.com/mikalhart/TinyGPS) for the generic `decode` approach.
|
||||
|
||||
tht's [initial implementation](http://forum.arduino.cc/index.php?topic=150299.msg1863220#msg1863220) of a Cosa `IOStream::Device`.
|
||||
@@ -0,0 +1,64 @@
|
||||
Character-oriented methods
|
||||
===========================
|
||||
|
||||
Sometimes, individual characters or sentences must be processed or filtered, long before a fix structure is completed (i.e., `available()`). In this advanced technique, your sketch should read each character and pass it to the character-oriented method `gps.decode()`:
|
||||
```
|
||||
void loop()
|
||||
{
|
||||
while (serial.available()) {
|
||||
char c = serial.read();
|
||||
if (gps.decode( c ) == DECODE_COMPLETED) {
|
||||
... do something with gps.fix()...
|
||||
}
|
||||
```
|
||||
As `gps` decodes those bytes, it will gradually fill out the pieces of its internal fix structure, `gps.fix()` (members described [here](Data%20Model.md). When you want to use some of the fix data, you can access it like this:
|
||||
```
|
||||
Serial.print( gps.fix().latitude() );
|
||||
Serial.print( ',' );
|
||||
Serial.println( gps.fix().longitude() );
|
||||
```
|
||||
However, you must wait for the sentence to be completely decoded. You can't access `gps.fix()` unless you know that it is COMPLETED. You must copy it to another fix variable if you need to access it at any time.
|
||||
|
||||
**IMPORTANT:** `gps.fix()` **IS ONLY VALID WHEN:**
|
||||
- `gps.decode()` just returned `DECODE_COMPLETED`, or
|
||||
- `gps.is_safe()`
|
||||
|
||||
This is because `gps.fix().speed` may be half-formed. You must either do all your accessing immediately after `gps.decode()` returns `DECODE_COMPLETED`:
|
||||
```
|
||||
void loop()
|
||||
{
|
||||
// At this point of the code, speed could be half-decoded.
|
||||
if (gps.fix().speed <= 5) // NOT A GOOD IDEA!
|
||||
Serial.println( F("Too slow!") );
|
||||
|
||||
while (serial.available()) {
|
||||
char c = serial.read();
|
||||
if (gps.decode( serial.read() ) == NMEAGPS::DECODE_COMPLETED) {
|
||||
|
||||
// Access any piece of gps.fix() in here...
|
||||
|
||||
if (gps.fix().speed <= 5) // OK!
|
||||
Serial.println( F("Too slow!") );
|
||||
|
||||
if (gps.fix().lat ...
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
Or you must call `gps.is_safe()` before using `gps.fix()`. It is safest to copy `gps.fix()` into your own variable for use at any time:
|
||||
```
|
||||
gps_fix my_fix;
|
||||
|
||||
void loop()
|
||||
{
|
||||
while (serial.available()) {
|
||||
char c = serial.read();
|
||||
if (gps.decode( serial.read() ) == NMEAGPS::DECODE_COMPLETED) {
|
||||
my_fix = gps.fix(); // save for later...
|
||||
}
|
||||
}
|
||||
|
||||
if (my_fix.speed <= 5) // OK
|
||||
DigitalWrite( UNDERSPEED_INDICATOR, HIGH );
|
||||
```
|
||||
Although the character-oriented program structure gives you a finer granularity of control, you must be more careful when accessing `gps.fix()`.
|
||||
231
software/firmware/libraries/NeoGPS/extras/doc/Choosing.md
Normal file
231
software/firmware/libraries/NeoGPS/extras/doc/Choosing.md
Normal file
@@ -0,0 +1,231 @@
|
||||
# Choosing your configuration
|
||||
There are only a few configurations provided by examples. If your application needs something slightly different, here is a general configuration process.
|
||||
|
||||
## What number do you want?
|
||||
First, decide which data members of `gps_fix` and `NMEAGPS` you need (see [Data Model](Data Model.md) for member descriptions). Those members **must** be enabled in `GPSfix_cfg.h`.
|
||||
|
||||
Next, figure out what messages can fill out those members, because those messages **must** be enabled in `NMEAGPS_cfg.h`. Here is a table of the NMEA messages parsed by NeoGPS, and which data members they affect:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><p align="right"><b>Message</b></p><p><b>Data Member</b></p></td>
|
||||
<td><p>GGA</p><p><br></p></td>
|
||||
<td><p>GLL</p><p><br></p></td>
|
||||
<td><p>GSA</p><p><br></p></td>
|
||||
<td><p>GST</p><p><br></p></td>
|
||||
<td><p>GSV</p><p><br></p></td>
|
||||
<td><p>RMC</p><p><br></p></td>
|
||||
<td><p>VTG</p><p><br></p></td>
|
||||
<td><p>ZDA</p><p><br></p></td>
|
||||
<td><p align="center">PUBX<br>00<sup>1<sup></p><p><br></p></td>
|
||||
<td><p align="center">PUBX<br>04<sup>1<sup></p><p><br></p></td>
|
||||
</tr>
|
||||
<tr><td><p><b>class gps_fix</b></p></td></tr>
|
||||
<tr>
|
||||
<td><p align="right">status</p></td>
|
||||
<td>*</td>
|
||||
<td>*</td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p align="right">date<sup>2</sup></p></td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p align="right">time<sup>2</sup></p></td>
|
||||
<td>*</td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td>*</td>
|
||||
<td>*</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p align="right">lat/lon</p></td>
|
||||
<td>*</td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p align="right">altitude</p></td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p align="right">speed</p></td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p align="right">heading</p></td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p align="right">lat, lon, alt error</p></td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p align="right">satellites</p></td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p align="right">HDOP</p></td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p align="right">VDOP</p></td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p align="right">PDOP</p></td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p align="right">TDOP</p></td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr><td><p><b>class NMEAGPS</b></p></td></tr>
|
||||
<tr>
|
||||
<td><p align="right">satellite IDs</p></td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><p align="right">satellite azimuth,<br> elevation and<br> signal strength</p></td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>*</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
This table illustrates the poor design of the NMEA message set: it requires multiple messages to deliver a complete fix (i.e., all members of `gps_fix`). This also explains why many manufacturers provide proprietary messages that *are* more complete. Above, you can see that the `$PUBX,00`<sup>1</sup> message contains all members except `date`.
|
||||
|
||||
While the manufacturer's specification will document all sentences supported for your device, you can also find general descriptions of many NMEA sentences [here](http://www.gpsinformation.org/dale/nmea.htm), [here](http://aprs.gids.nl/nmea/) or [here](http://www.catb.org/gpsd/NMEA.txt).
|
||||
|
||||
<hr>
|
||||
|
||||
|
||||
<sub><sup>1</sup> The NMEA proprietary messages "PUBX" are only availble in the `ubloxNMEA` class. See [ublox-specific instructions](ublox.md) for adding this class to your configuration.</sub>
|
||||
|
||||
<sub><sup>2</sup> Date and time are both stored in one member of `gps_fix`, called `dateTime`. The `fix.dateTime` member is a C++ class that has both date-oriented members (Date, Month and Year) and time-oriented members (Hours, Minutes and Seconds). See [NeoTime.h](/src/NeoTime.h) for the complete description and capabilities of the `dateTime` member, such as date/time arithmetic and conversion to/from seconds since the epoch. Hundredths of a second are stored in a separate member of `gps_fix`, called `dateTime_cs`, and can also be accessed with the functions `dateTime_ms()` and `dateTime_us()`.</sub>
|
||||
13
software/firmware/libraries/NeoGPS/extras/doc/Coherency.md
Normal file
13
software/firmware/libraries/NeoGPS/extras/doc/Coherency.md
Normal file
@@ -0,0 +1,13 @@
|
||||
Coherency
|
||||
==========
|
||||
Coherency guarantees that all members of a fix are from the same GPS time. For example, lat/long members may have been set by the newest sentence, but the altitude may be from the previous time interval. Most applications do not care that the fix members are not coherent. However, if you are controlling a drone or other autonomous vehicle, you may need coherency.
|
||||
|
||||
NeoGPS achieves coherency by detecting the "quiet" time between batches of sentences. When new data starts coming in, the fix will get emptied or initialized, and all new sentences will be accumulated in the internal fix.
|
||||
|
||||
If coherency is desired, **you must choose the correct LAST_SENTENCE_IN_INTERVAL.** If you're not sure which sentence is sent last (and therefore, when the quiet time begins), use NMEAorder.ino to analyze your GPS device.
|
||||
|
||||
You must also use **EXPLICIT_MERGING**. Implicit merging cannot be used with coherency is because a sentence has to be parsed to know its timestamp. If it were implicitly merged, the old data would not have been invalidated. Invalidating data from a previous update period must be performed _before_ the sentence parsing begins. That can only be accomplished with a second 'safe' copy of the fix data and explicit merging (i.e., FIX_MAX >= 1). With implicit merging, new data has already been mixed with old data by the time DECODE_COMPLETED occurs and timestamps can be checked.
|
||||
|
||||
When you have correctly chosen the LAST_SENTENCE_IN_INTERVAL *and* EXPLICIT_MERGING, the fix-oriented methods `available` and `read()` will return a coherent fix.
|
||||
|
||||
NOTE: If you use the [character-oriented methods](CharOriented.md) `decode`, `is_safe` and `fix()` to handle individual sentences, you must check `intervalComplete()` to know when the GPS update interval is completed, and the GPS quiet time has started.
|
||||
260
software/firmware/libraries/NeoGPS/extras/doc/Configurations.md
Normal file
260
software/firmware/libraries/NeoGPS/extras/doc/Configurations.md
Normal file
@@ -0,0 +1,260 @@
|
||||
Configuration
|
||||
=============
|
||||
All configuration items are conditional compilations: a `#define` controls an `#if`/`#endif` section.
|
||||
Comment out any items to be disabled or excluded from your build.
|
||||
Where possible, checks are performed to verify that you have chosen a "valid"
|
||||
configuration: you may see `#error` messages in the build log. See also [Choosing Your Configuration](Choosing.md) and [Troubleshooting](Troubleshooting.md).
|
||||
|
||||
# class gps_fix
|
||||
The following configuration items are near the top of GPSfix_cfg.h:
|
||||
```
|
||||
// Enable/Disable individual parts of a fix, as parsed from fields of a $GPxxx sentence
|
||||
#define GPS_FIX_DATE
|
||||
#define GPS_FIX_TIME
|
||||
#define GPS_FIX_LOCATION
|
||||
#define GPS_FIX_LOCATION_DMS
|
||||
#define GPS_FIX_ALTITUDE
|
||||
#define GPS_FIX_SPEED
|
||||
#define GPS_FIX_HEADING
|
||||
#define GPS_FIX_SATELLITES
|
||||
#define GPS_FIX_HDOP
|
||||
#define GPS_FIX_VDOP
|
||||
#define GPS_FIX_PDOP
|
||||
#define GPS_FIX_LAT_ERR
|
||||
#define GPS_FIX_LON_ERR
|
||||
#define GPS_FIX_ALT_ERR
|
||||
#define GPS_FIX_GEOID_HEIGHT
|
||||
```
|
||||
See the [Data Model](Data%20Model.md) page and `GPSfix.h` for the corresponding members that are enabled or disabled by these defines.
|
||||
|
||||
========================
|
||||
# class NMEAGPS
|
||||
The following configuration items are near the top of NMEAGPS_cfg.h.
|
||||
#### Enable/Disable parsing the fields of a $GPxxx sentence
|
||||
```
|
||||
#define NMEAGPS_PARSE_GGA
|
||||
#define NMEAGPS_PARSE_GLL
|
||||
#define NMEAGPS_PARSE_GSA
|
||||
#define NMEAGPS_PARSE_GSV
|
||||
#define NMEAGPS_PARSE_GST
|
||||
#define NMEAGPS_PARSE_RMC
|
||||
#define NMEAGPS_PARSE_VTG
|
||||
#define NMEAGPS_PARSE_ZDA
|
||||
```
|
||||
#### Select the last sentence in an update interval
|
||||
This is used to determine when the GPS quiet time begins and when a batch of coherent sentences have been merged. It is crucial to know when fixes can be marked as available, and when you can perform some time-consuming operations.
|
||||
```
|
||||
#define LAST_SENTENCE_IN_INTERVAL NMEAGPS::NMEA_GLL
|
||||
```
|
||||
You can use `NMEAorder.ino` to determine the last sentence sent by your device.
|
||||
#### Enable/Disable No, Implicit, Explicit Merging
|
||||
If you want NO merging, comment out both defines. Otherwise, uncomment the IMPLICIT or EXPLICIT define.
|
||||
```
|
||||
#define NMEAGPS_EXPLICIT_MERGING
|
||||
//#define NMEAGPS_IMPLICIT_MERGING
|
||||
```
|
||||
See [Merging](Merging.md) for more information.
|
||||
#### Define the fix buffer size.
|
||||
The NMEAGPS object will hold on to this many fixes before an overrun occurs. The buffered fixes can be obtained by calling `gps.read()`. You can specify zero, but you have to be sure to call `gps.read()` before the next sentence starts.
|
||||
```
|
||||
#define NMEAGPS_FIX_MAX 1
|
||||
```
|
||||
#### Enable/Disable interrupt-style processing
|
||||
Define how fixes are dropped when the fix buffer is full.
|
||||
```
|
||||
#define NMEAGPS_KEEP_NEWEST_FIXES true
|
||||
```
|
||||
true = the oldest fix will be dropped, and the new fix will be saved.
|
||||
false = the new fix will be dropped, and all old fixes will be saved.
|
||||
#### Enable/Disable interrupt-style processing
|
||||
If you are using one of the NeoXXSerial libraries to `attachInterrupt`, this must be uncommented to guarantee safe access to the buffered fixes with `gps.read()`. For normal polling-style processing, it must be commented out.
|
||||
```
|
||||
//#define NMEAGPS_INTERRUPT_PROCESSING
|
||||
```
|
||||
#### Enable/Disable the talker ID and manufacturer ID processing.
|
||||
There are two kinds of NMEA sentences:
|
||||
|
||||
1. Standard NMEA sentences begin with "$ttccc", where
|
||||
"tt" is the talker ID (e.g., GP), and
|
||||
"ccc" is the variable-length sentence type (e.g., RMC).
|
||||
|
||||
For example, "$GPGLL,..." is a GLL sentence (Geographic Lat/Long)
|
||||
transmitted by talker "GP". This is the most common talker ID. Some devices
|
||||
may report "$GNGLL,..." when a mix of GPS and non-GPS satellites have been
|
||||
used to determine the GLL data (e.g., GLONASS+GPS).
|
||||
|
||||
2. Proprietary NMEA sentences (i.e., those unique to a particular manufacturer)
|
||||
begin with "$Pmmmccc", where
|
||||
"P" is the NMEA-defined prefix indicator for proprietary messages,
|
||||
"mmm" is the 3-character manufacturer ID, and
|
||||
"ccc" is the variable-length sentence type (it can be empty).
|
||||
|
||||
No validation of manufacturer ID and talker ID is performed in this
|
||||
base class. For example, although "GP" is a common talker ID, it is not
|
||||
guaranteed to be transmitted by your particular device, and it IS NOT REQUIRED.
|
||||
If you need validation of these IDs, or you need to use the extra information
|
||||
provided by some devices, you have two independent options:
|
||||
|
||||
1. Enable SAVING the ID: When `decode` returns DECODE_COMPLETED, the `talker_id`
|
||||
and/or `mfr_id` members will contain ID bytes. The entire sentence will be
|
||||
parsed, perhaps modifying members of `fix`. You should enable one or both IDs
|
||||
if you want the information in all sentences *and* you also want to know the ID
|
||||
bytes. This adds 2 bytes of RAM for the talker ID, and 3 bytes of RAM for the
|
||||
manufacturer ID.
|
||||
|
||||
2. Enable PARSING the ID: The virtual `parse_talker_id` and `parse_mfr_id` will
|
||||
receive each ID character as it is received. If it is not a valid ID, return
|
||||
`false` to abort processing the rest of the sentence. No CPU time will be wasted
|
||||
on the invalid sentence, and no `fix` members will be modified. You should
|
||||
enable this if you want to ignore some IDs. You must override `parse_talker_id`
|
||||
and/or `parse_mfr_id` in a derived class.
|
||||
|
||||
```
|
||||
#define NMEAGPS_SAVE_TALKER_ID
|
||||
#define NMEAGPS_PARSE_TALKER_ID
|
||||
|
||||
#define NMEAGPS_SAVE_MFR_ID
|
||||
#define NMEAGPS_PARSE_MFR_ID
|
||||
```
|
||||
#### Enable/Disable parsing of NMEA proprietary messages
|
||||
If you are deriving a class from NMEAGPS to parse proprietary messages, you must uncomment this define:
|
||||
```
|
||||
//#define NMEAGPS_PARSE_PROPRIETARY
|
||||
```
|
||||
#### Enable/Disable tracking the current satellite array
|
||||
You can also enable tracking the detailed information for each satellite, and how many satellites you want to track.
|
||||
Although many GPS receivers claim to have 66 channels of tracking, 16 is usually the maximum number of satellites
|
||||
tracked at any one time.
|
||||
```
|
||||
#define NMEAGPS_PARSE_SATELLITES
|
||||
#define NMEAGPS_PARSE_SATELLITE_INFO
|
||||
#define NMEAGPS_MAX_SATELLITES (20)
|
||||
```
|
||||
#### Enable/disable gathering interface statistics:
|
||||
Uncommenting this define will allow counting the number of sentences and characters received and the number of checksum (CS) errors. If the CS errors are increasing, you could be losing characters or the connection could be noisy.
|
||||
```
|
||||
#define NMEAGPS_STATS
|
||||
```
|
||||
#### Enable/disable UTC sub-second resolution
|
||||
|
||||
Fixes will be received at approximately 1-second intervals, but there can
|
||||
be 30ms *or more* of variance in those intervals. If you need to know the exact UTC time at *any* time,
|
||||
with sub-second accuracy, you must calculate the
|
||||
offset between the Arduino micros() clock and the UTC time in a received fix.
|
||||
There are two ways to do this:
|
||||
|
||||
**1. When the GPS quiet time ends and the new update interval begins.**
|
||||
|
||||
The timestamp will be set when the first character (the '$') of
|
||||
the new batch of sentences arrives from the GPS device. This is fairly
|
||||
accurate, but it will be delayed from the PPS edge by the GPS device's
|
||||
fix calculation time (usually ~100us). There is very little variance
|
||||
in this calculation time (usually < 30us), so all timestamps are
|
||||
delayed by a nearly-constant amount.
|
||||
```
|
||||
#define NMEAGPS_TIMESTAMP_FROM_INTERVAL
|
||||
```
|
||||
NOTE: At update rates higher than 1Hz, the updates may arrive with
|
||||
some increasing variance.
|
||||
|
||||
**2. From the PPS pin of the GPS module.**
|
||||
|
||||
It is up to the application developer to decide how to capture that event. For example, you could:
|
||||
|
||||
a) simply poll for it in loop and call UTCsecondStart(micros());
|
||||
|
||||
b) use attachInterrupt to call a Pin Change Interrupt ISR to save
|
||||
the micros() at the time of the interrupt (see NMEAGPS.h), or
|
||||
|
||||
c) connect the PPS to an Input Capture pin. Set the
|
||||
associated TIMER frequency, calculate the elapsed time
|
||||
since the PPS edge, and add that to the current micros().
|
||||
```
|
||||
#define NMEAGPS_TIMESTAMP_FROM_PPS
|
||||
```
|
||||
#### Enable/Disable derived types
|
||||
Although normally disabled, this must be enabled if you derive any classes from NMEAGPS.
|
||||
```
|
||||
//#define NMEAGPS_DERIVED_TYPES
|
||||
```
|
||||
|
||||
The ublox-specific files require this define (see [ublox](ublox.md) section).
|
||||
#### Enable/Disable guaranteed comma field separator
|
||||
Some devices may omit trailing commas at the end of some sentences. This may prevent the last field from being parsed correctly, because the parser for some types keep the value in an intermediate state until the complete field is received (e.g., parseDDDMM, parseFloat and parseZDA).
|
||||
|
||||
Enabling this will inject a simulated comma when the end of a sentence is received and the last field parser indicated that it still needs one.
|
||||
```
|
||||
//#define NMEAGPS_COMMA_NEEDED
|
||||
```
|
||||
#### Enable/Disable recognizing all sentence types
|
||||
Some applications may want to recognize a sentence type without actually parsing any of the fields. Uncommenting this define will allow the `gps.nmeaMessage` member to be set when *any* standard message is seen, even though that message is not enabled by a `#defineNMEAGPS_PARSE_xxx`. No valid flags will be true for disabled sentences.
|
||||
```
|
||||
#define NMEAGPS_RECOGNIZE_ALL
|
||||
```
|
||||
#### Enable/Disable parsing scratchpad
|
||||
Sometimes, a little extra space is needed to parse an intermediate form. This define enables extra space. Parsers that require the scratchpad can either `#ifdef` an `#error` when the scratchpad is disabled, or let the compiler generate an error when attempting to use the `scratchpad` union (see NMEAGPS.h).
|
||||
```
|
||||
//#define NMEAGPS_PARSING_SCRATCHPAD
|
||||
```
|
||||
|
||||
========================
|
||||
# ublox-specific configuration items
|
||||
|
||||
See the [ublox](ublox.md) section.
|
||||
|
||||
========================
|
||||
# Floating-point output.
|
||||
Streamers.cpp is used by the example programs for printing members of `fix()`. It is not required for parsing the GPS data stream, and this file may be deleted. It is an example of checking validity flags and formatting the various members of `fix()` for textual streams (e.g., Serial prints or SD writes).
|
||||
|
||||
Streamers.cpp has one configuration item:
|
||||
```
|
||||
#define USE_FLOAT
|
||||
```
|
||||
This is local to this file, and is only used by the example programs. This file is _not_ required unless you need to stream one of these types: bool, char, uint8_t, int16_t, uint16_t, int32_t, uint32_t, F() strings, `gps_fix` or `NMEAGPS`.
|
||||
|
||||
Most example programs have a choice for displaying fix information once per day. (Untested!)
|
||||
```
|
||||
#define PULSE_PER_DAY
|
||||
```
|
||||
========================
|
||||
# Platforms
|
||||
The following configuration items are near the top of NeoGPS_cfg.h.
|
||||
#### Enable/Disable packed bitfields
|
||||
```
|
||||
#define NEOGPS_PACKED_DATA
|
||||
```
|
||||
8-bit Arduino platforms can address memory by bytes or words. This allows passing data by reference or
|
||||
address, as long as it is one or more bytes in length. The `gps_fix` class has some members which are
|
||||
only one bit; these members cannot be passed by reference or address, only by value. NeoGPS uses an
|
||||
appropriate passing technique, depending on the size of these members.
|
||||
|
||||
32-bit Arduino platforms require *all* memory accesses to be 32-bit aligned, which precludes passing
|
||||
bitfield, byte, or word members by reference or address. Rather than penalize the 8-bit platforms with
|
||||
unpacked classes and structs, the `NEOGPS_PACKED_DATA` can be disabled on 32-bit platforms. This
|
||||
increases the RAM requirements, but these platforms typically have more available RAM.
|
||||
|
||||
========================
|
||||
# Typical configurations
|
||||
A few common configurations are defined as follows
|
||||
|
||||
**Minimal**: no fix members, no messages (pulse-per-second only)
|
||||
|
||||
**DTL**: date, time, lat/lon, GPRMC messsage only.
|
||||
|
||||
**Nominal**: date, time, lat/lon, altitude, speed, heading, number of
|
||||
satellites, HDOP, GPRMC and GPGGA messages.
|
||||
|
||||
**Full**: Nominal plus talker ID, VDOP, PDOP, lat/lon/alt errors, satellite array with satellite info, all messages, and parser statistics.
|
||||
|
||||
**PUBX**: Nominal fix items, standard sentences _disabled_, proprietary sentences PUBX 00 and 04 enabled, and required PARSE_MFR_ID and DERIVED_TYPES
|
||||
|
||||
These configurations are available in the [configs](/extras/configs) subdirectory.
|
||||
|
||||
========================
|
||||
# Configurations of other libraries
|
||||
|
||||
**TinyGPS** uses the **Nominal** configuration + a second `fix`.
|
||||
|
||||
**TinyGPSPlus** uses the **Nominal** configuration + statistics + a second fix + timestamps for each `fix` member.
|
||||
|
||||
**Adafruit_GPS** uses the **Nominal** configuration + geoid height and IGNORES CHECKSUM!
|
||||
253
software/firmware/libraries/NeoGPS/extras/doc/Data Model.md
Normal file
253
software/firmware/libraries/NeoGPS/extras/doc/Data Model.md
Normal file
@@ -0,0 +1,253 @@
|
||||
Data Model
|
||||
==========
|
||||
Rather than holding onto individual fields, the concept of a **fix** is used to group data members of the GPS acquisition into a C structure (a `struct` type called `gps_fix`). This also facilitates merging pieces received at different times (i.e., in separate sentences) into a single easy-to-use structure.
|
||||
|
||||
The main `NMEAGPS gps;` object you declare in your sketch parses received characters, gradually assembling a `fix`. Most programs will call `gps.read()` to obtain the completed fix structure (see [Usage](#Usage) below).
|
||||
|
||||
Given a variable declaration of type `gps_fix`:
|
||||
```
|
||||
gps_fix fix;
|
||||
```
|
||||
...this `fix` variable (or any other variable of type `gps_fix`) contains the following members:
|
||||
* `fix.status`, a status code
|
||||
* `enum` values STATUS_NONE, STATUS_EST, STATUS_TIME_ONLY, STATUS_STD or STATUS_DGPS
|
||||
* a [location](Location.md) structure (i.e., latitude and longitude), accessed with
|
||||
* `fix.latitudeL()` and `fix.longitudeL()` for the higher-precision integer degrees, scaled by 10,000,000 (10 significant digits)
|
||||
* `fix.latitude()` and `fix.longitude()` for the lower-precision floating-point degrees (~7 significant digits)
|
||||
* NOTE: these lat/lon values are
|
||||
* positive for North or East degrees and negative for South or West degrees.
|
||||
* stored in a 'fix.location' structure, like a 2D coordinate. The `location_t` class provides additional methods for distance, bearing and offset calculations, as described [here](Location.md).
|
||||
* `fix.latitudeDMS` and `fix.latitudeDMS` are structures (see DMS.h) that each contain
|
||||
* `fix.longitudeDMS.degrees` in integer degrees
|
||||
* `fix.latitudeDMS.degrees`, in integer minutes
|
||||
* `fix.longitudeDMS.seconds_whole`, in integer seconds
|
||||
* `fix.latitudeDMS.seconds_frac`, in integer thousandths of a second
|
||||
* `fix.latitudeDMS.secondsF()`, in floating-point seconds
|
||||
* hemisphere indicator, accessed with
|
||||
* `fix.longitudeDMS.hemisphere` (enum values NORTH_H, SOUTH_H, EAST_H or WEST_H)
|
||||
* `fix.longitudeDMS.EW()` (char values `E` or `W`)
|
||||
* `fix.latitudeDMS.NS()` (char values `N` or `S`)
|
||||
* NOTE: An integer degree value (scaled by 10<sup>7</sup> can be used to set the DMS structure by using `fix.latitudeDMS.From( otherLatitude );`
|
||||
* an altitude (above ellipsoid, not Mean Sea Level), accessed with
|
||||
* `fix.altitude_cm()`, in integer centimeters
|
||||
* `fix.altitude()`, in floating-point meters
|
||||
* `fix.alt.whole`, in integer meters
|
||||
* `fix.alt.frac`, in integer centimeters, to be added to the whole part
|
||||
* a speed, accessed with
|
||||
* `fix.speed_kph()`, in floating-point kilometers per hour
|
||||
* `fix.speed_mph()`, in floating-point miles per hour
|
||||
* `fix.speed()`, in floating-point knots (nautical miles per hour)
|
||||
* `fix.speed_mkn()`, in integer knots, scaled by 1000
|
||||
* `fix.spd.whole`, in integer knots
|
||||
* `fix.spd.frac`, in integer thousandths of a knot, to be added to the whole part
|
||||
* a heading, accessed with
|
||||
* `fix.heading_cd()`, in integer hundredths of a degree
|
||||
* `fix.heading()`, in floating-point degrees
|
||||
* `fix.hdop`, `fix.vdop` and `fix.pdop`, in integer thousandths of the DOP.
|
||||
* [Dilution of Precision](https://en.wikipedia.org/wiki/Dilution_of_precision_(navigation)) is a unitless measure of the current satellite constellation geometry WRT how 'good' it is for determining a position. This is _independent_ of signal strength and many other factors that may be internal to the receiver. **It cannot be used to determine position accuracy in meters.** Instead, use the LAT/LON/ALT error in cm members, which are populated by GST sentences.
|
||||
* latitude, longitude and altitude error, accessed with
|
||||
* `fix.lat_err_cm`, `fix.lon_err_cm` and `fix.alt_err_cm`, in integer centimeters
|
||||
* `fix.lat_err()`, `fix.lon_err()` and `fix.alt_err()`, in floating-point meters
|
||||
* geoid height above ellipsoid (see [here](https://en.wikipedia.org/wiki/Geoid) for description), accessed with
|
||||
* `fix.geoidHeight_cm`, in integer centimeters
|
||||
* `fix.geoidHeight()`, in floating-point meters
|
||||
* `fix.geoidHt.whole`, in integer meters
|
||||
* `fix.geoidHt.frac`, in integer centimeters to be added to the whole part
|
||||
* `fix.satellites`, a satellite count
|
||||
* a date/time structure (see [Time.h](/src/Time.h)), accessed with
|
||||
* `fix.dateTime.year`,
|
||||
* `fix.dateTime.month`,
|
||||
* `fix.dateTime.date`, the day-of-month,
|
||||
* `fix.dateTime.hours`,
|
||||
* `fix.dateTime.minutes`,
|
||||
* `fix.dateTime.seconds`, and
|
||||
* `fix.dateTime.day`, the day-of-the-week. This member is expensive to calculate, so it is *uninitialized* until you call the `set_day()` method. If you need the day-of-the-week, be sure to call `set_day` whenever the `year`, `month` or `date` members are changed. In general, call `fix.dateTime.set_day()` whenever `fix` is assigned (e.g., `fix = gps.read()`).<br><br>
|
||||
`Time` operations allow converting to and from total seconds offset from a *de facto* starting time (e.g., an epoch date/time "origin"). There are constants in Time.h for NTP, POSIX and Y2K epochs. Simply change the `static` members `s_epoch_year` and `s_epoch_weekday` in Time.h, and all date/time operations will be based on that epoch. This does not affect GPS times, but it will allow you to easily convert a GPS time to/from an NTP or POSIX time value (seconds).<br><br>
|
||||
The [NMEAtimezone.ino](/examples/NMEAtimezone/NMEAtimezone.ino) example program shows how to convert the GPS time (UTC) into a local time. Basically, a `Time` structure is converted to seconds (from the epoch start), then the time zone offset *in seconds* is added, and then the offset seconds are converted back to a time structure, with corrected day, month, year, hours and minutes members.
|
||||
* `fix.dateTime_cs`, in integer hundredths of a second
|
||||
* `fix.dateTime_ms()`, in milliseconds
|
||||
* `fix.dateTime_us()`, in microseconds
|
||||
* a collection of boolean `valid` flags for each of the above members, accessed with
|
||||
* `fix.valid.status`
|
||||
* `fix.valid.date` for year, month, day-of-month
|
||||
* `fix.valid.time` for hours, minutes, seconds and centiseconds
|
||||
* `fix.valid.location` for latitude and longitude
|
||||
* `fix.valid.altitude`
|
||||
* `fix.valid.speed`
|
||||
* `fix.valid.heading`
|
||||
* `fix.valid.hdop`, `fix.valid.vdop` and `fix.valid.hpop`
|
||||
* `fix.valid.lat_err`, `fix.valid.lon_err` and `fix.valid.alt_err`
|
||||
* `fix.valid.geoidHeight`
|
||||
|
||||
## Validity
|
||||
Because the GPS device may *not* have a fix, each member of a `gps_fix` can be marked as valid or invalid. That is, the GPS device may not know the lat/long yet. To check whether the fix member has been received, test the corresponding `valid` flag (described above). For example, to check if lat/long data has been received:
|
||||
```
|
||||
if (my_fix.valid.location) {
|
||||
Serial.print( my_fix.latitude() );
|
||||
Serial.print( ',' );
|
||||
Serial.println( my_fix.longitude() );
|
||||
}
|
||||
```
|
||||
You should also know that, even though you have enabled a particular member (see [GPSfix_cfg.h](/src/GPSfix_cfg.h)), it **may not have a value** until the related NMEA sentence sets it. And if you have not enabled that sentence for parsing in `NMEAGPS_cfg.h`, it will **never** be valid.
|
||||
|
||||
## Other GPS-related information
|
||||
There is additional information that is not related to a fix. Instead, it contains information about parsing or a [**G**lobal **N**avigation **S**atellite **S**ystem](https://en.wikipedia.org/wiki/Satellite_navigation). GNSS's currently include GPS (US), GLONASS (Russia), Beidou (China) and Galileo (EU). The main `NMEAGPS gps` object you declare in your sketch contains:
|
||||
* `gps.UTCsecondStart()`, the Arduino `micros()` value when the current UTC second started
|
||||
* `gps.UTCms()`, the number of milliseconds since the last received UTC time, calculated from `micros()` and `gps.UTCsecondStart`.
|
||||
* `gps.UTCus()`, the number of microseconds since the last received UTC time, calculated from `micros()` and `gps.UTCsecondStart`.
|
||||
* `gps.nmeaMessage`, the latest received message type. This is an ephemeral value, because multiple sentences are merged into one `fix` structure. If you only check this after a complete fix is received, you will only see the LAST_SENTENCE_IN_INTERVAL.
|
||||
* enum values NMEA_GLL, NMEA_GSA, NMEA_GST, NMEA_GSV, NMEA_RMC, NMEA_VTG or NMEA_ZDA
|
||||
* `gps.satellies[]`, an array of satellite-specific information, where each element contains
|
||||
* `gps.satellies[i].id`, satellite ID
|
||||
* `gps.satellies[i].elevation`, satellite elevation in 0-90 integer degrees
|
||||
* `gps.satellies[i].azimuth`, satellite azimuth in 0-359 integer degrees
|
||||
* `gps.satellies[i].snr`, satellite signal-to-noise ratio in 0-99 integer dBHz
|
||||
* `gps.satellies[i].tracked`, satellite being tracked flag, a boolean
|
||||
* `gps.talker_id[]`, talker ID, a two-character array (not NUL-terminated)
|
||||
* `gps.mfr_id[]`, manufacturer ID, a three-character array (not NUL-terminated)
|
||||
* an internal fix structure, `gps.fix()`. Most sketches **should not** use `gps.fix()` directly!
|
||||
|
||||
## Usage
|
||||
First, declare an instance of `NMEAGPS`:
|
||||
```
|
||||
NMEAGPS gps;
|
||||
```
|
||||
Next, tell the `gps` object to handle any available characters on the serial port:
|
||||
```
|
||||
void loop()
|
||||
{
|
||||
while (gps.available( gps_port )) {
|
||||
```
|
||||
The `gps` object will check if there are any characters available, and if so, read them from the port and parse them into its internal fix. Many characters will have to be read before the current fix is complete, so `gps.available` will return `false` until the fix is complete; the body of `while` loop will be skipped many times, and the rest of `loop()` will be executed.
|
||||
|
||||
When a fix is finally completed, `gps.available` will return `true`. Now your sketch can "read" the completed fix structure from the `gps` object:
|
||||
```
|
||||
void loop()
|
||||
{
|
||||
while (gps.available( gps_port )) {
|
||||
gps_fix fix = gps.read();
|
||||
```
|
||||
The local `fix` variable now contains all the GPS fields that were parsed from the `gps_port`. You can access them as described above:
|
||||
```
|
||||
void loop()
|
||||
{
|
||||
while (gps.available( gps_port )) {
|
||||
gps_fix fix = gps.read();
|
||||
if (fix.valid.time) {
|
||||
...
|
||||
```
|
||||
Note that the `fix` variable is local to that `while` loop; it cannot be accessed elsewhere in your sketch. If you need to access the fix information elsewhere, you must declare a global fix variable:
|
||||
```
|
||||
gps_fix currentFix;
|
||||
|
||||
void loop()
|
||||
{
|
||||
while (gps.available( gps_port )) {
|
||||
currentFix = gps.read();
|
||||
if (currentFix.valid.time) {
|
||||
...
|
||||
```
|
||||
Any part of your sketch can use the information in `currentFix`.
|
||||
|
||||
Please note that the fix structure is much smaller than the raw character data (sentences). A fix is nominally 1/4 the size of one sentence (~30 bytes vs ~120 bytes). If two sentences are sent during each update interval, a fix could be 1/8 the size required for buffering two sentences.
|
||||
|
||||
In this fix-oriented program structure, the methods `gps.available` and `gps.read` are manipulating entire `gps_fix` structures. Multiple characters and sentences are used internally to fill out a single fix: members are "merged" from sentences into one fix structure (described [here](Merging.md)).
|
||||
|
||||
That program structure is very similar to the typical serial port reading loop:
|
||||
```
|
||||
void loop()
|
||||
{
|
||||
while (serial.available()) {
|
||||
char c = serial.read();
|
||||
... do something with the character ...;
|
||||
}
|
||||
```
|
||||
However, the fix-oriented methods operate on complete *fixes*, not individual characters, fields or sentences.
|
||||
|
||||
Note: If you find that you need to filter or merge data with a finer level of control, you may need to use a different [Merging option](Merging.md), [Coherency](Coherency.md), or the more-advanced [Character-Oriented methods](/doc/CharOriented.md).
|
||||
|
||||
## Examples
|
||||
Some examples of accessing fix values:
|
||||
```
|
||||
gps_fix fix_copy = gps.read();
|
||||
|
||||
int32_t lat_10e7 = fix_copy.lat; // scaled integer value of latitude
|
||||
float lat = fix_copy.latitude(); // float value of latitude
|
||||
|
||||
Serial.print( fix_copy.latDMS.degrees );
|
||||
Serial.print( ' ' );
|
||||
Serial.print( fix_copy.latDMS.minutes );
|
||||
Serial.print( F("' " );
|
||||
Serial.print( fix_copy.latDMS.seconds );
|
||||
|
||||
if (fix_copy.dateTime.month == 4) // test for the cruelest month
|
||||
cry();
|
||||
|
||||
// Count how satellites are being received for each GNSS
|
||||
for (uint8_t i=0; i < gps.sat_count; i++) {
|
||||
if (gps.satellites[i].tracked) {
|
||||
if (gps.satellites[i] . id <= 32)
|
||||
GPS_satellites++;
|
||||
if (gps.satellites[i] . id <= 64)
|
||||
SBAS_satellites++;
|
||||
if (gps.satellites[i] . id <= 96)
|
||||
GLONASS_satellites++;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And some examples of accessing valid flags in a `fix` structure:
|
||||
```
|
||||
if (fix_copy.valid.location)
|
||||
// we have a lat/long!
|
||||
|
||||
if (fix_copy.valid.time)
|
||||
// the copy has hours, minutes and seconds
|
||||
```
|
||||
Here's an example for accessing the altitude
|
||||
```
|
||||
if (fix_copy.valid.altitude) {
|
||||
z2 = fix_copy.altitude_cm();
|
||||
vz = (z2 - z1) / dt;
|
||||
z1 = z2;
|
||||
|
||||
// Note: if you only care about meters, you could also do this:
|
||||
// z = fix_copy.alt.whole;
|
||||
}
|
||||
```
|
||||
You can also check a collection of flags before performing a calculation involving
|
||||
multiple members:
|
||||
```
|
||||
if (fix_copy.valid.altitude && fix_copy.valid.date && fix_copy.valid.time) {
|
||||
dt = (clock_t) fix_copy.dateTime - (clock_t) fix_copy.dateTime;
|
||||
dz = fix_copy.alt.whole - last_alt; // meters
|
||||
vz = dz / dt; // meters per second vertical velocity
|
||||
}
|
||||
```
|
||||
Bonus: The compiler will optimize this into a single bit mask operation.
|
||||
|
||||
The example printing utility file, [Streamers.cpp](/src/Streamers.cpp#L100) shows how to access each fix member and print its value.
|
||||
|
||||
## Options
|
||||
Except for `status`, each of these `gps_fix` members is conditionally compiled; any, all, or *no* members can be selected for parsing, storing and merging. This allows you to configuring NeoGPS to use the minimum amount of RAM for the particular members of interest. See [Configurations](Configurations.md) for how to edit [GPSfix_cfg.h](/src/GPSfix_cfg.h) and [NMEAGPS_cfg.h](/src/NMEAGPS_cfg.h#L67), respectively.
|
||||
|
||||
## Precision
|
||||
Integers are used for all members, retaining full precision of the original data.
|
||||
```
|
||||
gps_fix fix = gps.read();
|
||||
if (fix.valid.location) {
|
||||
// 32-bit ints have 10 significant digits, so you can detect very
|
||||
// small changes in position:
|
||||
d_lat = fix_copy.lat - last_lat;
|
||||
}
|
||||
```
|
||||
|
||||
Optional floating-point accessors are provided for many members.
|
||||
```
|
||||
if (fix_copy.valid.location) {
|
||||
float lat = fix_copy.latitude();
|
||||
|
||||
// floats only have about 6 significant digits, so this
|
||||
// computation is useless for detecting small movements:
|
||||
foobar = (lat - target_lat);
|
||||
```
|
||||
168
software/firmware/libraries/NeoGPS/extras/doc/Examples.md
Normal file
168
software/firmware/libraries/NeoGPS/extras/doc/Examples.md
Normal file
@@ -0,0 +1,168 @@
|
||||
Examples
|
||||
======
|
||||
In an attempt to be reusable in a variety of different programming styles, this library supports:
|
||||
* sync or async operation (main `loop()` vs interrupt processing)
|
||||
* fused or not fused (multiple reports into one fix)
|
||||
* optional buffering of fixes
|
||||
* optional floating point
|
||||
* configurable message sets, including hooks for implementing proprietary NMEA messages
|
||||
* configurable message fields
|
||||
* multiple protocols from same device
|
||||
|
||||
These example programs demonstrate how to use the classes in the different programming styles:
|
||||
* [NMEA](/examples/NMEA/NMEA.ino) - sync, single fix, standard NMEA only (RMC sentence only)
|
||||
* [NMEA_isr](/examples/NMEA_isr/NMEA_isr.ino) - **async**, single fix, standard NMEA only (RMC sentence only)
|
||||
* [NMEAblink](/examples/NMEAblink/NMEAblink.ino) - sync, single fix, standard NMEA only, minimal example, only blinks LED
|
||||
* [NMEAloc](/examples/NMEAloc/NMEAloc.ino) - sync, single fix, minimal example using only standard NMEA RMC sentence
|
||||
* [NMEAlocDMS](/examples/NMEAlocDMS/NMEAlocDMS.ino) - same as NMEAloc.ino, but displays location in Degrees, Minutes and Seconds
|
||||
* [NMEAaverage](/examples/NMEAaverage/NMEAaverage.ino) - sync, single fix, averages a high-accuracy location over time
|
||||
* [NMEAtimezone](/examples/NMEAtimezone/NMEAtimezone.ino) - same as NMEAloc.ino, but displays local time instead of UTC (GMT)
|
||||
* [NMEASDlog](/examples/NMEASDlog/NMEASDlog.ino) - **async**, buffered fixes, standard NMEA only (RMC sentence only), logging to SD card
|
||||
* [PUBX](/examples/PUBX/PUBX.ino) - sync, coherent fix, standard NMEA + ublox proprietary NMEA
|
||||
* [ublox](/examples/ublox/ublox.ino) - sync or **async**, coherent fix, ublox binary protocol UBX
|
||||
|
||||
Preprocessor symbol `USE_FLOAT` can be used in [Streamers.cpp](/src/Streamers.cpp) to select integer or floating-point output.
|
||||
|
||||
See also important information in `NMEAorder.ino` below, and the [Installing](Installing.md), [Configurations](Configurations.md) and [Troubleshooting](Troubleshooting.md) sections.
|
||||
|
||||
##Diagnostics
|
||||
Several programs are provided to help diagnose GPS device problems:
|
||||
|
||||
### Connection and Baud Rate
|
||||
|
||||
* [NMEAdiagnostic](/examples/NMEAdiagnostic/NMEAdiagnostic.ino)
|
||||
|
||||
This program listens for sentences and, if none are detected, tries a different baud rate. When sentences are detected, the correct baud rate is displayed. The received data may help you determine the problem (e.g., dropped characters or binary protocol).
|
||||
|
||||
See the [Troubleshooting](Troubleshooting.md) section for more details.
|
||||
|
||||
### Sentence order
|
||||
|
||||
* [NMEAorder](/examples/NMEAorder/NMEAorder.ino)
|
||||
|
||||
This program determines the order of NMEA sentences sent during each 1-second interval:
|
||||
|
||||
```
|
||||
NMEAorder.INO: started
|
||||
fix object size = 44
|
||||
NMEAGPS object size = 72
|
||||
Looking for GPS device on Serial1
|
||||
.....................
|
||||
Sentence order in each 1-second interval:
|
||||
RMC
|
||||
VTG
|
||||
GGA
|
||||
GSA
|
||||
GSV
|
||||
GSV
|
||||
GSV
|
||||
GSV
|
||||
GLL
|
||||
```
|
||||
|
||||
The last sentence is of particular interest, as it is used to determine when the quiet time begins. All example programs **depend** on knowing the last sentence (see [Quiet Time Interval](Troubleshooting#quiet-time-interval)).
|
||||
|
||||
### Self-test Program
|
||||
|
||||
* [NMEAtest](/examples/NMEAtest/NMEAtest.ino)
|
||||
|
||||
For this program, **No GPS device is required**. Test bytes are streamed from PROGMEM character arrays. Various strings are passed to `decode` and the expected pass or fail results are displayed. If **NeoGPS** is correctly configured, you should see this on your SerialMonitor:
|
||||
|
||||
```
|
||||
NMEA test: started
|
||||
fix object size = 44
|
||||
NMEAGPS object size = 72
|
||||
Test string length = 75
|
||||
PASSED 11 tests.
|
||||
------ Samples ------
|
||||
Results format:
|
||||
Status,UTC Date/Time,Lat,Lon,Hdg,Spd,Alt,HDOP,VDOP,PDOP,Lat err,Lon err,Alt err,Sats,[sat],
|
||||
|
||||
Input: $GPGGA,092725.00,4717.11399,N,00833.91590,E,1,8,1.01,499.6,M,48.0,M,,0*5B
|
||||
Results: 3,2000-01-01 09:27:25.00,472852332,85652650,,,49960,1010,,,,,,8,[],
|
||||
|
||||
Input: $GPRMC,092725.00,A,2520.69213,S,13101.94948,E,0.004,77.52,091202,,,A*43
|
||||
Results: 3,2002-12-09 09:27:25.00,-253448688,1310324913,7752,4,,,,,,,,,[],
|
||||
|
||||
Input: $GPRMC,162254.00,A,3647.6643,N,8957.5193,W,0.820,188.36,110706,,,A*49
|
||||
Results: 3,2006-07-11 16:22:54.00,367944050,-899586550,18836,820,,,,,,,,,[],
|
||||
|
||||
Input: $GPRMC,235959.99,A,2149.65726,N,16014.69256,W,8.690,359.99,051015,9.47,E,A*26
|
||||
Results: 3,2015-10-05 23:59:59.99,218276210,-1602448760,35999,8690,,,,,,,,,[],
|
||||
|
||||
Input: $GNGLL,0105.60764,S,03701.70233,E,225627.00,A,A*6B
|
||||
Results: 3,2000-01-01 22:56:27.00,-10934607,370283722,,,,,,,,,,,[],
|
||||
|
||||
Input: $GPGGA,064951.000,2307.1256,N,12016.4438,E,1,8,0.95,39.9,M,17.8,M,,*63
|
||||
Results: 3,2000-01-01 06:49:51.00,231187600,1202740633,,,3990,950,,,,,,8,[],
|
||||
|
||||
Input: $GPRMC,064951.000,A,2307.1256,N,12016.4438,E,0.03,165.48,260406,3.05,W,A*2C
|
||||
Results: 3,2006-04-26 06:49:51.00,231187600,1202740633,16548,30,,,,,,,,,[],
|
||||
|
||||
Input: $GPVTG,165.48,T,,M,0.03,N,0.06,K,A*36
|
||||
Results: 3,,,,16548,30,,,,,,,,,[],
|
||||
|
||||
Input: $GPGSA,A,3,29,21,26,15,18,09,06,10,,,,,2.32,0.95,2.11*00
|
||||
Results: 3,,,,,,,950,,2320,,,,,[],
|
||||
|
||||
Input: $GPGSV,3,1,09,29,36,029,42,21,46,314,43,26,44,020,43,15,21,321,39*7D
|
||||
Results: ,,,,,,,,,,,,,9,[29,21,26,15,],
|
||||
|
||||
Input: $GPGSV,3,2,09,18,26,314,40,09,57,170,44,06,20,229,37,10,26,084,37*77
|
||||
Results: ,,,,,,,,,,,,,9,[29,21,26,15,18,9,6,10,],
|
||||
|
||||
Input: $GPGSV,3,3,09,07,,,26*73
|
||||
Results: ,,,,,,,,,,,,,9,[29,21,26,15,18,9,6,10,7,],
|
||||
|
||||
Input: $GNGST,082356.00,1.8,,,,1.7,1.3,2.2*60
|
||||
Results: ,2000-01-01 08:23:56.00,,,,,,,,,170,130,,,[29,21,26,15,18,9,6,10,7,],
|
||||
|
||||
Input: $GNRMC,083559.00,A,4717.11437,N,00833.91522,E,0.004,77.52,091202,,,A,V*33
|
||||
Results: 3,2002-12-09 08:35:59.00,472852395,85652537,7752,4,,,,,,,,,[29,21,26,15,18,9,6,10,7,],
|
||||
|
||||
Input: $GNGGA,092725.00,4717.11399,N,00833.91590,E,1,08,1.01,499.6,M,48.0,M,,*45
|
||||
Results: 3,2000-01-01 09:27:25.00,472852332,85652650,,,49960,1010,,,,,,8,[29,21,26,15,18,9,6,10,7,],
|
||||
|
||||
Input: $GLZDA,225627.00,21,09,2015,00,00*70
|
||||
Results: ,2015-09-21 22:56:27.00,,,,,,,,,,,,,[29,21,26,15,18,9,6,10,7,],
|
||||
|
||||
--- floating point conversion tests ---
|
||||
|
||||
Input: $GPGGA,092725.00,3242.9000,N,11705.8169,W,1,8,1.01,499.6,M,48.0,M,,0*49
|
||||
Results: 3,2000-01-01 09:27:25.00,327150000,-1170969483,,,49960,1010,,,,,,8,[29,21,26,15,18,9,6,10,7,],
|
||||
|
||||
Input: $GPGGA,092725.00,3242.9000,N,11705.8170,W,1,8,1.01,499.6,M,48.0,M,,0*41
|
||||
Results: 3,2000-01-01 09:27:25.00,327150000,-1170969500,,,49960,1010,,,,,,8,[29,21,26,15,18,9,6,10,7,],
|
||||
|
||||
Input: $GPGGA,092725.00,3242.9000,N,11705.8171,W,1,8,1.01,499.6,M,48.0,M,,0*40
|
||||
Results: 3,2000-01-01 09:27:25.00,327150000,-1170969517,,,49960,1010,,,,,,8,[29,21,26,15,18,9,6,10,7,],
|
||||
|
||||
Input: $GPGGA,092725.00,3242.9000,N,11705.8172,W,1,8,1.01,499.6,M,48.0,M,,0*43
|
||||
Results: 3,2000-01-01 09:27:25.00,327150000,-1170969533,,,49960,1010,,,,,,8,[29,21,26,15,18,9,6,10,7,],
|
||||
|
||||
Input: $GPGGA,092725.00,3242.9000,N,11705.8173,W,1,8,1.01,499.6,M,48.0,M,,0*42
|
||||
Results: 3,2000-01-01 09:27:25.00,327150000,-1170969550,,,49960,1010,,,,,,8,[29,21,26,15,18,9,6,10,7,],
|
||||
|
||||
Input: $GPGGA,092725.00,3242.9000,N,11705.8174,W,1,8,1.01,499.6,M,48.0,M,,0*45
|
||||
Results: 3,2000-01-01 09:27:25.00,327150000,-1170969567,,,49960,1010,,,,,,8,[29,21,26,15,18,9,6,10,7,],
|
||||
|
||||
Input: $GPGGA,092725.00,3242.9000,N,11705.8175,W,1,8,1.01,499.6,M,48.0,M,,0*44
|
||||
Results: 3,2000-01-01 09:27:25.00,327150000,-1170969583,,,49960,1010,,,,,,8,[29,21,26,15,18,9,6,10,7,],
|
||||
|
||||
Input: $GPGGA,092725.00,3242.9000,N,11705.8176,W,1,8,1.01,499.6,M,48.0,M,,0*47
|
||||
Results: 3,2000-01-01 09:27:25.00,327150000,-1170969600,,,49960,1010,,,,,,8,[29,21,26,15,18,9,6,10,7,],
|
||||
```
|
||||
|
||||
### Benchmark
|
||||
|
||||
* [NMEAbenchmark](/examples/NMEAbenchmark/NMEAbenchmark.ino)
|
||||
|
||||
For this program, **No GPS device is required**. GGA, RMC and GSV sentences can be tested. Bytes are streamed from PROGMEM character arrays and parsed to determine execution times. All times are displayed in microseconds:
|
||||
|
||||
```
|
||||
NMEAbenchmark: started
|
||||
fix object size = 22
|
||||
NMEAGPS object size = 29
|
||||
GGA time = 844
|
||||
GGA no lat time = 497
|
||||
```
|
||||
50
software/firmware/libraries/NeoGPS/extras/doc/Extending.md
Normal file
50
software/firmware/libraries/NeoGPS/extras/doc/Extending.md
Normal file
@@ -0,0 +1,50 @@
|
||||
Extending NeoGPS
|
||||
=========
|
||||
Using features that are unique to your device fall into three categories:
|
||||
####1. Configuring the device with special commands
|
||||
Many devices allow you to configure which standard messages are emitted, or the rate at which they are emitted. It may be as simple as sending a proprietary command to the device. Simply use the NMEAGPS `send` or `send_P` method.
|
||||
|
||||
For example, to set the baudrate of the ublox NEO-6M gps device, send it a
|
||||
`UBX,41` message:
|
||||
```
|
||||
gps.send_P( F("PUBX,41,1,0007,0003,19200,0") );
|
||||
```
|
||||
####2. Parsing additional message types
|
||||
Some devices provide additional messages with extra information, or more efficient groupings. This will require deriving a class from `NMEAGPS`. The derived class needs to
|
||||
* declare a PROGMEM table of the new message types,
|
||||
* point that table back to the NMEAGPS table
|
||||
* override the `parseField` method to extract information from each new message type
|
||||
|
||||
Please see ubxNMEA.h and .cpp for an example of adding two ublox-proprietary messages.
|
||||
|
||||
####3. Handling new protocols
|
||||
Some devices provide additional protocols. They are frequently binary, which requires
|
||||
fewer bytes than NMEA 0183. Because they can both be transmitted on the same port, it is
|
||||
very likely that they can be distinguished at the message framing level.
|
||||
|
||||
For example, NMEA messages always start with a '$' and end with CR/LF. ublox messages start
|
||||
with 0xB5 and 0x62 bytes, a message class and id, and a 2-byte message length. There is no
|
||||
terminating character; the message completed when `length` bytes have been received.
|
||||
|
||||
This will require deriving a class from `NMEAGPS`. The derived class needs
|
||||
to
|
||||
* define new `rxState` values for the protocol state machine. These should
|
||||
be unique from the NMEA state values, but they should share the IDLE state
|
||||
value.
|
||||
* override the `decode` method to watch for its messages. As bytes are
|
||||
received, it may transition out of the IDLE state and into its own set of
|
||||
state values. If the character is not valid for this protocol, it should
|
||||
delegate it to the NMEAGPS base clase, which may begin processing an NMEAGPS
|
||||
message. If the rxState is not one of the derived states (i.e., it is in
|
||||
one of the NMEAGPS states), the character should be delegated to
|
||||
NMEAGPS::decode.
|
||||
* implement something like the `parseField` method if parse-in-place
|
||||
behavior is desirable. This is not necessarily `virtual`, as it will only
|
||||
be called from the derived `decode`.
|
||||
* You are free to add methods and data members as required for handling the
|
||||
protocol. Only `decode` must be overridden.
|
||||
|
||||
Please see ubxGPS.h and .cpp for an example of implementing the
|
||||
ublox-proprietary protocol, UBX. The derived `ubloxGPS` class provides both
|
||||
parse-in-place *and* buffered messages. See the `send` and `poll` methods.
|
||||
|
||||
196
software/firmware/libraries/NeoGPS/extras/doc/Installing.md
Normal file
196
software/firmware/libraries/NeoGPS/extras/doc/Installing.md
Normal file
@@ -0,0 +1,196 @@
|
||||
Installing
|
||||
==========
|
||||
|
||||
1. [Download the library](#1-download-the-library)
|
||||
2. [Choose a serial port](#2-choose-a-serial-port)
|
||||
3. [Connect the GPS device](#3-connect-the-gps-device)
|
||||
4. [Review `GPSport.h`](#4-review-librariesneogpssrcgpsporth)
|
||||
5. [Open the example](#5--open-the-example-sketch-nmeaino)
|
||||
6. [Build and upload](#6--build-and-upload-the-sketch-to-your-arduino)
|
||||
<hr>
|
||||
|
||||
### 1. Download the library
|
||||
|
||||
It is easiest to use the [Ardino IDE Library Manager](https://www.arduino.cc/en/Guide/Libraries#toc3) to automatically download and install NeoGPS. Select the menu **Sketch -> Include Library -> Manage Libraries**. Then type "NeoGPS" in the Search box.
|
||||
|
||||
If you need to perform a manual installation,:
|
||||
|
||||
* Download the [master ZIP file](https://github.com/SlashDevin/NeoGPS/archive/master.zip).
|
||||
* Open the zip file and open the nested `NeoGPS-master` subdirectory.
|
||||
* Select and copy all files in the `NeoGPS-master` subdirectory into a new `Arduino/Libraries/NeoGPS` directory, like most libraries. The `Arduino/Libraries/NeoGPS` directory should contain:<br>
|
||||
```
|
||||
extras
|
||||
examples
|
||||
src
|
||||
library.properties
|
||||
LICENSE
|
||||
README.md
|
||||
```
|
||||
|
||||
<hr>
|
||||
|
||||
### 2. Choose a serial port
|
||||
|
||||
**BEST**: The fastest, most reliable way to connect a GPS device is to use a HardwareSerial port.
|
||||
|
||||
On any Arduino board, you can connect the GPS device to the `Serial` pins (0 & 1). You can still print debug statements, and they will show up on the Serial Monitor window. The received GPS characters will not interfere with those prints, and you will not see those characters on the Serial Monitor window.
|
||||
|
||||
However, when you need to upload a new sketch to the Arduino over USB, **you must disconnect the GPS TX from the Arduino RX pin 0.** Otherwise, the GPS characters will interfere with the upload data. Some people put a switch in that connection to make it easy to upload without disturbing the wires.
|
||||
|
||||
For Mega, Due and Teensy boards, you can connect the GPS device to the `Serial1`, `Serial2` or `Serial3` pins.
|
||||
|
||||
For Micro and Leo (and other 32U4-based Arduinos), you can connect the GPS device to the `Serial1` pins.
|
||||
|
||||
**2nd Best**: If you can't connect the GPS device to a `HardwareSerial` port, you should download and install the [AltSoftSerial](https://github.com/PaulStoffregen/AltSoftSerial) or [NeoICSerial](https://github.com/SlashDevin/NeoICSerial) library. These libraries only work on two specific pins (8 & 9 on an UNO). This library is very efficient and reliable. It uses one of the hardware TIMERs, so it may conflict with libraries that use TIMERs or PWM output (e.g., servo).
|
||||
|
||||
**3rd Best**: If you can't use the pins required by `AltSoftSerial`, and your GPS device runs at 9600, 19200 or 38400 baud, you should download and install the [NeoSWSerial](https://github.com/SlashDevin/NeoSWSerial) library. This library is almost as efficient. It will help you avoid common timing problems caused by `SoftwareSerial`. It does not need an extra TIMER, so it can be used with most other libraries. It does use Pin Change Interrupts, but there is an option in the header file that allows you to coordinate other PCI usage with `NeoSWSerial`.
|
||||
|
||||
`NeoSWSerial` can be used with `AltSoftSerial` at the same time, allowing your sketch to have two extra serial ports.
|
||||
|
||||
**WORST**: `SoftwareSerial` is NOT RECOMMENDED, because it disables interrupts for long periods of time. This can interfere with other parts of your sketch, or with other libraries. It cannot transmit and receive at the same time, and your sketch can only receive from one `SoftwareSerial` instance at time.
|
||||
|
||||
<hr>
|
||||
|
||||
### 3. Connect the GPS device
|
||||
|
||||
Most GPS devices are 3.3V devices, and most Arduinos are 5V devices. Although many GPS modules are described as "3V & 5V compatible",
|
||||
|
||||
<p align=center><b>YOU SHOULD NOT CONNECT A 5V ARDUINO TRANSMIT PIN TO THE 3.3V GPS RX PIN</b></p>
|
||||
|
||||
This can damage the device, cause overheating, system power problems or decrease the lifetime of battery-operated systems. You must level-shift this connection with inexpensive level-shifting modules (best) or a resistor divider.
|
||||
|
||||
Connecting the 3.3V GPS TX pin to a 5V Arduino receive pin will not damage the GPS device, but it may not be reliable. This is because the GPS TX voltage is slightly lower than what the Arduino requires. It works in many situations, but if you are not able to receive GPS characters reliably, you probably need to use a level-shifting module (best) or a diode+resistor to "pull up" the GPS TX pin voltage.
|
||||
|
||||
<hr>
|
||||
|
||||
### 4. Review `Libraries/NeoGPS/src/GPSport.h`
|
||||
|
||||
This file declares a the serial port to be used for the GPS device. You can either:
|
||||
|
||||
* Use the default `GPSport.h` and connect your GPS device according to what it chooses; or
|
||||
* Replace the entire contents of `GPSport.h` and insert your own declarations (see below and comments in `GPSport.h`).
|
||||
|
||||
#### Default choices for GPSport.h
|
||||
|
||||
By default, Mega, Leonardo, Due, Zero/MKR1000 and Teensy boards will use `Serial1`.
|
||||
|
||||
All other Boards will use [AltSoftSerial](https://github.com/PaulStoffregen/AltSoftSerial) on two specific pins (see table at linked page).
|
||||
|
||||
If you want to use a different serial port library (review step 2 above), you must edit these `#include` lines in `GPSport.h`:
|
||||
|
||||
```
|
||||
//#include <NeoHWSerial.h> // NeoSerial or NeoSerial1 for INTERRUPT_PROCESSING
|
||||
#include <AltSoftSerial.h> // <-- DEFAULT. Two specific pins required (see docs)
|
||||
//#include <NeoICSerial.h> // AltSoftSerial with Interrupt-style processing
|
||||
//#include <NeoSWSerial.h> // Any pins, only @ 9600, 19200 or 38400 baud
|
||||
//#include <SoftwareSerial.h> // NOT RECOMMENDED!
|
||||
```
|
||||
|
||||
Uncomment **one** of those include statements, and it will use that library for the GPS serial port.
|
||||
|
||||
If you uncomment the `NeoSWSerial.h` include, pins 3 and 4 will be used for the GPS. If your GPS is on different pins, you must edit these `#define` lines in `GPSport.h`:
|
||||
|
||||
#define RX_PIN 4
|
||||
#define TX_PIN 3
|
||||
|
||||
|
||||
|
||||
#### Choosing your own serial port
|
||||
|
||||
If you know what serial port you want to use, you can **REPLACE EVERYTHING** in `GPSport.h' with the three declarations that are used by all example programs:
|
||||
|
||||
1. the `gpsPort` variable **(include its library header if needed)**;
|
||||
2. the double-quoted C string for the `GPS_PORT_NAME` (displayed by all example programs); and
|
||||
3. the `DEBUG_PORT` to use for Serial Monitor print messages (usually `Serial`).
|
||||
|
||||
All the example programs can use any of the following serial port types:
|
||||
|
||||
* HardwareSerial (built-in `Serial`, `Serial1` et al. STRONGLY recommended)
|
||||
* [AltSoftSerial](https://github.com/PaulStoffregen/AltSoftSerial) **DEFAULT** (only works on one specific Input Capture pin)
|
||||
* [NeoICSerial](https://github.com/SlashDevin/NeoICSerial) (only works on one specific Input Capture pin)
|
||||
* [NeoHWSerial](https://github.com/SlashDevin/NeoHWSerial) (required for NMEA_isr and NMEASDlog on built-in serial ports)
|
||||
* [NeoSWSerial](https://github.com/SlashDevin/NeoSWSerial) (works on most pins)
|
||||
* SoftwareSerial (built-in, NOT recommended)
|
||||
|
||||
Be sure to download the library you have selected (NOTE: `HardwareSerial` and `SoftwareSerial` are pre-installed by the Arduino IDE and do not need to be downloaded).
|
||||
|
||||
For example, to make all examples use `Serial` for the GPS port **and** for Serial Monitor messages, `GPSport.h` should contain just these 3 declarations:
|
||||
|
||||
```
|
||||
#ifndef GPSport_h
|
||||
#define GPSport_h
|
||||
|
||||
#define gpsPort Serial
|
||||
#define GPS_PORT_NAME "Serial"
|
||||
#define DEBUG_PORT Serial
|
||||
|
||||
#endif
|
||||
```
|
||||
|
||||
Or, to make all examples use `AltSoftSerial` for the GPS port and `Serial` for Serial Monitor messages, `GPSport.h` should contain just these statements:
|
||||
|
||||
```
|
||||
#ifndef GPSport_h
|
||||
#define GPSport_h
|
||||
|
||||
#include <AltSoftSerial.h>
|
||||
AltSoftSerial gpsPort;
|
||||
#define GPS_PORT_NAME "AltSoftSerial"
|
||||
#define DEBUG_PORT Serial
|
||||
|
||||
#endif
|
||||
```
|
||||
|
||||
<hr>
|
||||
|
||||
### 5. Open the example sketch NMEA.ino
|
||||
|
||||
In the Arduino IDE, select **File -> Examples -> NeoGPS -> NMEA**.
|
||||
|
||||
<hr>
|
||||
|
||||
### 6. Build and upload the sketch to your Arduino.
|
||||
|
||||
**Note:** If the sketch does not compile, please see the [Troubleshooting](Troubleshooting.md#configuration-errors) section.
|
||||
|
||||
When the sketch begins, you should see this:
|
||||
```
|
||||
NMEA.INO: started
|
||||
fix object size = 31
|
||||
gps object size = 84
|
||||
Looking for GPS device on Serial1
|
||||
|
||||
GPS quiet time is assumed to begin after a RMC sentence is received.
|
||||
You should confirm this with NMEAorder.ino
|
||||
|
||||
Status,UTC Date/Time,Lat,Lon,Hdg,Spd,Alt,Sats,Rx ok,Rx err,Rx chars,
|
||||
3,2016-05-24 01:21:29.00,472852332,85652650,,138,,,1,0,66,
|
||||
3,2016-05-24 01:21:30.00,472852311,85652653,,220,24040,7,9,0,557,
|
||||
3,2016-05-24 01:21:31.00,472852315,85652647,,449,24080,7,17,0,1048,
|
||||
etc.
|
||||
```
|
||||
The default NeoGPS configuration is **Nominal**, as described [here](Configurations.md#typical-configurations). If you do not see this output, please review the [Troubleshooting](Troubleshooting.md#gps-device-connection-problems) section.
|
||||
|
||||
This output can be copy & pasted into a into a text editor for saving as a CSV file, which can then be imported into a spreadsheet program for graphing or analysis.
|
||||
|
||||
<img src="images/example.png"/>
|
||||
|
||||
<hr>
|
||||
|
||||
### The NMEA.ino example works!
|
||||
Once you have verified the GPS device connection and build process with this first example, you should also verify your device's behavior with `NMEAorder.ino` (see [this section](Troubleshooting.md#quiet-time-interval)). This can avoid problems later on, when you start adding/merging other functions to do your "work".
|
||||
|
||||
[Other examples](Examples.md) include `NMEAloc.ino`, which shows how to use just the location fields of a fix, or `NMEAtimezone.ino`, which shows how to adjust the GPS time for your local time zone.
|
||||
|
||||
If you are logging information to an SD card, you should next try `NMEA_isr.ino`. It is identical to `NMEA.ino`, except that it handles the GPS characters during the RX char interrupt. Interrupt handling will require one of the NeoXXSerial libraries to be installed (e.g. [NeoHWSerial](https://github.com/SlashDevin/NeoHWSerial)).
|
||||
|
||||
If you are working on a drone or other autonomous system, you should you should read about [Coherency](Coherency.md) and the interrupt-driven technique in [NMEA_isr](/examples/NMEA_isr/NMEA_isr.ino).
|
||||
|
||||
You can also try other configurations. Please see [Choosing Your Configuration](Choosing.md) for more information, and then simply edit `GPSfix_cfg.h` and/or `NMEAGPS_cfg.h`, or select an [example configuration](../configs) and copy these three files into your application directory: `NeoGPS_cfg.h`, `GPSfix_cfg.h`, and `NMEAGPS_cfg.h`.
|
||||
|
||||
You can review and edit each of the copied configuration files to add or remove messages or fields, at any time.
|
||||
|
||||
**Note:** Not all configurations will work with all example applications. Compiler error messages are emitted for incompatible settings, or if an example requires certain configurations.
|
||||
|
||||
### I have a ublox GPS device
|
||||
After you have tried all the standard NMEA examples, and you need the ublox-specific capabilities of NeoGPS, please see the [ublox](ublox.md) section. Try `PUBX.ino` first, then try `ublox.ino` if you *really* need the binary protocol.
|
||||
18
software/firmware/libraries/NeoGPS/extras/doc/License.md
Normal file
18
software/firmware/libraries/NeoGPS/extras/doc/License.md
Normal file
@@ -0,0 +1,18 @@
|
||||
### License:
|
||||
|
||||
**NeoGPS**
|
||||
|
||||
Copyright (C) 2014-2017, SlashDevin
|
||||
|
||||
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/>.
|
||||
62
software/firmware/libraries/NeoGPS/extras/doc/Location.md
Normal file
62
software/firmware/libraries/NeoGPS/extras/doc/Location.md
Normal file
@@ -0,0 +1,62 @@
|
||||
Location
|
||||
========
|
||||
The `Location_t` class is a 2D point, containing a latitude and longitude in integer degrees * 10<sup>7</sup> (source [here](/src/Location.h)).
|
||||
|
||||
This class also provides geographic distance, bearing and offset functions. Furthermore, they all take advantage of the increased precision of the integer coordinates. Other libraries use floating-point coordinates, which have only 6 or 7 significant digits. By using integer math, calculations maintain their original accuracy as long as possible. For example, small distances can be calculated to millimeter accuracy.
|
||||
|
||||
The example program [NMEAaverage.ino](/examples/NMEAaverage/NMEAaverage.ino) shows several techniques for performing 2D calculations.
|
||||
|
||||
### Distance
|
||||
|
||||
To calculate the distance between a pre-determined point and the current fix,
|
||||
|
||||
```
|
||||
NeoGPS::Location_t madrid( 404381311L, -38196229L ); // see https://www.google.com/maps/@40.4381311,-3.8196229,6z
|
||||
gps_fix fix;
|
||||
|
||||
void loop()
|
||||
{
|
||||
while (gps.available( gps_port )) {
|
||||
fix = gps.read();
|
||||
float dist = fix.location.DistanceKm( madrid );
|
||||
// or dist = NeoGPS::Location_t::DistanceKm( fix.location, madrid );
|
||||
Serial.print( dist );
|
||||
Serial.println( F(" km") );
|
||||
```
|
||||
|
||||
`DistanceMiles` is also available
|
||||
|
||||
### Bearing
|
||||
|
||||
To calculate the bearing from one point to another (in radians, CW from North),
|
||||
|
||||
```
|
||||
float bearing = fix.location.BearingToDegrees( madrid );
|
||||
// or bearing = NeoGPS::Location_t::BearingToDegrees( fix.location, madrid );
|
||||
```
|
||||
Radians is returned by `BearingTo`.
|
||||
|
||||
### Offsetting a Location
|
||||
|
||||
To move a location by a specified distance, in a specified direction,
|
||||
|
||||
```
|
||||
float bearing = fix.location.BearingToDegrees( madrid );
|
||||
// or bearing = NeoGPS::Location_t::BearingToDegrees( fix.location, madrid );
|
||||
|
||||
// Step 10km closer to the destination
|
||||
Location_t next_stop( fix.location );
|
||||
next_stop.OffsetBy( bearing, 10 / NeoGPS::Location_t::EARTH_RADIUS_KM );
|
||||
```
|
||||
Notice that the distance is specified in *radians*. To convert from km to radians, divide by the Earth's radius in km. To convert from miles, divide the miles by the Earth's radius in miles.
|
||||
|
||||
### NeoGPS namespace
|
||||
Because the `Location_t` is inside the `NeoGPS` namespace, any time you want to declare your own instance, use any of the constants in that class (anything that requires the `Location_t` name), you must prefix it with `NeoGPS::` (shown above). As with any C++ namespace, you can relax that requirement by putting this statement anywhere after the NeoGPS includes:
|
||||
|
||||
```
|
||||
using namespace NeoGPS;
|
||||
```
|
||||
|
||||
This technique is used in the **NMEAaverage.ino** sketch.
|
||||
|
||||
However, if you have any other libraries that declare their own `Location_t` (not likely), you could not use the `using` statement. `Time_t` is inside the `NeoGPS` namespace for the same reason: avoiding name collisions.
|
||||
90
software/firmware/libraries/NeoGPS/extras/doc/Merging.md
Normal file
90
software/firmware/libraries/NeoGPS/extras/doc/Merging.md
Normal file
@@ -0,0 +1,90 @@
|
||||
Merging
|
||||
===========
|
||||
Because different NMEA sentences contain different pieces of a fix, they have to be "merged" to determine a complete picture. Some sentences contain only date and time. Others contain location and altitude, but not speed and heading (see table [here](Choosing.md)).
|
||||
|
||||
There are several ways to use the GPS fix data: without merging, implicit merging, and **explicit merging ([the default](#3-explicit-merging))**. NeoGPS allows you to choose how you want multiple sentences to be merged:
|
||||
|
||||
### 1. NO MERGING
|
||||
|
||||
In this mode, `gps.read()` will return a fix that is populated from just one sentence. You will probably receive multiple sentences per update interval, depending on your GPS device.
|
||||
|
||||
If you are interested in just a few pieces of information, and those pieces can be obtained from one or two sentences, you can wait for that specific sentence to arrive, and then use one or more members of the fix at that time. Make sure that "no merging" is selected in NMEAGPS_cfg.h by commenting out these lines:
|
||||
```
|
||||
//#define NMEAGPS_EXPLICIT_MERGING
|
||||
//#define NMEAGPS_IMPLICIT_MERGING
|
||||
```
|
||||
Then write your loop to wait for the specific sentence:
|
||||
```
|
||||
void loop()
|
||||
{
|
||||
while (gps.available( gps_port )) {
|
||||
const gps_fix & rmc = gps.read();
|
||||
|
||||
if (gps.nmeaMessage == NMEAGPS::NMEA_RMC) {
|
||||
// All GPS-related work is performed inside this if statement
|
||||
|
||||
if (rmc.valid.speed && (rmc.speed <= 5))
|
||||
Serial.println( F("Too slow!") );
|
||||
|
||||
if (rmc.valid.location && ... or any rmc member
|
||||
}
|
||||
}
|
||||
|
||||
// Can't access rmc out here...
|
||||
```
|
||||
If you are interested in pieces of information that are grouped by some detailed criteria (e.g., field values), you must select "no merging" and then manually merge the fixes of interest. The `merged` copy will be safe to access at any time:
|
||||
```
|
||||
gps_fix merged;
|
||||
|
||||
void loop()
|
||||
{
|
||||
while (gps.available( gps_port )) {
|
||||
const gps_fix & fix = gps.read();
|
||||
|
||||
if ((gps.nmeaMessage == NMEAGPS::NMEA_RMC) &&
|
||||
(fix.valid.heading &&
|
||||
((4500 <= fix.heading_cd()) && (fix.heading_cd() < 9000)))){
|
||||
|
||||
merged |= fix;
|
||||
|
||||
if (merged.valid.satellites && (rmc.satellites > 5))
|
||||
Serial.println( F("Moar sats!") );
|
||||
}
|
||||
}
|
||||
|
||||
// Can't access 'fix' out here, but 'merged' can be used...
|
||||
```
|
||||
### 2. IMPLICIT MERGING
|
||||
If you are interested in more pieces of information, perhaps requiring more kinds of sentences to be decoded, but don't really care about what time the pieces were received, you could enable implicit merging:
|
||||
```
|
||||
//#define NMEAGPS_EXPLICIT_MERGING
|
||||
#define NMEAGPS_IMPLICIT_MERGING
|
||||
```
|
||||
As sentences are received, they are accumulated internally. Previous field values are retained until they are overwritten by another sentence. When `gps.available`, the accumulated fix can be obtained with `gps.read()`.
|
||||
|
||||
Note: The members in an implicitly-merged fix may not be coherent (see [Coherency](Coherency.md). Also, checksum errors can cause the internal fix to be completely reset. Be sure your sketch checks the [valid flags](Data%20Model.md#validity) before using any fix data.
|
||||
|
||||
### 3. EXPLICIT MERGING
|
||||
This is the default setting. To enable explicit merging, make sure this is in NMEAGPS_cfg.h:
|
||||
```
|
||||
#define NMEAGPS_EXPLICIT_MERGING
|
||||
//#define NMEAGPS_IMPLICIT_MERGING
|
||||
|
||||
#define NMEAGPS_FIX_MAX 1
|
||||
```
|
||||
NMEAGPS_FIX_MAX must be at least one to use EXPLICIT merging.
|
||||
|
||||
As sentences are received, they are merged internally. When the LAST_SENTENCE_IN_INTERVAL is received, the internal fix is marked as "available", and it can be accessed by calling `gps.read()`. When the next sentence arrives, the internal fix structure will be emptied.
|
||||
|
||||
```
|
||||
gps_fix_t currentFix;
|
||||
|
||||
void loop()
|
||||
{
|
||||
while (gps.available( gps_port ))
|
||||
currentFix = gps.read();
|
||||
|
||||
check_position( currentFix );
|
||||
```
|
||||
|
||||
Explicit merging is also required to implement [Coherency](Coherency.md).
|
||||
48
software/firmware/libraries/NeoGPS/extras/doc/Performance.md
Normal file
48
software/firmware/libraries/NeoGPS/extras/doc/Performance.md
Normal file
@@ -0,0 +1,48 @@
|
||||
Performance
|
||||
===========
|
||||
|
||||
#### **NeoGPS** is **40% to 70% faster**.
|
||||
|
||||
For comparison, the following sentences were parsed by various [Configurations](/doc/Configurations.md) of **NeoGPS**, **TinyGPS** and **TinyGPSPlus** on a 16MHz Arduino Mega2560.
|
||||
|
||||
```
|
||||
$GPGGA,092725.00,4717.11399,N,00833.91590,E,1,8,1.01,499.6,M,48.0,M,,0*5B
|
||||
$GPRMC,083559.00,A,4717.11437,N,00833.91522,E,0.004,77.52,091202,,,A*57
|
||||
$GPGSV,3,1,10,23,38,230,44,29,71,156,47,07,29,116,41,08,09,081,36*7F
|
||||
$GPGSV,3,2,10,10,07,189,,05,05,220,,09,34,274,42,18,25,309,44*72
|
||||
$GPGSV,3,3,10,26,82,187,47,28,43,056,46*77
|
||||
```
|
||||
|
||||
<table>
|
||||
<tr><td>Configuration</td><td>Sentence</td><td>NeoGPS</td><td>TinyGPS<br>Time (% faster)</td><td>TinyGPS++<br>Time (% faster)</td><td>Adafrut_GPS<br>Time (%faster)</td></tr>
|
||||
<tr><td>Minimal</td><td>GGA<br>RMC</td><td>329us<br>335us</td><td>- (78%)<br>- (77%)</td><td>- (78%)<br>- (77%)</td></tr>
|
||||
<tr><td>DTL</td><td>GGA<br>RMC</td><td>780us<br>803us</td><td>- (46%)<br>- (44%)</td><td>- (47%)<br>- (44%)</td></tr>
|
||||
<tr><td>Nominal</td><td>GGA<br>RMC</td><td>864us<br>883us</td><td>1448us (40%)<br>1435us (39%)</td><td>1473us (41%)<br>1442us (39%)</td><td>1358us (36%)<br>1535us (42%)</td></tr>
|
||||
<tr><td>Full</td><td>GGA<br>RMC<br>GSV</td><td>908us<br>899us<br>2194us</td><td>- (37%)<BR>- (37%)<br>- (-)</td><td>1523us (40%)<br>1560us (42%)<br>6651us (67%)</td></tr>
|
||||
</table>
|
||||
|
||||
#### Why is **NeoGPS** faster?
|
||||
|
||||
Most libraries use extra buffers to accumulate parts of the sentence so they
|
||||
can be parsed all at once. For example, an extra field buffer may hold on
|
||||
to all the characters between commas. That buffer is then parsed into a
|
||||
single data item, like `heading`. Some libraries even hold on to the
|
||||
*entire* sentence before attempting to parse it. In addition to increasing
|
||||
the RAM requirements, this requires **extra CPU time** to copy the bytes and
|
||||
index through them... again.
|
||||
|
||||
**NeoGPS** parses each character immediately into the data item. When the
|
||||
delimiting comma is received, the data item has been fully computed *in
|
||||
place* and is marked as valid.
|
||||
|
||||
Most libraries parse all fields of their selected sentences. Although most
|
||||
people use GPS for obtaining lat/long, some need only time, or even just one
|
||||
pulse-per-second.
|
||||
|
||||
**NeoGPS** configures each item separately. Disabled items are
|
||||
conditionally compiled, which means they will not use any RAM, program space
|
||||
or CPU time. The characters from those fields are simply skipped; they are
|
||||
never copied into a buffer or processed.
|
||||
|
||||
While it is significantly faster and smaller than all NMEA parsers, these same improvements also make
|
||||
NeoGPS faster and smaller than _binary_ parsers.
|
||||
13
software/firmware/libraries/NeoGPS/extras/doc/Program.md
Normal file
13
software/firmware/libraries/NeoGPS/extras/doc/Program.md
Normal file
@@ -0,0 +1,13 @@
|
||||
Program Space requirements
|
||||
=======
|
||||
|
||||
The **Minimal** configuration requires 866 bytes.
|
||||
|
||||
The **DTL** configuration requires 2072 bytes.
|
||||
|
||||
The **Nominal** configuration requires 2800 bytes. TinyGPS uses about 2400 bytes. TinyGPS++ uses about 2700 bytes.
|
||||
|
||||
The **Full** configuration requires 3462 bytes.
|
||||
|
||||
(All configuration numbers include 166 bytes PROGMEM.)
|
||||
|
||||
41
software/firmware/libraries/NeoGPS/extras/doc/RAM.md
Normal file
41
software/firmware/libraries/NeoGPS/extras/doc/RAM.md
Normal file
@@ -0,0 +1,41 @@
|
||||
RAM requirements
|
||||
=======
|
||||
|
||||
#### **NeoGPS** requires **72% to 96% _less_ RAM, saving 140 to 1100 bytes.**
|
||||
|
||||
Because you can select what data members are stored, the RAM savings depends on the [configuration](Configurations.md):
|
||||
|
||||
<table>
|
||||
<tr><td>Configuration</td><td>NeoGPS<br>Size</td><td>TinyGPS<br>Size (% smaller)</td><td>TinyGPS++<br>Size (% smaller)</td><td>Adafruit_GPS<br>Size (% smaller)</td></tr>
|
||||
<tr><td>Minimal</td><td>10</td><td>- (95%)</td><td>- (96%)</td></tr>
|
||||
<tr><td>DTL</td><td>25</td><td>- (86%)</td><td>- (90%)</td></tr>
|
||||
<tr><td>Nominal</td><td>41</td><td>180 (72%)</td><td>240 (83%)</td><td>326 (87%)</td></tr>
|
||||
<tr><td>Full</td><td>242</td><td>- (-)</td><td>~1400 (83%)</td></tr>
|
||||
</table>
|
||||
|
||||
#### Why does **NeoGPS** use less RAM?
|
||||
|
||||
As data is received from the device, various portions of a `fix` are
|
||||
modified. In fact, _**no buffering RAM is required**_. Each character
|
||||
affects the internal state machine and may also contribute to a data member
|
||||
(e.g., latitude).
|
||||
|
||||
If your application only requires an accurate one pulse-per-second, you
|
||||
can configure it to parse *no* sentence types and retain *no* data members.
|
||||
This is the **Minimal** configuration. Although the
|
||||
`fix().status` can be checked, no valid flags are available. Even
|
||||
though no sentences are parsed and no data members are stored, the
|
||||
application will still receive an empty `fix` once per second:
|
||||
|
||||
```
|
||||
while (gps.available( gpsPort )) {
|
||||
gps_fix nothingButStatus = gps.read();
|
||||
sentenceReceived();
|
||||
}
|
||||
```
|
||||
|
||||
The `ubloxNMEA` derived class doesn't use any extra bytes of RAM.
|
||||
|
||||
The `ubloxGPS` derived class adds 20 bytes to handle the more-complicated protocol,
|
||||
plus 5 static bytes for converting GPS time and Time Of Week to UTC.
|
||||
|
||||
40
software/firmware/libraries/NeoGPS/extras/doc/Tradeoffs.md
Normal file
40
software/firmware/libraries/NeoGPS/extras/doc/Tradeoffs.md
Normal file
@@ -0,0 +1,40 @@
|
||||
Tradeoffs
|
||||
=========
|
||||
|
||||
There's a price for everything, hehe...
|
||||
|
||||
#### Configurability means that the code is littered with #ifdef sections.
|
||||
|
||||
I've tried to increase white space and organization to make it more readable, but let's be honest...
|
||||
conditional compilation is ugly.
|
||||
|
||||
#### Accumulating parts means knowing which parts are valid.
|
||||
|
||||
Before accessing a part, you must check its `valid` flag. Fortunately, this adds only one bit per member. See [Streamers.cpp](/src/Streamers.cpp#L100) for an example of accessing every data member. That file also shows how to accommodate different builds: all references to 'gps_fix' members are wrapped with conditional compilation `#ifdef`/`#endif` statements. If you do not plan to support multiple configurations, you do not need to use `#ifdef`/`#endif` statements.
|
||||
|
||||
#### Parsing without buffers, or *in place*, means that you must be more careful about when you access data items.
|
||||
|
||||
In general, using the fix-oriented methods `available` and `read` are atomically safe. You can access any parts of your `fix` structure, at any time.
|
||||
|
||||
If you are using the advanced [character-oriented methods](/extras/doc/CharOriented.md):
|
||||
|
||||
* You must wait to access the internal `gps.fix()` until after the entire sentence has been parsed.
|
||||
* Only 3 example programs use these methods: NMEAblink, NMEAorder and NMEAdiagnostic. These examples simply `decode` until a sentence is COMPLETED. See `GPSloop()` in [NMEAdiagnostic.ino](/examples/NMEAdiagnostoc/NMEAdiagnostic.ino).
|
||||
* Member function `gps.is_safe()` can also be used to determine when it is safe to access the internal `gps.fix()`.
|
||||
* Received data errors can cause invalid field values to be set in the internal fix *before* the CRC is fully computed. The CRC will
|
||||
catch most of those, and the internal fix members will then be marked as invalid.
|
||||
|
||||
#### Accumulating parts into *one* fix means less RAM but more complicated code
|
||||
|
||||
By enabling one of the [merging](/extras/doc/Merging.md) methods, fixes will accumulate data from all received sentences. The code required to implement those different techniques is more complicated than simply setting a structure member.
|
||||
|
||||
You are not restricted from having other instances of fix; you can copy or merge a some or all of a new fix into another copy if you want.
|
||||
|
||||
#### Full C++ OO implementation is more advanced than most Arduino libraries.
|
||||
|
||||
You've been warned! ;)
|
||||
|
||||
#### "fast, good, cheap... pick two."
|
||||
|
||||
Although most of the RAM reduction is due to eliminating buffers, some of it is from trading RAM
|
||||
for additional code (see **Nominal** Program Space above). And, as I mentioned, the readabilty (i.e., goodness) suffers from its configurability.
|
||||
275
software/firmware/libraries/NeoGPS/extras/doc/Troubleshooting.md
Normal file
275
software/firmware/libraries/NeoGPS/extras/doc/Troubleshooting.md
Normal file
@@ -0,0 +1,275 @@
|
||||
Troubleshooting
|
||||
===============
|
||||
Most problems are caused by these kinds of errors:
|
||||
1. [Device connection](#gps-device-connection-problems) (use `NMEAdiagnostic.ino`)
|
||||
2. [Poor reception](#poor-reception) (use `NMEA.ino`)
|
||||
3. [Configuration](#configuration-errors) (use `NMEAtest.ino`)
|
||||
4. [Quiet Time Interval](#quiet-time-interval) (use `NMEAorder.ino`)
|
||||
5. [Trying to do too many things](#trying-to-do-too-many-things) at the same time
|
||||
6. [When all else fails...](#when-all-else-fails)
|
||||
|
||||
__________________
|
||||
## GPS device connection problems
|
||||
The example program `NMEAdiagnostic.ino` can several kinds of problems:
|
||||
|
||||
1) The GPS device may not be correctly wired,
|
||||
2) The GPS device is correctly wired but running at the wrong baud rate,
|
||||
3) The GPS device is running at the correct baud rate, but it never sends the LAST_SENTENCE_IN_INTERVAL, as defined in NMEAGPS_cfg.h
|
||||
|
||||
To help diagnose the problem, use [NMEAdiagnostic.ino](/examples/NMEAdiagnostic/NMEAdiagnostic.ino). Create an NMEAdiagnostic subdirectory, copy the same NeoGPS files into that subdirectory, along with NMEAdiagnostic.ino. Build and upload the sketch.
|
||||
|
||||
##### 1) Not correctly wired
|
||||
If the GPS device is not correctly connected, [NMEAdiagnostic.ino](/examples/NMEAdiagnostic/NMEAdiagnostic.ino) will display:
|
||||
```
|
||||
NMEAdiagnostic.INO: started
|
||||
Looking for GPS device on Serial1
|
||||
|
||||
____________________________
|
||||
|
||||
Checking 9600 baud...
|
||||
|
||||
|
||||
Check GPS device and/or connections. No data received.
|
||||
```
|
||||
The example program [NMEA.ino](/examples/NMEA/NMEA.ino) will display the following, stopping after printing the header:
|
||||
```
|
||||
NMEA.INO: started
|
||||
fix object size = 31
|
||||
gps object size = 84
|
||||
Looking for GPS device on Serial1
|
||||
|
||||
GPS quiet time is assumed to begin after a GST sentence is received.
|
||||
You should confirm this with NMEAorder.ino
|
||||
|
||||
Status,UTC Date/Time,Lat,Lon,Hdg,Spd,Alt,Sats,Rx ok,Rx err,Rx chars,
|
||||
```
|
||||
You may have the GPS device connected to the wrong pins (GPS RX should be connected to Arduino TX, and GPS TX should be connected to Arduino RX), or the .INO may be using the wrong serial object: review `GPSport.h` for the expected connections, or delete the include and declare your own serial port variable.
|
||||
|
||||
##### 2) Wrong baud rate
|
||||
If the wrong baud rate is chosen, [NMEAdiagnostic.ino](/examples/NMEAdiagnostic/NMEAdiagnostic.ino) will try each baud rate to determine the correct baud rate for your GPS device. For each baud rate, it will display:
|
||||
```
|
||||
Checking 4800 baud...
|
||||
No valid sentences, but characters are being received.
|
||||
Check baud rate or device protocol configuration.
|
||||
|
||||
Received data:
|
||||
884A0C4C8C480C8808884A0C8C480C4A4CC80A0C027759495995A5084C0A4C88 .J.L.H....J..H.JL....wYIY...L.L.
|
||||
```
|
||||
If the example program [NMEA.ino](/examples/NMEA/NMEA.ino) is using the wrong baud rate, it will print lines of empty data:
|
||||
```
|
||||
Local time,Status,UTC Date/Time,Lat,Lon,Hdg,Spd,Alt,HDOP,Rx ok,Rx err,Rx chars,
|
||||
,,,,,,,,0,3,181,
|
||||
,,,,,,,,0,1,422,
|
||||
```
|
||||
Notice how the received character count (Rx chars) is increasing, but nothing was decoded successfully (Rx ok always 0), and a few sentences had errors. You should review your GPS device's documentation to find the correct baud rate, or use [NMEAdiagnostic](/examples/NMEAdiagnostic/NMEAdiagnostic.ino) to auto-detect the correct baud rate.
|
||||
##### 3) Wrong LAST_SENTENCE_IN_INTERVAL in NMEAGPS_cfg.h
|
||||
It is very important that the correct LAST_SENTENCE_IN_INTERVAL is chosen. It is used to determine what sentences are in a particular interval (usually 1 second) and when the GPS quiet time begins (see below).
|
||||
|
||||
Choosing the wrong LAST_SENTENCE_IN_INTERVAL may cause GPS characters to be dropped (because the quiet time is assumed to begin at the wrong time), or prevent any update intervals from being completed (because the sketch waits for the wrong sentence to arrive).
|
||||
|
||||
If the wrong LAST_SENTENCE_IN_INTERVAL is chosen, [NMEAdiagnostic.ino](/examples/NMEAdiagnostic/NMEAdiagnostic.ino) will display:
|
||||
```
|
||||
NMEAdiagnostic.INO: started
|
||||
Looking for GPS device on Serial1
|
||||
|
||||
____________________________
|
||||
|
||||
Checking 9600 baud...
|
||||
Received GSV
|
||||
Received GSV
|
||||
Received GLL
|
||||
Received RMC
|
||||
Received VTG
|
||||
Received GGA
|
||||
Received GSA
|
||||
Received GSV
|
||||
Received GSV
|
||||
Received GSV
|
||||
Received GLL
|
||||
Received RMC
|
||||
Received VTG
|
||||
Received GGA
|
||||
Received GSA
|
||||
Received GSV
|
||||
Received GSV
|
||||
Received GSV
|
||||
Received GLL
|
||||
Received RMC
|
||||
Received VTG
|
||||
|
||||
|
||||
**** NMEA sentence(s) detected! ****
|
||||
Received data:
|
||||
47504753562C332C312C31312C30322C37302C3330322C32372C30352C33352C GPGSV,3,1,11,02,70,302,27,05,35,
|
||||
3139372C32342C30362C34392C3035332C33312C30392C31372C3037332C3230 197,24,06,49,053,31,09,17,073,20
|
||||
2A37360D0A2447504753562C332C322C31312C31322C35352C3236362C32352C *76..$GPGSV,3,2,11,12,55,266,25,
|
||||
|
||||
Device baud rate is 9600
|
||||
|
||||
GPS data fields received:
|
||||
|
||||
Status,UTC Date/Time,Lat,Lon,Hdg,Spd,Alt,Sats,Rx ok,Rx err,Rx chars,
|
||||
3,2016-05-24 01:56:45.00,456013948,-720168555,,816,25450,7,21,0,1317,
|
||||
|
||||
Warning: LAST_SENTENCE_IN_INTERVAL defined to be RMC, but was never received.
|
||||
Please use NMEAorder.ino to determine which sentences your GPS device sends, and then
|
||||
use the last one for the definition in NMEAGPS_cfg.h.
|
||||
|
||||
** NMEAdiagnostic completed **
|
||||
|
||||
1 warnings
|
||||
```
|
||||
As instructed, you should run the NMEAorder.ino sketch to determine which sentence is last. You may be able to see a slight pause in the "Received XXX" messages above, which would also identify the last sentence. Edit NMEAGPS_cfg.ino and change this line:
|
||||
```
|
||||
#define LAST_SENTENCE_IN_INTERVAL NMEAGPS::NMEA_GLL
|
||||
```
|
||||
__________________
|
||||
## Poor reception
|
||||
If the GPS device is correctly connected, and the sketch is receiving complete NMEA sentences, without data errors, [NMEA.ino](/examples/NMEA/NMEA.ino) displays "mostly" empty fields:
|
||||
```
|
||||
Local time,Status,UTC Date/Time,Lat,Lon,Hdg,Spd,Alt,HDOP,Rx ok,Rx err,Rx chars,
|
||||
,0,,,,,,,3,0,259,
|
||||
,0,,,,,,,6,0,521,
|
||||
```
|
||||
Notice how "Rx ok" and "Rx chars" increase each second, and "Rx err" is usually zero. This means that the sketch is receiving complete NMEA sentences, without data errors.
|
||||
|
||||
Because the fields are all empty, the GPS device is not receiving signals from any satellites. Check the antenna connection and orientation, and make sure you have an unobstructed view of the sky: go outside for the best reception, although getting close to a window may help.
|
||||
|
||||
Although different GPS devices behave differently when they do not have a fix, you may be able to determine how many satellites are being received from what is being reported.
|
||||
|
||||
As soon as the GPS device receives a signal from just one satellite, the status may change to "1" and the date and time will be reported:
|
||||
```
|
||||
Local time,Status,UTC Date/Time,Lat,Lon,Hdg,Spd,Alt,HDOP,Rx ok,Rx err,Rx chars,
|
||||
2015-09-14 15:07:30,1,2015-09-14 19:07:30.00,,,,,,3,0,259,
|
||||
2015-09-14 15:07:31,1,2015-09-14 19:07:30.00,,,,,,3,0,521,
|
||||
```
|
||||
If it continues to report only date and time, you do not have an unobstructed view of the sky: only one satellite signal is being received.
|
||||
|
||||
When signals from three satellites are being received, the GPS device will start reporting latitude and longitude.
|
||||
When signals from four or more satellites are being received, the GPS device will start reporting altitude.
|
||||
|
||||
You can also enable other `gps_fix` fields or NMEA sentences. In **GPSfix_cfg.h**, uncomment this line:
|
||||
```
|
||||
#define GPS_FIX_SATELLITES
|
||||
```
|
||||
In **NMEAGPS_cfg.h** uncomment these lines:
|
||||
```
|
||||
#define NMEAGPS_PARSE_GGA
|
||||
#define NMEAGPS_PARSE_GSA
|
||||
#define NMEAGPS_PARSE_GSV
|
||||
|
||||
#define NMEAGPS_PARSE_SATELLITES
|
||||
#define NMEAGPS_PARSE_SATELLITE_INFO
|
||||
#define NMEAGPS_MAX_SATELLITES (20)
|
||||
```
|
||||
This will display additional fields for how many satellites are in view, whether they are being "tracked", and their individual signal strengths.
|
||||
```
|
||||
Local time,Status,UTC Date/Time,Lat,Lon,Hdg,Spd,Alt,HDOP,VDOP,PDOP,Lat err,Lon err,Alt err,Sats,[sat elev/az @ SNR],Rx ok,Rx err,Rx chars,
|
||||
2015-09-14 16:03:07,3,2015-09-14 20:03:07.00,,,,,,,,,,,,2,[2 71/27@14,5 65/197@33,],8,0,476,
|
||||
2015-09-14 16:03:08,3,2015-09-14 20:03:08.00,,,,,,,,,,,,2,[2 71/27@14,5 65/197@33,],16,0,952,
|
||||
```
|
||||
This shows that only two satellites are being tracked. You must move to a position with a better view of the sky.
|
||||
|
||||
__________________
|
||||
## Quiet Time Interval
|
||||
Because GPS devices send lots of data, it is possible for the Arduino input buffer to overflow. Many other libraries' examples will fail when modified to print too much information, or write to an SD card (see also [next section](#trying-to-do-too-many-things)).
|
||||
|
||||
NeoGPS examples are structured in a way that takes advantage of a "quiet time" in the data stream. GPS devices send a batch of sentences, once per second. After the last sentence in the batch has been sent, the GPS device will not send any more data until the next interval. The example programs watch for that last sentence. When it is received, it is safe to perform time-consuming operations.
|
||||
|
||||
It is **critical** to know the order of the sentences sent by your specific device. If you do not know what sentence is last in a batch, use the example program `NMEAorder.ino` to list the sentence order. When you know the last sentence, review `NMEAGPS_cfg.h` to confirm that the correct value on this line:
|
||||
|
||||
```
|
||||
#define LAST_SENTENCE_IN_INTERVAL NMEAGPS::NMEA_GLL
|
||||
```
|
||||
|
||||
Most example programs depend on this statement. `NMEAdiagnostic.ino` will emit a warning if that sentence is never recevied. If `LAST_SENTENCE_IN_INTERVAL` is not correct for your device, the example programs will probably lose GPS data, especially on `SoftwareSerial` data ports. The example programs may behave like they are using the wrong baud rate: empty fields, increasing Rx Errors, and increasing Rx Chars. Basically, the example programs are [Trying To Do Too Much](#trying-to-do-too-many-things) at the wrong time. With the correct `LAST_SENTENCE_IN_INTERVAL`, the example programs will not lose GPS data.
|
||||
|
||||
## Configuration errors
|
||||
Because there are so many configurable items, it is possible that your configuration prevents acquiring the desired GPS information.
|
||||
|
||||
The compiler **cannot** catch message set dependencies: the enum
|
||||
`nmea_msg_t` is always available. So even though a `fix` member is enabled,
|
||||
you may have disabled all messages that would have set its value.
|
||||
`NMEAtest.ino` can be used to check some configurations.
|
||||
|
||||
For example, if your application needs altitude, you **must** enable the GGA sentence. No other sentence provides the altitude member (see [this table](Choosing.md)). If `NMEA_PARSE_GGA` is not defined, `gps.decode()` will return COMPLETED after a GGA is received, but no parts of the GGA sentence will have been parsed, and altitude will never be valid. NeoGPS will _recognize_ the GGA sentence, but it will not be parsed.
|
||||
|
||||
The compiler will catch any attempt to use parts of a `fix` that have been
|
||||
configured out: you will see something like `gps_fix does not have member
|
||||
xxx`.
|
||||
|
||||
There are also compile-time checks to make sure the configuration is valid. For example, if you enable `NMEAGPS_PARSE_SATELLITES` so that you can access the array of satellite information, you *must* enable `GPS_FIX_SATELLITES`. An error message will tell you to do that. Until you disable `NMEAGPS_PARSE_SATELLITES` **or** enable `GPS_FIX_SATELLITES`, it will not compile.
|
||||
|
||||
__________________
|
||||
## Trying to do too many things
|
||||
Many libraries and their examples, and I mean almost all of 'em, are not structured in a way that lets you do more than one thing in a sketch. The result: the example program works great, but adding anything to it breaks it.
|
||||
|
||||
#### Printing too much
|
||||
Many programmers run into trouble because they try to print too much debug info. The Arduino `Serial.print` function will "block" until those output characters can be stored in a buffer. While the sketch is blocked at `Serial.print`, the GPS device is probably still sending data. The _input_ buffer on an Arduino is only 64 bytes, about the size of one NMEA sentence. After 64 bytes have been received stored, all other data is dropped! Depending on the GPS baud rate and the Serial Monitor baud rate, it may be very easy to lose GPS characters.
|
||||
|
||||
It is crucial to call `gps.available( gps_port )` or `serial.read()` frequently, and _never_ to call a blocking function that takes more than (64*11/baud) seconds. If the GPS is running at 9600, you cannot block for more than 70ms. If your debug `Serial` is also running at 9600, you cannot write more than 64 bytes consecutively (i.e., in less than 70ms).
|
||||
|
||||
#### Blocking operations
|
||||
Most Arduino libraries are written in a blocking fashion. That is, if you call a library's function, it will not return from that function until the operation has been completed. If that operation takes a long time, GPS characters will be dropped.
|
||||
|
||||
Many programmers want to write GPS data to an SD card. This is completely reasonable to do, but an `SD.write` can block long enough to cause the input buffer to overflow. SD libraries have their own buffers, and when they are filled, the library performs SPI operations to "flush" the buffer to the SD card. While that is happening, the GPS device is _still_ sending data, and it will eventually overflow the serial input buffer.
|
||||
|
||||
This is a very common problem! Here are some diagrams to help explain the timing for the Adafruit_GPS library. First, lets look at how the incoming GPS data relates to reading and parsing it:
|
||||
|
||||
<img src="images/GPS%20Timing%200.jpg"/>
|
||||
|
||||
Note how loop calls GPS.read, and when it has read all the chars that have been received up to that point, it returns. loop may get called lots of times while it's waiting for the chars to come in. Eventually, the whole sentence is received, newNMEAreceived returns true, and your sketch can `parse` the new data (not needed for **NeoGPS**).
|
||||
|
||||
The problem is that if you try to do anything that takes "too long", `GPS.read` won't get called. The incoming chars stack up in the input buffer until it's full. After that, the chars will be dropped:
|
||||
|
||||
<img src="images/GPS%20Timing%201.jpg"/>
|
||||
|
||||
The next sentence, a GPRMC, continues to come in while `Serial.print` and `SD.write` are doing their thing... and data gets lost.
|
||||
|
||||
Fortunately, there are two ways to work around this:
|
||||
|
||||
#### **1)** Use an interrupt-driven approach
|
||||
|
||||
The received data could be handled by an **I**nterrupt **S**ervice **R**outine. The example program [NMEA_isr.INO](/examples/NMEA_isr/NMEA_isr.ino) shows how to handle the received GPS characters *during* the RX interrupt. This program uses one of the replacement **NeoXXSerial** libraries to attach an interrupt handler to the GPS serial port.
|
||||
|
||||
When a character is received, the ISR is called, where it is immediately decoded. Normally, the character is stored in an input buffer, and you have to call `available()` and then `read()` to retrieve the character. Handling it in the ISR totally avoids having to continuously call `Serial1.read()`, and is much more efficient. Your program does not have to be structured around the GPS quiet time.
|
||||
|
||||
The ISR can also save (i.e., "buffer") complete fixes as they are completed. This allows the main sketch to perform an operation that takes multiple update intervals. This is especially important if your GPS is sending updates 10 times per second (10Hz), and your SD card takes ~150ms to complete a logging write.
|
||||
|
||||
Normally, this would cause a loss of data. You can specify the number of fixes to be stored by the ISR for later use: simply set NMEAGPS_FIX_MAX to 2. This will allow 2 complete fixes, accumulated from several sentences each, to be stored until `loop()` can call `gps.read()`. This is referred to as "fix-oriented operation" in the Data Model description.
|
||||
|
||||
While interrupt handling is considered a more advanced technique, it is similar to the existing Arduino [attachInterrupt](https://www.arduino.cc/en/Reference/AttachInterrupt) function for detecting when pin change.
|
||||
|
||||
Which **NeoXXLibrary** should you use?
|
||||
|
||||
* If `Serial` or `Serial1` is connected to the GPS device, you can use [NeoHWSerial](https://github.com/SlashDevin/NeoHWSerial).
|
||||
* If the Input Capture pin can be connected to the GPS device, as required for AltSoftSerial, you can use [NeoICSerial](https://github.com/SlashDevin/NeoICSerial).
|
||||
* If neither of those connections is possible, you can [NeoSWSerial](https://github.com/SlashDevin/NeoSWSerial) on almost any pair of digital pins. It only supports a few baud rates, though.
|
||||
|
||||
#### **2)** Restructure `loop()` to do time-consuming operations during the GPS [quiet time](#quiet-time-interval).
|
||||
|
||||
All non-ISR example programs are structured this way. The "quiet time" is perfect for doing other things:
|
||||
|
||||
<img src="images/GPS%20Timing%202.jpg"/>
|
||||
|
||||
All you need to do is hold on to the GPS information (date, time, location, etc.) until the quiet time comes around. You'll need to take the same approach for each additional task. For additional sensors, hold on to the temperature, acceleration, whatever, until the quiet time comes around. *Then* perform the blocking operation, like `SD.write`, and no GPS data will be lost.
|
||||
|
||||
This is why NeoGPS uses a `fix` structure: it can be
|
||||
* _populated_ as the characters are received,
|
||||
* _copied/merged_ when a sentence is complete, and then
|
||||
* _used_ anytime (for fast operations) or during the quiet time (for slow operations).
|
||||
|
||||
You do not have to call a "parse" function after a complete sentence has been received -- the data was parsed as it was received. Essentially, the processing time for parsing is spread out across the receipt of all characters. When the last character of the sentence is received (i.e. `gps.available()` or `gps.decode(c) == DECODE_COMPLETED`), the relevant members of `gps.fix()` have already been populated.
|
||||
|
||||
These example programs are structured so that the (relatively) slow printing operations are performed during the GPS quiet time. Simply replace those trace/print statements with your specific code.
|
||||
|
||||
__________________
|
||||
## When all else fails
|
||||
|
||||
If you still do not have enough time to complete your tasks during the GPS quiet time, you can
|
||||
* Increase the baud rate on the debug port (takes less time to print)
|
||||
* Increase the baud rate on the GPS port (increases quiet time)
|
||||
* Configure the GPS device to send fewer sentences (decreases parsing time, increases quiet time)
|
||||
* Use a binary protocol for your specific device (decreases parsing time, increases quiet time)
|
||||
* Watch for a specific message to be COMPLETED, then begin your specific processing. This may cause some sentences to lose characters, but they may not be necessary. See comments regarding `LAST_SENTENCE_IN_INTERVAL` above.
|
||||
* Use the interrupt-driven approach, described above. It is *guaranteed* to work!
|
||||
1
software/firmware/libraries/NeoGPS/extras/doc/readme.txt
Normal file
1
software/firmware/libraries/NeoGPS/extras/doc/readme.txt
Normal file
@@ -0,0 +1 @@
|
||||
These .MD files are in github markdown format. They are intended to be read on the github website, as linked from the top repository page.
|
||||
61
software/firmware/libraries/NeoGPS/extras/doc/ublox.md
Normal file
61
software/firmware/libraries/NeoGPS/extras/doc/ublox.md
Normal file
@@ -0,0 +1,61 @@
|
||||
NeoGPS support for u-blox GPS devices
|
||||
=================
|
||||
To use either ublox-specific NMEA messages ($PUBX) or the UBX binary protocol, you must enable the following in `NMEAGPS_cfg.h`:
|
||||
```
|
||||
#define NMEAGPS_PARSE_MFR_ID
|
||||
|
||||
#define NMEAGPS_DERIVED_TYPES
|
||||
```
|
||||
|
||||
## ublox-specific NMEA messages
|
||||
**NeoGPS** implements the following additional NMEA messages:
|
||||
|
||||
#NMEA 0183 Proprietary Messages
|
||||
* UBX,00 - Lat/Long Position Data
|
||||
* UBX,04 - Time of Day and Clock Information
|
||||
|
||||
You may want to change the configured PUBX messages in `ubxNMEA.h`. It is currently configured to work with the example application, `PUBX.ino`.
|
||||
|
||||
The derived class `ubloxNMEA` has the following configuration items near the top of ubxNMEA.h:
|
||||
```
|
||||
#define NMEAGPS_PARSE_PUBX_00
|
||||
#define NMEAGPS_PARSE_PUBX_04
|
||||
```
|
||||
|
||||
## ublox-specific binary protocol
|
||||
|
||||
**NeoGPS** implements the following messages in the UBX binary protocol:
|
||||
|
||||
#UBX Protocol Messages
|
||||
|
||||
* NAV_STATUS - Receiver Navigation Status
|
||||
* NAV_TIMEGPS - GPS Time Solution
|
||||
* NAV_TIMEUTC - UTC Time Solution
|
||||
* NAV_POSLLH - Geodetic Position Solution
|
||||
* NAV_VELNED - Velocity Solution in NED (North/East/Down)
|
||||
* NAV_SVINFO - Space Vehicle Information
|
||||
|
||||
You may want to change the configured UBX messages in `ubx_cfg.h`. It is currently configured to work with the example application `ublox.ino`.
|
||||
|
||||
The configuration file `ubx_cfg.h` has the following configuration items near the top of the file:
|
||||
```
|
||||
#define UBLOX_PARSE_STATUS
|
||||
#define UBLOX_PARSE_TIMEGPS
|
||||
#define UBLOX_PARSE_TIMEUTC
|
||||
#define UBLOX_PARSE_POSLLH
|
||||
//#define UBLOX_PARSE_DOP
|
||||
#define UBLOX_PARSE_VELNED
|
||||
#define UBLOX_PARSE_SVINFO
|
||||
```
|
||||
|
||||
**Note:** Disabling some of the UBX messages may prevent the `ublox.ino` example sketch from working. That sketch goes through a process of first acquiring the current GPS leap seconds and UTC time so that "time-of-week" milliseconds can be converted to a UTC time.
|
||||
|
||||
The POSLLH and VELNED messages use a Time-Of-Week timestamp. Without the TIMEGPS and TIMEUTC messages, that TOW timestamp cannot be converted to a UTC time.
|
||||
|
||||
* If your application does not need the UTC date and/or time, you could disable the TIMEGPS and TIMEUTC messages.
|
||||
|
||||
* If your application does not need latitude, longitude or altitude, you could disable the POSLLH message.
|
||||
|
||||
* If your application does not need speed or heading, you could disable the VELNED message.
|
||||
|
||||
* If your application does not need satellite information, you could disable the SVINFO message.
|
||||
Reference in New Issue
Block a user