From 39f391181d137b2bf3152fd6036300b5c1809651 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Thu, 27 Jul 2017 10:46:06 +0200 Subject: [PATCH 01/38] feat: allow compilation without ARDUINO --- src/CosaCompat.h | 18 ++- src/DMS.cpp | 8 +- src/DMS.h | 10 +- src/Location.cpp | 2 +- src/Location.h | 8 +- src/NMEAGPS.cpp | 288 ++++++++++++++++++++++++----------------------- src/NMEAGPS.h | 101 +++++++++-------- src/NeoGPS_cfg.h | 5 +- src/NeoTime.cpp | 50 ++++---- src/NeoTime.h | 24 ++-- 10 files changed, 284 insertions(+), 230 deletions(-) diff --git a/src/CosaCompat.h b/src/CosaCompat.h index 98143df..a2912f3 100644 --- a/src/CosaCompat.h +++ b/src/CosaCompat.h @@ -12,6 +12,22 @@ #endif typedef PGM_P str_P; + #define __PROGMEM PROGMEM -#endif \ No newline at end of file +#ifndef ARDUINO + #include + #define PROGMEM + + #define pgm_read_byte(x) (*(x)) + #define __FlashStringHelper char + #define F(x) (x) + + #include + constexpr double pi() { return std::atan(1)*4; } + + #define PI pi() + #define TWO_PI pi() * 2 +#endif + +#endif diff --git a/src/DMS.cpp b/src/DMS.cpp index bab8621..1a6b2a0 100644 --- a/src/DMS.cpp +++ b/src/DMS.cpp @@ -18,7 +18,9 @@ #include "DMS.h" -#include +#ifdef ARDUINO + #include +#endif //---------------------------------------------------------------- // Note that no division is used, and shifts are on byte boundaries. Fast! @@ -66,6 +68,7 @@ void DMS_t::From( int32_t deg_1E7 ) } // From //---------------------------------------------------------------- +#ifdef ARDUINO Print & operator << ( Print & outs, const DMS_t & dms ) { @@ -119,4 +122,5 @@ void DMS_t::printDDDMMmmmm( Print & outs ) const if (mmmm < 10) outs.print( '0' ); outs.print( mmmm ); -} \ No newline at end of file +} +#endif diff --git a/src/DMS.h b/src/DMS.h index 3b26efc..0a23a13 100644 --- a/src/DMS.h +++ b/src/DMS.h @@ -21,7 +21,9 @@ #include "NeoGPS_cfg.h" #include -class Print; +#ifdef ARDUINO + class Print; +#endif enum Hemisphere_t { NORTH_H = 0, SOUTH_H = 1, EAST_H = 0, WEST_H = 1 }; @@ -51,6 +53,8 @@ class DMS_t } NEOGPS_PACKED; -extern Print & operator << ( Print & outs, const DMS_t & ); +#ifdef ARDUINO + extern Print & operator << ( Print & outs, const DMS_t & ); +#endif -#endif \ No newline at end of file +#endif diff --git a/src/Location.cpp b/src/Location.cpp index fed8604..7b3750a 100644 --- a/src/Location.cpp +++ b/src/Location.cpp @@ -117,4 +117,4 @@ void Location_t::OffsetBy( float distR, float bearingR ) _lat = (newLat / (RAD_PER_DEG * LOC_SCALE)); _lon += (dLon / (RAD_PER_DEG * LOC_SCALE)); -} // OffsetBy \ No newline at end of file +} // OffsetBy diff --git a/src/Location.h b/src/Location.h index 65bfc6b..747b5fa 100644 --- a/src/Location.h +++ b/src/Location.h @@ -1,7 +1,11 @@ #ifndef NEOGPS_LOCATION_H #define NEOGPS_LOCATION_H -#include +#ifdef ARDUINO + #include +#else + #include "CosaCompat.h" +#endif #include "NeoGPS_cfg.h" @@ -126,4 +130,4 @@ class Location_t } // NeoGPS -#endif \ No newline at end of file +#endif diff --git a/src/NMEAGPS.cpp b/src/NMEAGPS.cpp index 2792c3a..aae0c67 100644 --- a/src/NMEAGPS.cpp +++ b/src/NMEAGPS.cpp @@ -18,7 +18,9 @@ #include "NMEAGPS.h" -#include +#ifdef ARDUINO + #include +#endif // Check configurations @@ -445,7 +447,7 @@ static const char * const std_nmea[] __PROGMEM = const NMEAGPS::msg_table_t NMEAGPS::nmea_msg_table __PROGMEM = { NMEAGPS::NMEA_FIRST_MSG, - (const msg_table_t *) NULL, + (const msg_table_t *) 0x00, sizeof(std_nmea)/sizeof(std_nmea[0]), std_nmea }; @@ -660,7 +662,7 @@ const __FlashStringHelper *NMEAGPS::string_for( nmea_msg_t msg ) const continue; #endif - return (const __FlashStringHelper *) NULL; + return (const __FlashStringHelper *) 0x00; } } // string_for @@ -1589,145 +1591,147 @@ const gps_fix NMEAGPS::read() //---------------------------------------------------------------- -void NMEAGPS::poll( Stream *device, nmea_msg_t msg ) -{ - // Only the ublox documentation references talker ID "EI". - // Other manufacturer's devices use "II" and "GP" talker IDs for the GPQ sentence. - // However, "GP" is reserved for the GPS device, so it seems inconsistent - // to use that talker ID when requesting something from the GPS device. - - #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gga[] __PROGMEM = "EIGPQ,GGA"; - #endif - #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gll[] __PROGMEM = "EIGPQ,GLL"; - #endif - #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gsa[] __PROGMEM = "EIGPQ,GSA"; - #endif - #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gst[] __PROGMEM = "EIGPQ,GST"; - #endif - #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gsv[] __PROGMEM = "EIGPQ,GSV"; - #endif - #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char rmc[] __PROGMEM = "EIGPQ,RMC"; - #endif - #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char vtg[] __PROGMEM = "EIGPQ,VTG"; - #endif - #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char zda[] __PROGMEM = "EIGPQ,ZDA"; - #endif - - static const char * const poll_msgs[] __PROGMEM = - { - #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) - gga, - #endif - #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) - gll, - #endif - #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) - gsa, - #endif - #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) - gst, - #endif - #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) - gsv, - #endif - #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) - rmc, - #endif - #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) - vtg, - #endif - #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) - zda - #endif - }; - - if ((NMEA_FIRST_MSG <= msg) && (msg <= NMEA_LAST_MSG)) { - #ifdef __AVR__ - const __FlashStringHelper * pollCmd = - (const __FlashStringHelper *) pgm_read_word(&poll_msgs[msg-NMEA_FIRST_MSG]); - #else - const __FlashStringHelper * pollCmd = - (const __FlashStringHelper *) poll_msgs[msg-NMEA_FIRST_MSG]; +#ifdef ARDUINO + void NMEAGPS::poll( Stream *device, nmea_msg_t msg ) + { + // Only the ublox documentation references talker ID "EI". + // Other manufacturer's devices use "II" and "GP" talker IDs for the GPQ sentence. + // However, "GP" is reserved for the GPS device, so it seems inconsistent + // to use that talker ID when requesting something from the GPS device. + + #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gga[] __PROGMEM = "EIGPQ,GGA"; #endif - send_P( device, pollCmd ); - } - -} // poll - -//---------------------------------------------------------------- - -static void send_trailer( Stream *device, uint8_t crc ) -{ - device->print('*'); - - char hexDigit = formatHex( crc>>4 ); - device->print( hexDigit ); - - hexDigit = formatHex( crc ); - device->print( hexDigit ); - - device->print( CR ); - device->print( LF ); - -} // send_trailer - -//---------------------------------------------------------------- - -void NMEAGPS::send( Stream *device, const char *msg ) -{ - if (msg && *msg) { - if (*msg == '$') - msg++; - device->print('$'); - uint8_t sent_trailer = 0; - uint8_t crc = 0; - while (*msg) { - if ((*msg == '*') || (sent_trailer > 0)) - sent_trailer++; - else - crc ^= *msg; - device->print( *msg++ ); + #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gll[] __PROGMEM = "EIGPQ,GLL"; + #endif + #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gsa[] __PROGMEM = "EIGPQ,GSA"; + #endif + #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gst[] __PROGMEM = "EIGPQ,GST"; + #endif + #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gsv[] __PROGMEM = "EIGPQ,GSV"; + #endif + #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char rmc[] __PROGMEM = "EIGPQ,RMC"; + #endif + #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char vtg[] __PROGMEM = "EIGPQ,VTG"; + #endif + #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char zda[] __PROGMEM = "EIGPQ,ZDA"; + #endif + + static const char * const poll_msgs[] __PROGMEM = + { + #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) + gga, + #endif + #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) + gll, + #endif + #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) + gsa, + #endif + #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) + gst, + #endif + #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) + gsv, + #endif + #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) + rmc, + #endif + #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) + vtg, + #endif + #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) + zda + #endif + }; + + if ((NMEA_FIRST_MSG <= msg) && (msg <= NMEA_LAST_MSG)) { + #ifdef __AVR__ + const __FlashStringHelper * pollCmd = + (const __FlashStringHelper *) pgm_read_word(&poll_msgs[msg-NMEA_FIRST_MSG]); + #else + const __FlashStringHelper * pollCmd = + (const __FlashStringHelper *) poll_msgs[msg-NMEA_FIRST_MSG]; + #endif + send_P( device, pollCmd ); } - - if (!sent_trailer) - send_trailer( device, crc ); - } - -} // send - -//---------------------------------------------------------------- - -void NMEAGPS::send_P( Stream *device, const __FlashStringHelper *msg ) -{ - if (msg) { - const char *ptr = (const char *)msg; - char chr = pgm_read_byte(ptr++); - - device->print('$'); - if (chr == '$') - chr = pgm_read_byte(ptr++); - uint8_t sent_trailer = 0; - uint8_t crc = 0; - while (chr) { - if ((chr == '*') || (sent_trailer > 0)) - sent_trailer++; - else - crc ^= chr; - device->print( chr ); - - chr = pgm_read_byte(ptr++); + + } // poll + + //---------------------------------------------------------------- + + static void send_trailer( Stream *device, uint8_t crc ) + { + device->print('*'); + + char hexDigit = formatHex( crc>>4 ); + device->print( hexDigit ); + + hexDigit = formatHex( crc ); + device->print( hexDigit ); + + device->print( CR ); + device->print( LF ); + + } // send_trailer + + //---------------------------------------------------------------- + + void NMEAGPS::send( Stream *device, const char *msg ) + { + if (msg && *msg) { + if (*msg == '$') + msg++; + device->print('$'); + uint8_t sent_trailer = 0; + uint8_t crc = 0; + while (*msg) { + if ((*msg == '*') || (sent_trailer > 0)) + sent_trailer++; + else + crc ^= *msg; + device->print( *msg++ ); + } + + if (!sent_trailer) + send_trailer( device, crc ); } - - if (!sent_trailer) - send_trailer( device, crc ); - } - -} // send_P + + } // send + + //---------------------------------------------------------------- + + void NMEAGPS::send_P( Stream *device, const __FlashStringHelper *msg ) + { + if (msg) { + const char *ptr = (const char *)msg; + char chr = pgm_read_byte(ptr++); + + device->print('$'); + if (chr == '$') + chr = pgm_read_byte(ptr++); + uint8_t sent_trailer = 0; + uint8_t crc = 0; + while (chr) { + if ((chr == '*') || (sent_trailer > 0)) + sent_trailer++; + else + crc ^= chr; + device->print( chr ); + + chr = pgm_read_byte(ptr++); + } + + if (!sent_trailer) + send_trailer( device, crc ); + } + + } // send_P +#endif diff --git a/src/NMEAGPS.h b/src/NMEAGPS.h index cb56e05..4ef5dd3 100644 --- a/src/NMEAGPS.h +++ b/src/NMEAGPS.h @@ -21,9 +21,11 @@ #include "CosaCompat.h" -#include -#ifdef __AVR__ - #include +#ifdef ARDUINO + #include + #ifdef __AVR__ + #include + #endif #endif #include "GPSfix.h" @@ -96,22 +98,25 @@ class NMEAGPS CONST_CLASS_DATA nmea_msg_t NMEA_FIRST_MSG = (nmea_msg_t) (NMEA_UNKNOWN+1); CONST_CLASS_DATA nmea_msg_t NMEA_LAST_MSG = (nmea_msg_t) (NMEAMSG_END-1); - //======================================================================= - // FIX-ORIENTED methods: available, read and handle - //======================================================================= - - //....................................................................... - // The available(...) functions return the number of *fixes* that - // are available to be "read" from the fix buffer. The GPS port - // object is passed in so a char can be read if port.available(). - - uint8_t available( Stream & port ) - { - if (processing_style == PS_POLLING) - while (port.available()) - handle( port.read() ); - return _available(); - } + #ifdef ARDUINO + //======================================================================= + // FIX-ORIENTED methods: available, read and handle + //======================================================================= + + //....................................................................... + // The available(...) functions return the number of *fixes* that + // are available to be "read" from the fix buffer. The GPS port + // object is passed in so a char can be read if port.available(). + + uint8_t available( Stream & port ) + { + if (processing_style == PS_POLLING) + while (port.available()) + handle( port.read() ); + return _available(); + } + #endif + uint8_t available() const volatile { return _available(); }; //....................................................................... @@ -166,7 +171,7 @@ class NMEAGPS // Convert a nmea_msg_t to a PROGMEM string. // Useful for printing the sentence type instead of a number. // This can return "UNK" if the message is not a valid number. - + const __FlashStringHelper *string_for( nmea_msg_t msg ) const; //....................................................................... @@ -227,17 +232,19 @@ class NMEAGPS } statistics; #endif - //....................................................................... - // Request the specified NMEA sentence. Not all devices will respond. - - static void poll( Stream *device, nmea_msg_t msg ); - - //....................................................................... - // Send a message to the GPS device. - // The '$' is optional, and the '*' and CS will be added automatically. - - static void send( Stream *device, const char *msg ); - static void send_P( Stream *device, const __FlashStringHelper *msg ); + #ifdef ARDUINO + //....................................................................... + // Request the specified NMEA sentence. Not all devices will respond. + + static void poll( Stream *device, nmea_msg_t msg ); + + //....................................................................... + // Send a message to the GPS device. + // The '$' is optional, and the '*' and CS will be added automatically. + + static void send( Stream *device, const char *msg ); + static void send_P( Stream *device, const __FlashStringHelper *msg ); + #endif //....................................................................... // Indicate that the next sentence should initialize the internal data. @@ -249,8 +256,9 @@ class NMEAGPS //....................................................................... // Correlate the Arduino micros() clock with UTC. - #if defined(NMEAGPS_TIMESTAMP_FROM_PPS) | \ - defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL) + #if defined ARDUINO && \ + (defined(NMEAGPS_TIMESTAMP_FROM_PPS) | \ + defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL)) private: uint32_t _UTCsecondStart; #if defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL) & \ @@ -339,17 +347,22 @@ class NMEAGPS // Control access to this object. This preserves atomicity when // the processing style is interrupt-driven. - void lock() const - { - if (processing_style == PS_INTERRUPT) - noInterrupts(); - } - - void unlock() const - { - if (processing_style == PS_INTERRUPT) - interrupts(); - } + #ifdef ARDUINO + void lock() const + { + if (processing_style == PS_INTERRUPT) + noInterrupts(); + } + + void unlock() const + { + if (processing_style == PS_INTERRUPT) + interrupts(); + } + #else + void lock() const; + void unlock() const; + #endif protected: // Current fix diff --git a/src/NeoGPS_cfg.h b/src/NeoGPS_cfg.h index b325f06..d17cbce 100644 --- a/src/NeoGPS_cfg.h +++ b/src/NeoGPS_cfg.h @@ -72,7 +72,10 @@ * */ -#if (ARDUINO < 10606) | ((10700 <= ARDUINO) & (ARDUINO <= 10799)) | ((107000 <= ARDUINO) & (ARDUINO <= 107999)) +#if defined ARDUINO && \ + ((ARDUINO < 10606) | \ + ((10700 <= ARDUINO) & (ARDUINO <= 10799)) | \ + ((107000 <= ARDUINO) & (ARDUINO <= 107999))) #define CONST_CLASS_DATA static const diff --git a/src/NeoTime.cpp b/src/NeoTime.cpp index d2d336b..77dd584 100644 --- a/src/NeoTime.cpp +++ b/src/NeoTime.cpp @@ -24,29 +24,31 @@ // For strtoul declaration #include -#include - -Print & operator<<( Print& outs, const NeoGPS::time_t& t ) -{ - outs.print( t.full_year( t.year ) ); - outs.write( '-' ); - if (t.month < 10) outs.write( '0' ); - outs.print( t.month ); - outs.write( '-' ); - if (t.date < 10) outs.write( '0' ); - outs.print( t.date ); - outs.write( ' ' ); - if (t.hours < 10) outs.write( '0' ); - outs.print( t.hours ); - outs.write( ':' ); - if (t.minutes < 10) outs.write( '0' ); - outs.print( t.minutes ); - outs.write( ':' ); - if (t.seconds < 10) outs.write( '0' ); - outs.print( t.seconds ); - - return outs; -} +#ifdef ARDUINO + #include + + Print & operator<<( Print& outs, const NeoGPS::time_t& t ) + { + outs.print( t.full_year( t.year ) ); + outs.write( '-' ); + if (t.month < 10) outs.write( '0' ); + outs.print( t.month ); + outs.write( '-' ); + if (t.date < 10) outs.write( '0' ); + outs.print( t.date ); + outs.write( ' ' ); + if (t.hours < 10) outs.write( '0' ); + outs.print( t.hours ); + outs.write( ':' ); + if (t.minutes < 10) outs.write( '0' ); + outs.print( t.minutes ); + outs.write( ':' ); + if (t.seconds < 10) outs.write( '0' ); + outs.print( t.seconds ); + + return outs; + } +#endif using NeoGPS::time_t; @@ -209,4 +211,4 @@ uint16_t time_t::day_of_year() const epoch_weekday( compile_weekday ); pivot_year ( this_year.year ); } -#endif \ No newline at end of file +#endif diff --git a/src/NeoTime.h b/src/NeoTime.h index 67f792f..d92422b 100644 --- a/src/NeoTime.h +++ b/src/NeoTime.h @@ -22,7 +22,9 @@ #ifndef TIME_H #define TIME_H -#include +#ifdef ARDUINO + #include +#endif #include "NeoGPS_cfg.h" #include "CosaCompat.h" @@ -298,14 +300,16 @@ struct time_t { }; // namespace NeoGPS -class Print; - -/** - * Print the date/time to the given stream with the format "YYYY-MM-DD HH:MM:SS". - * @param[in] outs output stream. - * @param[in] t time structure. - * @return iostream. - */ -Print & operator <<( Print & outs, const NeoGPS::time_t &t ); +#ifdef ARDUINO + class Print; + + /** + * Print the date/time to the given stream with the format "YYYY-MM-DD HH:MM:SS". + * @param[in] outs output stream. + * @param[in] t time structure. + * @return iostream. + */ + Print & operator <<( Print & outs, const NeoGPS::time_t &t ); +#endif #endif From 813f8be4da5e5da205fbf4a6c2aa626aa3a0cd40 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Thu, 27 Jul 2017 22:50:16 +0200 Subject: [PATCH 02/38] feat: extract functionality into Arduino compat. libs --- src/CosaCompat.h | 15 --- src/NMEAGPS.cpp | 283 ++++++++++++++++++++--------------------- src/NMEAGPS.h | 92 ++++++-------- src/Platform.h | 31 +++++ src/platforms/Port.h | 6 + src/platforms/Stream.h | 11 ++ src/platforms/System.h | 4 + 7 files changed, 230 insertions(+), 212 deletions(-) create mode 100644 src/Platform.h create mode 100644 src/platforms/Port.h create mode 100644 src/platforms/Stream.h create mode 100644 src/platforms/System.h diff --git a/src/CosaCompat.h b/src/CosaCompat.h index a2912f3..e4f06c5 100644 --- a/src/CosaCompat.h +++ b/src/CosaCompat.h @@ -15,19 +15,4 @@ typedef PGM_P str_P; #define __PROGMEM PROGMEM -#ifndef ARDUINO - #include - #define PROGMEM - - #define pgm_read_byte(x) (*(x)) - #define __FlashStringHelper char - #define F(x) (x) - - #include - constexpr double pi() { return std::atan(1)*4; } - - #define PI pi() - #define TWO_PI pi() * 2 -#endif - #endif diff --git a/src/NMEAGPS.cpp b/src/NMEAGPS.cpp index aae0c67..927ec1f 100644 --- a/src/NMEAGPS.cpp +++ b/src/NMEAGPS.cpp @@ -18,9 +18,6 @@ #include "NMEAGPS.h" -#ifdef ARDUINO - #include -#endif // Check configurations @@ -1591,147 +1588,145 @@ const gps_fix NMEAGPS::read() //---------------------------------------------------------------- -#ifdef ARDUINO - void NMEAGPS::poll( Stream *device, nmea_msg_t msg ) - { - // Only the ublox documentation references talker ID "EI". - // Other manufacturer's devices use "II" and "GP" talker IDs for the GPQ sentence. - // However, "GP" is reserved for the GPS device, so it seems inconsistent - // to use that talker ID when requesting something from the GPS device. - - #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gga[] __PROGMEM = "EIGPQ,GGA"; - #endif - #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gll[] __PROGMEM = "EIGPQ,GLL"; - #endif - #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gsa[] __PROGMEM = "EIGPQ,GSA"; - #endif - #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gst[] __PROGMEM = "EIGPQ,GST"; - #endif - #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gsv[] __PROGMEM = "EIGPQ,GSV"; - #endif - #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char rmc[] __PROGMEM = "EIGPQ,RMC"; - #endif - #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char vtg[] __PROGMEM = "EIGPQ,VTG"; - #endif - #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char zda[] __PROGMEM = "EIGPQ,ZDA"; - #endif - - static const char * const poll_msgs[] __PROGMEM = - { - #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) - gga, - #endif - #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) - gll, - #endif - #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) - gsa, - #endif - #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) - gst, - #endif - #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) - gsv, - #endif - #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) - rmc, - #endif - #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) - vtg, - #endif - #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) - zda - #endif - }; - - if ((NMEA_FIRST_MSG <= msg) && (msg <= NMEA_LAST_MSG)) { - #ifdef __AVR__ - const __FlashStringHelper * pollCmd = - (const __FlashStringHelper *) pgm_read_word(&poll_msgs[msg-NMEA_FIRST_MSG]); - #else - const __FlashStringHelper * pollCmd = - (const __FlashStringHelper *) poll_msgs[msg-NMEA_FIRST_MSG]; +void NMEAGPS::poll( Stream *device, nmea_msg_t msg ) +{ + // Only the ublox documentation references talker ID "EI". + // Other manufacturer's devices use "II" and "GP" talker IDs for the GPQ sentence. + // However, "GP" is reserved for the GPS device, so it seems inconsistent + // to use that talker ID when requesting something from the GPS device. + + #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gga[] __PROGMEM = "EIGPQ,GGA"; + #endif + #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gll[] __PROGMEM = "EIGPQ,GLL"; + #endif + #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gsa[] __PROGMEM = "EIGPQ,GSA"; + #endif + #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gst[] __PROGMEM = "EIGPQ,GST"; + #endif + #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gsv[] __PROGMEM = "EIGPQ,GSV"; + #endif + #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char rmc[] __PROGMEM = "EIGPQ,RMC"; + #endif + #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char vtg[] __PROGMEM = "EIGPQ,VTG"; + #endif + #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char zda[] __PROGMEM = "EIGPQ,ZDA"; + #endif + + static const char * const poll_msgs[] __PROGMEM = + { + #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) + gga, #endif - send_P( device, pollCmd ); - } - - } // poll - - //---------------------------------------------------------------- - - static void send_trailer( Stream *device, uint8_t crc ) - { - device->print('*'); - - char hexDigit = formatHex( crc>>4 ); - device->print( hexDigit ); - - hexDigit = formatHex( crc ); - device->print( hexDigit ); - - device->print( CR ); - device->print( LF ); - - } // send_trailer - - //---------------------------------------------------------------- - - void NMEAGPS::send( Stream *device, const char *msg ) - { - if (msg && *msg) { - if (*msg == '$') - msg++; - device->print('$'); - uint8_t sent_trailer = 0; - uint8_t crc = 0; - while (*msg) { - if ((*msg == '*') || (sent_trailer > 0)) - sent_trailer++; - else - crc ^= *msg; - device->print( *msg++ ); - } - - if (!sent_trailer) - send_trailer( device, crc ); + #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) + gll, + #endif + #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) + gsa, + #endif + #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) + gst, + #endif + #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) + gsv, + #endif + #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) + rmc, + #endif + #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) + vtg, + #endif + #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) + zda + #endif + }; + + if ((NMEA_FIRST_MSG <= msg) && (msg <= NMEA_LAST_MSG)) { + #ifdef __AVR__ + const __FlashStringHelper * pollCmd = + (const __FlashStringHelper *) pgm_read_word(&poll_msgs[msg-NMEA_FIRST_MSG]); + #else + const __FlashStringHelper * pollCmd = + (const __FlashStringHelper *) poll_msgs[msg-NMEA_FIRST_MSG]; + #endif + send_P( device, pollCmd ); + } + +} // poll + +//---------------------------------------------------------------- + +static void send_trailer( Stream *device, uint8_t crc ) +{ + device->print('*'); + + char hexDigit = formatHex( crc>>4 ); + device->print( hexDigit ); + + hexDigit = formatHex( crc ); + device->print( hexDigit ); + + device->print( CR ); + device->print( LF ); + +} // send_trailer + +//---------------------------------------------------------------- + +void NMEAGPS::send( Stream *device, const char *msg ) +{ + if (msg && *msg) { + if (*msg == '$') + msg++; + device->print('$'); + uint8_t sent_trailer = 0; + uint8_t crc = 0; + while (*msg) { + if ((*msg == '*') || (sent_trailer > 0)) + sent_trailer++; + else + crc ^= *msg; + device->print( *msg++ ); } - - } // send - - //---------------------------------------------------------------- - - void NMEAGPS::send_P( Stream *device, const __FlashStringHelper *msg ) - { - if (msg) { - const char *ptr = (const char *)msg; - char chr = pgm_read_byte(ptr++); - - device->print('$'); - if (chr == '$') - chr = pgm_read_byte(ptr++); - uint8_t sent_trailer = 0; - uint8_t crc = 0; - while (chr) { - if ((chr == '*') || (sent_trailer > 0)) - sent_trailer++; - else - crc ^= chr; - device->print( chr ); - - chr = pgm_read_byte(ptr++); - } - - if (!sent_trailer) - send_trailer( device, crc ); + + if (!sent_trailer) + send_trailer( device, crc ); + } + +} // send + +//---------------------------------------------------------------- + +void NMEAGPS::send_P( Stream *device, const __FlashStringHelper *msg ) +{ + if (msg) { + const char *ptr = (const char *)msg; + char chr = pgm_read_byte(ptr++); + + device->print('$'); + if (chr == '$') + chr = pgm_read_byte(ptr++); + uint8_t sent_trailer = 0; + uint8_t crc = 0; + while (chr) { + if ((chr == '*') || (sent_trailer > 0)) + sent_trailer++; + else + crc ^= chr; + device->print( chr ); + + chr = pgm_read_byte(ptr++); } - - } // send_P -#endif + + if (!sent_trailer) + send_trailer( device, crc ); + } + +} // send_P diff --git a/src/NMEAGPS.h b/src/NMEAGPS.h index 4ef5dd3..66e71d1 100644 --- a/src/NMEAGPS.h +++ b/src/NMEAGPS.h @@ -21,12 +21,7 @@ #include "CosaCompat.h" -#ifdef ARDUINO - #include - #ifdef __AVR__ - #include - #endif -#endif +#include "Platform.h" #include "GPSfix.h" #include "NMEAGPS_cfg.h" @@ -98,24 +93,22 @@ class NMEAGPS CONST_CLASS_DATA nmea_msg_t NMEA_FIRST_MSG = (nmea_msg_t) (NMEA_UNKNOWN+1); CONST_CLASS_DATA nmea_msg_t NMEA_LAST_MSG = (nmea_msg_t) (NMEAMSG_END-1); - #ifdef ARDUINO - //======================================================================= - // FIX-ORIENTED methods: available, read and handle - //======================================================================= - - //....................................................................... - // The available(...) functions return the number of *fixes* that - // are available to be "read" from the fix buffer. The GPS port - // object is passed in so a char can be read if port.available(). - - uint8_t available( Stream & port ) - { - if (processing_style == PS_POLLING) - while (port.available()) - handle( port.read() ); - return _available(); - } - #endif + //======================================================================= + // FIX-ORIENTED methods: available, read and handle + //======================================================================= + + //....................................................................... + // The available(...) functions return the number of *fixes* that + // are available to be "read" from the fix buffer. The GPS port + // object is passed in so a char can be read if port.available(). + + uint8_t available( Stream & port ) + { + if (processing_style == PS_POLLING) + while (port.available()) + handle( port.read() ); + return _available(); + } uint8_t available() const volatile { return _available(); }; @@ -232,19 +225,17 @@ class NMEAGPS } statistics; #endif - #ifdef ARDUINO - //....................................................................... - // Request the specified NMEA sentence. Not all devices will respond. - - static void poll( Stream *device, nmea_msg_t msg ); - - //....................................................................... - // Send a message to the GPS device. - // The '$' is optional, and the '*' and CS will be added automatically. - - static void send( Stream *device, const char *msg ); - static void send_P( Stream *device, const __FlashStringHelper *msg ); - #endif + //....................................................................... + // Request the specified NMEA sentence. Not all devices will respond. + + static void poll( Stream *device, nmea_msg_t msg ); + + //....................................................................... + // Send a message to the GPS device. + // The '$' is optional, and the '*' and CS will be added automatically. + + static void send( Stream *device, const char *msg ); + static void send_P( Stream *device, const __FlashStringHelper *msg ); //....................................................................... // Indicate that the next sentence should initialize the internal data. @@ -347,22 +338,17 @@ class NMEAGPS // Control access to this object. This preserves atomicity when // the processing style is interrupt-driven. - #ifdef ARDUINO - void lock() const - { - if (processing_style == PS_INTERRUPT) - noInterrupts(); - } - - void unlock() const - { - if (processing_style == PS_INTERRUPT) - interrupts(); - } - #else - void lock() const; - void unlock() const; - #endif + void lock() const + { + if (processing_style == PS_INTERRUPT) + noInterrupts(); + } + + void unlock() const + { + if (processing_style == PS_INTERRUPT) + interrupts(); + } protected: // Current fix diff --git a/src/Platform.h b/src/Platform.h new file mode 100644 index 0000000..47bb9d7 --- /dev/null +++ b/src/Platform.h @@ -0,0 +1,31 @@ +#pragma once + +/** + * This file contains platform related definitions and imports. + **/ +#ifdef ARDUINO + #include + #include + + #ifdef __AVR__ + #include + #endif +#else + #include "platforms/Stream.h" + #include "platforms/Port.h" + #include "platforms/System.h" + + #include + #define PROGMEM + + #define pgm_read_byte(x) (*(x)) + #define __FlashStringHelper char + #define F(x) (x) + + #include + constexpr double pi() { return std::atan(1)*4; } + + #define PI pi() + #define TWO_PI pi() * 2.0 + +#endif diff --git a/src/platforms/Port.h b/src/platforms/Port.h new file mode 100644 index 0000000..97663d0 --- /dev/null +++ b/src/platforms/Port.h @@ -0,0 +1,6 @@ +#pragma once + +#include +class Port { +public: +}; diff --git a/src/platforms/Stream.h b/src/platforms/Stream.h new file mode 100644 index 0000000..c5d4231 --- /dev/null +++ b/src/platforms/Stream.h @@ -0,0 +1,11 @@ +#pragma once + +#include +// If there is not already an implementation for your platform, +// implement these functions. +class Stream { +public: + bool available(); + uint8_t read(); + void print(uint8_t); +}; diff --git a/src/platforms/System.h b/src/platforms/System.h new file mode 100644 index 0000000..e161f77 --- /dev/null +++ b/src/platforms/System.h @@ -0,0 +1,4 @@ +#pragma once + +void interrupts(); +void noInterrupts(); From 31fc16163e3313a022e9e2d5f71efdd18162c98d Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Fri, 28 Jul 2017 01:30:57 +0200 Subject: [PATCH 03/38] feat: continue Arduino compat declarations replace 0x00 with nullptr --- src/NMEAGPS.cpp | 4 ++-- src/NeoTime.cpp | 46 ++++++++++++++++++++----------------------- src/NeoTime.h | 25 ++++++++++------------- src/Platform.h | 4 +++- src/platforms/Port.h | 6 ------ src/platforms/Print.h | 10 ++++++++++ 6 files changed, 46 insertions(+), 49 deletions(-) delete mode 100644 src/platforms/Port.h create mode 100644 src/platforms/Print.h diff --git a/src/NMEAGPS.cpp b/src/NMEAGPS.cpp index 927ec1f..606ec58 100644 --- a/src/NMEAGPS.cpp +++ b/src/NMEAGPS.cpp @@ -444,7 +444,7 @@ static const char * const std_nmea[] __PROGMEM = const NMEAGPS::msg_table_t NMEAGPS::nmea_msg_table __PROGMEM = { NMEAGPS::NMEA_FIRST_MSG, - (const msg_table_t *) 0x00, + (const msg_table_t *) nullptr, sizeof(std_nmea)/sizeof(std_nmea[0]), std_nmea }; @@ -659,7 +659,7 @@ const __FlashStringHelper *NMEAGPS::string_for( nmea_msg_t msg ) const continue; #endif - return (const __FlashStringHelper *) 0x00; + return (const __FlashStringHelper *) nullptr; } } // string_for diff --git a/src/NeoTime.cpp b/src/NeoTime.cpp index 77dd584..dbbe5fd 100644 --- a/src/NeoTime.cpp +++ b/src/NeoTime.cpp @@ -24,31 +24,27 @@ // For strtoul declaration #include -#ifdef ARDUINO - #include - - Print & operator<<( Print& outs, const NeoGPS::time_t& t ) - { - outs.print( t.full_year( t.year ) ); - outs.write( '-' ); - if (t.month < 10) outs.write( '0' ); - outs.print( t.month ); - outs.write( '-' ); - if (t.date < 10) outs.write( '0' ); - outs.print( t.date ); - outs.write( ' ' ); - if (t.hours < 10) outs.write( '0' ); - outs.print( t.hours ); - outs.write( ':' ); - if (t.minutes < 10) outs.write( '0' ); - outs.print( t.minutes ); - outs.write( ':' ); - if (t.seconds < 10) outs.write( '0' ); - outs.print( t.seconds ); - - return outs; - } -#endif +Print & operator<<( Print& outs, const NeoGPS::time_t& t ) +{ + outs.print( t.full_year( t.year ) ); + outs.write( '-' ); + if (t.month < 10) outs.write( '0' ); + outs.print( t.month ); + outs.write( '-' ); + if (t.date < 10) outs.write( '0' ); + outs.print( t.date ); + outs.write( ' ' ); + if (t.hours < 10) outs.write( '0' ); + outs.print( t.hours ); + outs.write( ':' ); + if (t.minutes < 10) outs.write( '0' ); + outs.print( t.minutes ); + outs.write( ':' ); + if (t.seconds < 10) outs.write( '0' ); + outs.print( t.seconds ); + + return outs; +} using NeoGPS::time_t; diff --git a/src/NeoTime.h b/src/NeoTime.h index d92422b..b0fd35f 100644 --- a/src/NeoTime.h +++ b/src/NeoTime.h @@ -22,12 +22,9 @@ #ifndef TIME_H #define TIME_H -#ifdef ARDUINO - #include -#endif +#include "Platform.h" #include "NeoGPS_cfg.h" -#include "CosaCompat.h" namespace NeoGPS { @@ -300,16 +297,14 @@ struct time_t { }; // namespace NeoGPS -#ifdef ARDUINO - class Print; - - /** - * Print the date/time to the given stream with the format "YYYY-MM-DD HH:MM:SS". - * @param[in] outs output stream. - * @param[in] t time structure. - * @return iostream. - */ - Print & operator <<( Print & outs, const NeoGPS::time_t &t ); -#endif +class Print; + +/** + * Print the date/time to the given stream with the format "YYYY-MM-DD HH:MM:SS". + * @param[in] outs output stream. + * @param[in] t time structure. + * @return iostream. + */ +Print & operator <<( Print & outs, const NeoGPS::time_t &t ); #endif diff --git a/src/Platform.h b/src/Platform.h index 47bb9d7..1f89640 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -5,14 +5,16 @@ **/ #ifdef ARDUINO #include + #include + #include #ifdef __AVR__ #include #endif #else #include "platforms/Stream.h" - #include "platforms/Port.h" + #include "platforms/Print.h" #include "platforms/System.h" #include diff --git a/src/platforms/Port.h b/src/platforms/Port.h deleted file mode 100644 index 97663d0..0000000 --- a/src/platforms/Port.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include -class Port { -public: -}; diff --git a/src/platforms/Print.h b/src/platforms/Print.h new file mode 100644 index 0000000..1331b4f --- /dev/null +++ b/src/platforms/Print.h @@ -0,0 +1,10 @@ +#pragma once + +#include +class Print { +public: + void print(uint8_t); + void print(uint16_t); + void print(uint32_t); + void write(char); +}; From 852821b0698781ed970c8884225226905fd0971e Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Mon, 7 Aug 2017 09:51:35 +0200 Subject: [PATCH 04/38] feat: add str_P to Platform.h also deactivate copying of string in parse. --- src/NeoTime.cpp | 12 ++++++++---- src/Platform.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/NeoTime.cpp b/src/NeoTime.cpp index dbbe5fd..b84226f 100644 --- a/src/NeoTime.cpp +++ b/src/NeoTime.cpp @@ -50,10 +50,14 @@ using NeoGPS::time_t; bool time_t::parse(str_P s) { - static size_t BUF_MAX = 32; - char buf[BUF_MAX]; - strcpy_P(buf, s); - char* sp = &buf[0]; + #ifdef AVR + static size_t BUF_MAX = 32; + char buf[BUF_MAX]; + strcpy_P(buf, s); + char* sp = &buf[0]; + #else + char* sp = &s[0]; + #endif uint16_t value = strtoul(sp, &sp, 10); if (*sp != '-') return false; diff --git a/src/Platform.h b/src/Platform.h index 1f89640..425a768 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -23,6 +23,7 @@ #define pgm_read_byte(x) (*(x)) #define __FlashStringHelper char #define F(x) (x) + #define str_P char * #include constexpr double pi() { return std::atan(1)*4; } From e9706e3a419554e56ad9f915e9574423326c8374 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Mon, 7 Aug 2017 10:25:53 +0200 Subject: [PATCH 05/38] feat[Platforms]: adapt DMS.h DMS.cpp Location.h to use Platform.h fix PI (std:atan(1)*4 is not a constexpr) --- src/DMS.cpp | 6 ------ src/DMS.h | 10 ++++------ src/Location.h | 6 +----- src/Platform.h | 5 ++--- src/Streamers.h | 4 ++-- src/platforms/Print.h | 10 ++++++---- 6 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/DMS.cpp b/src/DMS.cpp index 1a6b2a0..82f0e96 100644 --- a/src/DMS.cpp +++ b/src/DMS.cpp @@ -18,10 +18,6 @@ #include "DMS.h" -#ifdef ARDUINO - #include -#endif - //---------------------------------------------------------------- // Note that no division is used, and shifts are on byte boundaries. Fast! @@ -68,7 +64,6 @@ void DMS_t::From( int32_t deg_1E7 ) } // From //---------------------------------------------------------------- -#ifdef ARDUINO Print & operator << ( Print & outs, const DMS_t & dms ) { @@ -123,4 +118,3 @@ void DMS_t::printDDDMMmmmm( Print & outs ) const outs.print( '0' ); outs.print( mmmm ); } -#endif diff --git a/src/DMS.h b/src/DMS.h index 0a23a13..b1cee52 100644 --- a/src/DMS.h +++ b/src/DMS.h @@ -20,10 +20,10 @@ // #include "NeoGPS_cfg.h" +#include "Platform.h" #include -#ifdef ARDUINO - class Print; -#endif + +class Print; enum Hemisphere_t { NORTH_H = 0, SOUTH_H = 1, EAST_H = 0, WEST_H = 1 }; @@ -53,8 +53,6 @@ class DMS_t } NEOGPS_PACKED; -#ifdef ARDUINO - extern Print & operator << ( Print & outs, const DMS_t & ); -#endif +extern Print & operator << ( Print & outs, const DMS_t & ); #endif diff --git a/src/Location.h b/src/Location.h index 747b5fa..4ef3171 100644 --- a/src/Location.h +++ b/src/Location.h @@ -1,11 +1,7 @@ #ifndef NEOGPS_LOCATION_H #define NEOGPS_LOCATION_H -#ifdef ARDUINO - #include -#else - #include "CosaCompat.h" -#endif +#include "Platform.h" #include "NeoGPS_cfg.h" diff --git a/src/Platform.h b/src/Platform.h index 425a768..9631fe3 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -26,9 +26,8 @@ #define str_P char * #include - constexpr double pi() { return std::atan(1)*4; } - #define PI pi() - #define TWO_PI pi() * 2.0 + const double PI = 3.14159265358979323846; + #define TWO_PI PI * 2.0 #endif diff --git a/src/Streamers.h b/src/Streamers.h index a356302..f0a2e68 100644 --- a/src/Streamers.h +++ b/src/Streamers.h @@ -1,7 +1,7 @@ #ifndef STREAMERS_H #define STREAMERS_H -#include +#include "Platform.h" extern Print & operator <<( Print & outs, const bool b ); extern Print & operator <<( Print & outs, const char c ); @@ -30,4 +30,4 @@ class NMEAGPS; extern void trace_header( Print & outs ); extern void trace_all( Print & outs, const NMEAGPS &gps, const gps_fix &fix ); -#endif \ No newline at end of file +#endif diff --git a/src/platforms/Print.h b/src/platforms/Print.h index 1331b4f..1b2da9a 100644 --- a/src/platforms/Print.h +++ b/src/platforms/Print.h @@ -3,8 +3,10 @@ #include class Print { public: - void print(uint8_t); - void print(uint16_t); - void print(uint32_t); - void write(char); + void print(char) const; + void print(uint8_t) const; + void print(uint16_t) const; + void print(uint32_t) const; + void print(const char *) const; + void write(char) const; }; From 491cf1d297e5496a8d34ce673dc45287cb4ec6b4 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Sat, 19 Aug 2017 13:56:32 +0200 Subject: [PATCH 06/38] feat: introduce templates for arduino classes --- src/NMEAGPS.cpp | 159 -------------------------------------- src/NMEAGPS.h | 168 ++++++++++++++++++++++++++++++++++++++++- src/Platform.h | 12 ++- src/platforms/Stream.h | 4 +- 4 files changed, 177 insertions(+), 166 deletions(-) diff --git a/src/NMEAGPS.cpp b/src/NMEAGPS.cpp index 606ec58..0afc9ca 100644 --- a/src/NMEAGPS.cpp +++ b/src/NMEAGPS.cpp @@ -30,13 +30,6 @@ #endif -#ifndef CR - #define CR ((char)13) -#endif -#ifndef LF - #define LF ((char)10) -#endif - //---------------------------------------------------------------- // Parse a single character as HEX and returns byte value. @@ -49,15 +42,6 @@ inline static uint8_t parseHEX(char a) return a - '0'; } -//---------------------------------------------------------------- -// Format lower nybble of value as HEX and returns character. - -static char formatHex( uint8_t val ) -{ - val &= 0x0F; - return (val >= 10) ? ((val - 10) + 'A') : (val + '0'); -} - //---------------------------------------------------------------- inline uint8_t to_binary(uint8_t value) @@ -1587,146 +1571,3 @@ const gps_fix NMEAGPS::read() } // read //---------------------------------------------------------------- - -void NMEAGPS::poll( Stream *device, nmea_msg_t msg ) -{ - // Only the ublox documentation references talker ID "EI". - // Other manufacturer's devices use "II" and "GP" talker IDs for the GPQ sentence. - // However, "GP" is reserved for the GPS device, so it seems inconsistent - // to use that talker ID when requesting something from the GPS device. - - #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gga[] __PROGMEM = "EIGPQ,GGA"; - #endif - #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gll[] __PROGMEM = "EIGPQ,GLL"; - #endif - #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gsa[] __PROGMEM = "EIGPQ,GSA"; - #endif - #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gst[] __PROGMEM = "EIGPQ,GST"; - #endif - #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gsv[] __PROGMEM = "EIGPQ,GSV"; - #endif - #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char rmc[] __PROGMEM = "EIGPQ,RMC"; - #endif - #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char vtg[] __PROGMEM = "EIGPQ,VTG"; - #endif - #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char zda[] __PROGMEM = "EIGPQ,ZDA"; - #endif - - static const char * const poll_msgs[] __PROGMEM = - { - #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) - gga, - #endif - #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) - gll, - #endif - #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) - gsa, - #endif - #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) - gst, - #endif - #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) - gsv, - #endif - #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) - rmc, - #endif - #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) - vtg, - #endif - #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) - zda - #endif - }; - - if ((NMEA_FIRST_MSG <= msg) && (msg <= NMEA_LAST_MSG)) { - #ifdef __AVR__ - const __FlashStringHelper * pollCmd = - (const __FlashStringHelper *) pgm_read_word(&poll_msgs[msg-NMEA_FIRST_MSG]); - #else - const __FlashStringHelper * pollCmd = - (const __FlashStringHelper *) poll_msgs[msg-NMEA_FIRST_MSG]; - #endif - send_P( device, pollCmd ); - } - -} // poll - -//---------------------------------------------------------------- - -static void send_trailer( Stream *device, uint8_t crc ) -{ - device->print('*'); - - char hexDigit = formatHex( crc>>4 ); - device->print( hexDigit ); - - hexDigit = formatHex( crc ); - device->print( hexDigit ); - - device->print( CR ); - device->print( LF ); - -} // send_trailer - -//---------------------------------------------------------------- - -void NMEAGPS::send( Stream *device, const char *msg ) -{ - if (msg && *msg) { - if (*msg == '$') - msg++; - device->print('$'); - uint8_t sent_trailer = 0; - uint8_t crc = 0; - while (*msg) { - if ((*msg == '*') || (sent_trailer > 0)) - sent_trailer++; - else - crc ^= *msg; - device->print( *msg++ ); - } - - if (!sent_trailer) - send_trailer( device, crc ); - } - -} // send - -//---------------------------------------------------------------- - -void NMEAGPS::send_P( Stream *device, const __FlashStringHelper *msg ) -{ - if (msg) { - const char *ptr = (const char *)msg; - char chr = pgm_read_byte(ptr++); - - device->print('$'); - if (chr == '$') - chr = pgm_read_byte(ptr++); - uint8_t sent_trailer = 0; - uint8_t crc = 0; - while (chr) { - if ((chr == '*') || (sent_trailer > 0)) - sent_trailer++; - else - crc ^= chr; - device->print( chr ); - - chr = pgm_read_byte(ptr++); - } - - if (!sent_trailer) - send_trailer( device, crc ); - } - -} // send_P diff --git a/src/NMEAGPS.h b/src/NMEAGPS.h index 66e71d1..65e2339 100644 --- a/src/NMEAGPS.h +++ b/src/NMEAGPS.h @@ -102,6 +102,7 @@ class NMEAGPS // are available to be "read" from the fix buffer. The GPS port // object is passed in so a char can be read if port.available(). + template uint8_t available( Stream & port ) { if (processing_style == PS_POLLING) @@ -228,13 +229,17 @@ class NMEAGPS //....................................................................... // Request the specified NMEA sentence. Not all devices will respond. + template static void poll( Stream *device, nmea_msg_t msg ); //....................................................................... // Send a message to the GPS device. // The '$' is optional, and the '*' and CS will be added automatically. + template static void send( Stream *device, const char *msg ); + + template static void send_P( Stream *device, const __FlashStringHelper *msg ); //....................................................................... @@ -289,6 +294,7 @@ class NMEAGPS // uint32_t elapsedUS = (currentCount - captureCount) * countUS; // gps.UTCsecondStart( micros() - elapsedUS ); // } + #endif //....................................................................... @@ -337,13 +343,13 @@ class NMEAGPS //....................................................................... // Control access to this object. This preserves atomicity when // the processing style is interrupt-driven. - + void lock() const { if (processing_style == PS_INTERRUPT) noInterrupts(); } - + void unlock() const { if (processing_style == PS_INTERRUPT) @@ -665,4 +671,162 @@ class NMEAGPS } NEOGPS_PACKED; + +template +void NMEAGPS::poll( Stream *device, nmea_msg_t msg ) +{ + // Only the ublox documentation references talker ID "EI". + // Other manufacturer's devices use "II" and "GP" talker IDs for the GPQ sentence. + // However, "GP" is reserved for the GPS device, so it seems inconsistent + // to use that talker ID when requesting something from the GPS device. + + #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gga[] __PROGMEM = "EIGPQ,GGA"; + #endif + #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gll[] __PROGMEM = "EIGPQ,GLL"; + #endif + #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gsa[] __PROGMEM = "EIGPQ,GSA"; + #endif + #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gst[] __PROGMEM = "EIGPQ,GST"; + #endif + #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gsv[] __PROGMEM = "EIGPQ,GSV"; + #endif + #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char rmc[] __PROGMEM = "EIGPQ,RMC"; + #endif + #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char vtg[] __PROGMEM = "EIGPQ,VTG"; + #endif + #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char zda[] __PROGMEM = "EIGPQ,ZDA"; + #endif + + static const char * const poll_msgs[] __PROGMEM = + { + #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) + gga, + #endif + #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) + gll, + #endif + #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) + gsa, + #endif + #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) + gst, + #endif + #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) + gsv, + #endif + #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) + rmc, + #endif + #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) + vtg, + #endif + #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) + zda + #endif + }; + + if ((NMEA_FIRST_MSG <= msg) && (msg <= NMEA_LAST_MSG)) { + #ifdef __AVR__ + const __FlashStringHelper * pollCmd = + (const __FlashStringHelper *) pgm_read_word(&poll_msgs[msg-NMEA_FIRST_MSG]); + #else + const __FlashStringHelper * pollCmd = + (const __FlashStringHelper *) poll_msgs[msg-NMEA_FIRST_MSG]; + #endif + send_P( device, pollCmd ); + } + +} // poll + +//---------------------------------------------------------------- +// Format lower nybble of value as HEX and returns character. + +static char formatHex( uint8_t val ) +{ + val &= 0x0F; + return (val >= 10) ? ((val - 10) + 'A') : (val + '0'); +} + +//---------------------------------------------------------------- + +template +static void send_trailer( Stream *device, uint8_t crc ) +{ + + device->print('*'); + + char hexDigit = formatHex( crc>>4 ); + device->print( hexDigit ); + + hexDigit = formatHex( crc ); + device->print( hexDigit ); + + device->print( CR ); + device->print( LF ); + +} // send_trailer + +//---------------------------------------------------------------- + +template +void NMEAGPS::send( Stream *device, const char *msg ) +{ + if (msg && *msg) { + if (*msg == '$') + msg++; + device->print('$'); + uint8_t sent_trailer = 0; + uint8_t crc = 0; + while (*msg) { + if ((*msg == '*') || (sent_trailer > 0)) + sent_trailer++; + else + crc ^= *msg; + device->print( *msg++ ); + } + + if (!sent_trailer) + send_trailer( device, crc ); + } + +} // send + +//---------------------------------------------------------------- + +template +void NMEAGPS::send_P( Stream *device, const __FlashStringHelper *msg ) +{ + if (msg) { + const char *ptr = (const char *)msg; + char chr = pgm_read_byte(ptr++); + + device->print('$'); + if (chr == '$') + chr = pgm_read_byte(ptr++); + uint8_t sent_trailer = 0; + uint8_t crc = 0; + while (chr) { + if ((chr == '*') || (sent_trailer > 0)) + sent_trailer++; + else + crc ^= chr; + device->print( chr ); + + chr = pgm_read_byte(ptr++); + } + + if (!sent_trailer) + send_trailer( device, crc ); + } + +} // send_P + #endif diff --git a/src/Platform.h b/src/Platform.h index 9631fe3..510e320 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -13,11 +13,10 @@ #include #endif #else - #include "platforms/Stream.h" - #include "platforms/Print.h" #include "platforms/System.h" #include + #define __PROGMEM #define PROGMEM #define pgm_read_byte(x) (*(x)) @@ -27,7 +26,14 @@ #include - const double PI = 3.14159265358979323846; + #define PI 3.14159265358979323846 #define TWO_PI PI * 2.0 #endif + +#ifndef CR + #define CR ((char)13) +#endif +#ifndef LF + #define LF ((char)10) +#endif diff --git a/src/platforms/Stream.h b/src/platforms/Stream.h index c5d4231..79484db 100644 --- a/src/platforms/Stream.h +++ b/src/platforms/Stream.h @@ -6,6 +6,6 @@ class Stream { public: bool available(); - uint8_t read(); - void print(uint8_t); + char read(); + void print(char); }; From 44153e68e94bb251359b01c06aaf6ae4d5361c2c Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Sat, 19 Aug 2017 17:38:34 +0200 Subject: [PATCH 07/38] feat: continue converting to template functions --- src/DMS.cpp | 56 ------ src/DMS.h | 60 +++++- src/NeoTime.cpp | 23 --- src/NeoTime.h | 25 ++- src/Streamers.cpp | 404 ---------------------------------------- src/Streamers.h | 421 ++++++++++++++++++++++++++++++++++++++++-- src/platforms/Print.h | 2 + 7 files changed, 492 insertions(+), 499 deletions(-) delete mode 100644 src/Streamers.cpp diff --git a/src/DMS.cpp b/src/DMS.cpp index 82f0e96..eadc898 100644 --- a/src/DMS.cpp +++ b/src/DMS.cpp @@ -62,59 +62,3 @@ void DMS_t::From( int32_t deg_1E7 ) } } // From - -//---------------------------------------------------------------- - -Print & operator << ( Print & outs, const DMS_t & dms ) -{ - if (dms.degrees < 10) - outs.write( '0' ); - outs.print( dms.degrees ); - outs.write( ' ' ); - if (dms.minutes < 10) - outs.write( '0' ); - outs.print( dms.minutes ); - outs.print( F("\' ") ); - if (dms.seconds_whole < 10) - outs.write( '0' ); - outs.print( dms.seconds_whole ); - outs.write( '.' ); - if (dms.seconds_frac < 100) - outs.write( '0' ); - if (dms.seconds_frac < 10) - outs.write( '0' ); - outs.print( dms.seconds_frac ); - outs.print( F("\" ") ); - - return outs; - -} // operator << - -//---------------------------------------------------------------- - -void DMS_t::printDDDMMmmmm( Print & outs ) const -{ - outs.print( degrees ); - - if (minutes < 10) - outs.print( '0' ); - outs.print( minutes ); - outs.print( '.' ); - - // Calculate the fractional minutes from the seconds, - // *without* using floating-point numbers. - - uint16_t mmmm = seconds_whole * 166; // same as 10000/60, less .66666... - mmmm += (seconds_whole * 2 + seconds_frac/2 ) / 3; // ... plus the remaining .66666 - // ... plus the seconds_frac, scaled by 10000/(60*1000) = 1/6, which - // is implemented above as 1/2 * 1/3 - - // print leading zeroes, if necessary - if (mmmm < 1000) - outs.print( '0' ); - if (mmmm < 100) - outs.print( '0' ); - if (mmmm < 10) - outs.print( '0' ); - outs.print( mmmm ); -} diff --git a/src/DMS.h b/src/DMS.h index b1cee52..e458b11 100644 --- a/src/DMS.h +++ b/src/DMS.h @@ -49,10 +49,68 @@ class DMS_t void From( int32_t deg_1E7 ); // Print DMS as the funky NMEA DDDMM.mmmm format + template void printDDDMMmmmm( Print & outs ) const; } NEOGPS_PACKED; -extern Print & operator << ( Print & outs, const DMS_t & ); +//---------------------------------------------------------------- + +template +Print & operator << ( Print & outs, const DMS_t & dms ) +{ + if (dms.degrees < 10) + outs.write( '0' ); + outs.print( dms.degrees ); + outs.write( ' ' ); + if (dms.minutes < 10) + outs.write( '0' ); + outs.print( dms.minutes ); + outs.print( F("\' ") ); + if (dms.seconds_whole < 10) + outs.write( '0' ); + outs.print( dms.seconds_whole ); + outs.write( '.' ); + if (dms.seconds_frac < 100) + outs.write( '0' ); + if (dms.seconds_frac < 10) + outs.write( '0' ); + outs.print( dms.seconds_frac ); + outs.print( F("\" ") ); + + return outs; + +} // operator << + +//---------------------------------------------------------------- + +template +void DMS_t::printDDDMMmmmm( Print & outs ) const +{ + outs.print( degrees ); + + if (minutes < 10) + outs.print( '0' ); + outs.print( minutes ); + outs.print( '.' ); + + // Calculate the fractional minutes from the seconds, + // *without* using floating-point numbers. + + uint16_t mmmm = seconds_whole * 166; // same as 10000/60, less .66666... + mmmm += (seconds_whole * 2 + seconds_frac/2 ) / 3; // ... plus the remaining .66666 + // ... plus the seconds_frac, scaled by 10000/(60*1000) = 1/6, which + // is implemented above as 1/2 * 1/3 + + // print leading zeroes, if necessary + if (mmmm < 1000) + outs.print( '0' ); + if (mmmm < 100) + outs.print( '0' ); + if (mmmm < 10) + outs.print( '0' ); + outs.print( mmmm ); +} + #endif diff --git a/src/NeoTime.cpp b/src/NeoTime.cpp index b84226f..d842bf9 100644 --- a/src/NeoTime.cpp +++ b/src/NeoTime.cpp @@ -23,29 +23,6 @@ // For strtoul declaration #include - -Print & operator<<( Print& outs, const NeoGPS::time_t& t ) -{ - outs.print( t.full_year( t.year ) ); - outs.write( '-' ); - if (t.month < 10) outs.write( '0' ); - outs.print( t.month ); - outs.write( '-' ); - if (t.date < 10) outs.write( '0' ); - outs.print( t.date ); - outs.write( ' ' ); - if (t.hours < 10) outs.write( '0' ); - outs.print( t.hours ); - outs.write( ':' ); - if (t.minutes < 10) outs.write( '0' ); - outs.print( t.minutes ); - outs.write( ':' ); - if (t.seconds < 10) outs.write( '0' ); - outs.print( t.seconds ); - - return outs; -} - using NeoGPS::time_t; bool time_t::parse(str_P s) diff --git a/src/NeoTime.h b/src/NeoTime.h index b0fd35f..127910b 100644 --- a/src/NeoTime.h +++ b/src/NeoTime.h @@ -297,14 +297,33 @@ struct time_t { }; // namespace NeoGPS -class Print; - /** * Print the date/time to the given stream with the format "YYYY-MM-DD HH:MM:SS". * @param[in] outs output stream. * @param[in] t time structure. * @return iostream. */ -Print & operator <<( Print & outs, const NeoGPS::time_t &t ); +template +Print & operator <<( Print & outs, const NeoGPS::time_t &t ) +{ + outs.print( t.full_year( t.year ) ); + outs.write( '-' ); + if (t.month < 10) outs.write( '0' ); + outs.print( t.month ); + outs.write( '-' ); + if (t.date < 10) outs.write( '0' ); + outs.print( t.date ); + outs.write( ' ' ); + if (t.hours < 10) outs.write( '0' ); + outs.print( t.hours ); + outs.write( ':' ); + if (t.minutes < 10) outs.write( '0' ); + outs.print( t.minutes ); + outs.write( ':' ); + if (t.seconds < 10) outs.write( '0' ); + outs.print( t.seconds ); + + return outs; +} #endif diff --git a/src/Streamers.cpp b/src/Streamers.cpp deleted file mode 100644 index 1e3a112..0000000 --- a/src/Streamers.cpp +++ /dev/null @@ -1,404 +0,0 @@ -#include "Streamers.h" -#include "NMEAGPS.h" - -//#define USE_FLOAT - -Print& operator <<( Print &outs, const bool b ) - { outs.print( b ? 't' : 'f' ); return outs; } - -Print& operator <<( Print &outs, const char c ) { outs.print(c); return outs; } - -Print& operator <<( Print &outs, const uint16_t v ) { outs.print(v); return outs; } - -Print& operator <<( Print &outs, const uint32_t v ) { outs.print(v); return outs; } - -Print& operator <<( Print &outs, const int32_t v ) { outs.print(v); return outs; } - -Print& operator <<( Print &outs, const uint8_t v ) { outs.print(v); return outs; } - -Print& operator <<( Print &outs, const __FlashStringHelper *s ) -{ outs.print(s); return outs; } - -//------------------------------------------ - -const char gps_fix_header[] __PROGMEM = - "Status," - - #if defined(GPS_FIX_DATE) | defined(GPS_FIX_TIME) - - "UTC " - - #if defined(GPS_FIX_DATE) - "Date" - #endif - #if defined(GPS_FIX_DATE) & defined(GPS_FIX_TIME) - "/" - #endif - #if defined(GPS_FIX_TIME) - "Time" - #endif - - #else - "s" - #endif - - "," - - #ifdef GPS_FIX_LOCATION - "Lat,Lon," - #endif - - #ifdef GPS_FIX_LOCATION_DMS - "DMS," - #endif - - #if defined(GPS_FIX_HEADING) - "Hdg," - #endif - - #if defined(GPS_FIX_SPEED) - "Spd," - #endif - - #if defined(GPS_FIX_ALTITUDE) - "Alt," - #endif - - #if defined(GPS_FIX_HDOP) - "HDOP," - #endif - - #if defined(GPS_FIX_VDOP) - "VDOP," - #endif - - #if defined(GPS_FIX_PDOP) - "PDOP," - #endif - - #if defined(GPS_FIX_LAT_ERR) - "Lat err," - #endif - - #if defined(GPS_FIX_LON_ERR) - "Lon err," - #endif - - #if defined(GPS_FIX_ALT_ERR) - "Alt err," - #endif - - #if defined(GPS_FIX_GEOID_HEIGHT) - "Geoid Ht," - #endif - - #if defined(GPS_FIX_SATELLITES) - "Sats," - #endif - - ; - -//............... - -#ifdef GPS_FIX_LOCATION_DMS - - static void printDMS( Print & outs, const DMS_t & dms ) - { - if (dms.degrees < 10) - outs.write( '0' ); - outs.print( dms.degrees ); - outs.write( ' ' ); - - if (dms.minutes < 10) - outs.write( '0' ); - outs.print( dms.minutes ); - outs.print( F("\' ") ); - - if (dms.seconds_whole < 10) - outs.write( '0' ); - outs.print( dms.seconds_whole ); - outs.write( '.' ); - - if (dms.seconds_frac < 100) - outs.write( '0' ); - if (dms.seconds_frac < 10) - outs.write( '0' ); - outs.print( dms.seconds_frac ); - outs.print( F("\" ") ); - - } // printDMS - -#endif -//............... - -Print & operator <<( Print &outs, const gps_fix &fix ) -{ - if (fix.valid.status) - outs << (uint8_t) fix.status; - outs << ','; - - #if defined(GPS_FIX_DATE) | defined(GPS_FIX_TIME) - bool someTime = false; - - #if defined(GPS_FIX_DATE) - someTime |= fix.valid.date; - #endif - - #if defined(GPS_FIX_TIME) - someTime |= fix.valid.time; - #endif - - if (someTime) { - outs << fix.dateTime << '.'; - uint16_t ms = fix.dateTime_ms(); - if (ms < 100) - outs << '0'; - if (ms < 10) - outs << '0'; - outs << ms; - } - outs << ','; - - #else - - // Date/Time not enabled, just output the interval number - static uint32_t sequence = 0L; - outs << sequence++ << ','; - - #endif - - #ifdef USE_FLOAT - #ifdef GPS_FIX_LOCATION - if (fix.valid.location) { - outs.print( fix.latitude(), 6 ); - outs << ','; - outs.print( fix.longitude(), 6 ); - } else - outs << ','; - outs << ','; - #endif - #ifdef GPS_FIX_LOCATION_DMS - if (fix.valid.location) { - printDMS( outs, fix.latitudeDMS ); - outs.print( fix.latitudeDMS.NS() ); - outs.write( ' ' ); - if (fix.longitudeDMS.degrees < 100) - outs.write( '0' ); - printDMS( outs, fix.longitudeDMS ); - outs.print( fix.longitudeDMS.EW() ); - } - outs << ','; - #endif - #ifdef GPS_FIX_HEADING - if (fix.valid.heading) - outs.print( fix.heading(), 2 ); - outs << ','; - #endif - #ifdef GPS_FIX_SPEED - if (fix.valid.speed) - outs.print( fix.speed(), 3 ); // knots - outs << ','; - #endif - #ifdef GPS_FIX_ALTITUDE - if (fix.valid.altitude) - outs.print( fix.altitude(), 2 ); - outs << ','; - #endif - - #ifdef GPS_FIX_HDOP - if (fix.valid.hdop) - outs.print( (fix.hdop * 0.001), 3 ); - outs << ','; - #endif - #ifdef GPS_FIX_VDOP - if (fix.valid.vdop) - outs.print( (fix.vdop * 0.001), 3 ); - outs << ','; - #endif - #ifdef GPS_FIX_PDOP - if (fix.valid.pdop) - outs.print( (fix.pdop * 0.001), 3 ); - outs << ','; - #endif - - #ifdef GPS_FIX_LAT_ERR - if (fix.valid.lat_err) - outs.print( fix.lat_err(), 2 ); - outs << ','; - #endif - #ifdef GPS_FIX_LON_ERR - if (fix.valid.lon_err) - outs.print( fix.lon_err(), 2 ); - outs << ','; - #endif - #ifdef GPS_FIX_ALT_ERR - if (fix.valid.alt_err) - outs.print( fix.alt_err(), 2 ); - outs << ','; - #endif - - #ifdef GPS_FIX_GEOID_HEIGHT - if (fix.valid.geoidHeight) - outs.print( fix.geoidHeight(), 2 ); - outs << ','; - #endif - - #else - - // not USE_FLOAT ---------------------- - - #ifdef GPS_FIX_LOCATION - if (fix.valid.location) - outs << fix.latitudeL() << ',' << fix.longitudeL(); - else - outs << ','; - outs << ','; - #endif - #ifdef GPS_FIX_LOCATION_DMS - if (fix.valid.location) { - printDMS( outs, fix.latitudeDMS ); - outs.print( fix.latitudeDMS.NS() ); - outs.write( ' ' ); - if (fix.longitudeDMS.degrees < 100) - outs.write( '0' ); - printDMS( outs, fix.longitudeDMS ); - outs.print( fix.longitudeDMS.EW() ); - } - outs << ','; - #endif - #ifdef GPS_FIX_HEADING - if (fix.valid.heading) - outs << fix.heading_cd(); - outs << ','; - #endif - #ifdef GPS_FIX_SPEED - if (fix.valid.speed) - outs << fix.speed_mkn(); - outs << ','; - #endif - #ifdef GPS_FIX_ALTITUDE - if (fix.valid.altitude) - outs << fix.altitude_cm(); - outs << ','; - #endif - - #ifdef GPS_FIX_HDOP - if (fix.valid.hdop) - outs << fix.hdop; - outs << ','; - #endif - #ifdef GPS_FIX_VDOP - if (fix.valid.vdop) - outs << fix.vdop; - outs << ','; - #endif - #ifdef GPS_FIX_PDOP - if (fix.valid.pdop) - outs << fix.pdop; - outs << ','; - #endif - - #ifdef GPS_FIX_LAT_ERR - if (fix.valid.lat_err) - outs << fix.lat_err_cm; - outs << ','; - #endif - #ifdef GPS_FIX_LON_ERR - if (fix.valid.lon_err) - outs << fix.lon_err_cm; - outs << ','; - #endif - #ifdef GPS_FIX_ALT_ERR - if (fix.valid.alt_err) - outs << fix.alt_err_cm; - outs << ','; - #endif - - #ifdef GPS_FIX_GEOID_HEIGHT - if (fix.valid.geoidHeight) - outs << fix.geoidHeight_cm(); - outs << ','; - #endif - - #endif - - #ifdef GPS_FIX_SATELLITES - if (fix.valid.satellites) - outs << fix.satellites; - outs << ','; - #endif - - return outs; -} - -//----------------------------- - -static const char NMEAGPS_header[] __PROGMEM = - #if defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL) | defined(NMEAGPS_TIMESTAMP_FROM_PPS) - "micros()," - #endif - - #if defined(NMEAGPS_PARSE_SATELLITES) - "[sat" - #if defined(NMEAGPS_PARSE_SATELLITE_INFO) - " elev/az @ SNR" - #endif - "]," - #endif - - #ifdef NMEAGPS_STATS - "Rx ok,Rx err,Rx chars," - #endif - - ""; - -void trace_header( Print & outs ) -{ - outs.print( (const __FlashStringHelper *) &gps_fix_header[0] ); - outs.print( (const __FlashStringHelper *) &NMEAGPS_header[0] ); - - outs << '\n'; -} - -//-------------------------- - -void trace_all( Print & outs, const NMEAGPS &gps, const gps_fix &fix ) -{ - outs << fix; - - #if defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL) | defined(NMEAGPS_TIMESTAMP_FROM_PPS) - outs << gps.UTCsecondStart(); - outs << ','; - #endif - - #if defined(NMEAGPS_PARSE_SATELLITES) - outs << '['; - - for (uint8_t i=0; i < gps.sat_count; i++) { - outs << gps.satellites[i].id; - - #if defined(NMEAGPS_PARSE_SATELLITE_INFO) - outs << ' ' << - gps.satellites[i].elevation << '/' << gps.satellites[i].azimuth; - outs << '@'; - if (gps.satellites[i].tracked) - outs << gps.satellites[i].snr; - else - outs << '-'; - #endif - - outs << ','; - } - - outs << F("],"); - #endif - - #ifdef NMEAGPS_STATS - outs << gps.statistics.ok << ',' - << gps.statistics.errors << ',' - << gps.statistics.chars << ','; - #endif - - outs << '\n'; - -} // trace_all diff --git a/src/Streamers.h b/src/Streamers.h index f0a2e68..870d0e3 100644 --- a/src/Streamers.h +++ b/src/Streamers.h @@ -3,15 +3,32 @@ #include "Platform.h" -extern Print & operator <<( Print & outs, const bool b ); -extern Print & operator <<( Print & outs, const char c ); -extern Print & operator <<( Print & outs, const uint16_t v ); -extern Print & operator <<( Print & outs, const uint32_t v ); -extern Print & operator <<( Print & outs, const int32_t v ); -extern Print & operator <<( Print & outs, const uint8_t v ); -extern Print & operator <<( Print & outs, const __FlashStringHelper *s ); +#include "GPSfix.h" +#include "NMEAGPS.h" + +template +Print& operator <<( Print &outs, const bool b ) + { outs.print( b ? 't' : 'f' ); return outs; } + +template +Print& operator <<( Print &outs, const char c ) { outs.print(c); return outs; } + +template +Print& operator <<( Print &outs, const uint16_t v ) { outs.print(v); return outs; } + +template +Print& operator <<( Print &outs, const uint32_t v ) { outs.print(v); return outs; } + +template +Print& operator <<( Print &outs, const int32_t v ) { outs.print(v); return outs; } + +template +Print& operator <<( Print &outs, const uint8_t v ) { outs.print(v); return outs; } + +template +Print& operator <<( Print &outs, const __FlashStringHelper *s ) +{ outs.print(s); return outs; } -class gps_fix; /** * Print valid fix data to the given stream with the format @@ -23,11 +40,391 @@ class gps_fix; * @param[in] fix gps_fix instance. * @return iostream. */ -extern Print & operator <<( Print &outs, const gps_fix &fix ); -class NMEAGPS; +template +Print & operator <<( Print &outs, const gps_fix &fix ) +{ + if (fix.valid.status) + outs << (uint8_t) fix.status; + outs << ','; + + #if defined(GPS_FIX_DATE) | defined(GPS_FIX_TIME) + bool someTime = false; + + #if defined(GPS_FIX_DATE) + someTime |= fix.valid.date; + #endif + + #if defined(GPS_FIX_TIME) + someTime |= fix.valid.time; + #endif + + if (someTime) { + outs << fix.dateTime << '.'; + uint16_t ms = fix.dateTime_ms(); + if (ms < 100) + outs << '0'; + if (ms < 10) + outs << '0'; + outs << ms; + } + outs << ','; + + #else + + // Date/Time not enabled, just output the interval number + static uint32_t sequence = 0L; + outs << sequence++ << ','; + + #endif + + #ifdef USE_FLOAT + #ifdef GPS_FIX_LOCATION + if (fix.valid.location) { + outs.print( fix.latitude(), 6 ); + outs << ','; + outs.print( fix.longitude(), 6 ); + } else + outs << ','; + outs << ','; + #endif + #ifdef GPS_FIX_LOCATION_DMS + if (fix.valid.location) { + printDMS( outs, fix.latitudeDMS ); + outs.print( fix.latitudeDMS.NS() ); + outs.write( ' ' ); + if (fix.longitudeDMS.degrees < 100) + outs.write( '0' ); + printDMS( outs, fix.longitudeDMS ); + outs.print( fix.longitudeDMS.EW() ); + } + outs << ','; + #endif + #ifdef GPS_FIX_HEADING + if (fix.valid.heading) + outs.print( fix.heading(), 2 ); + outs << ','; + #endif + #ifdef GPS_FIX_SPEED + if (fix.valid.speed) + outs.print( fix.speed(), 3 ); // knots + outs << ','; + #endif + #ifdef GPS_FIX_ALTITUDE + if (fix.valid.altitude) + outs.print( fix.altitude(), 2 ); + outs << ','; + #endif + + #ifdef GPS_FIX_HDOP + if (fix.valid.hdop) + outs.print( (fix.hdop * 0.001), 3 ); + outs << ','; + #endif + #ifdef GPS_FIX_VDOP + if (fix.valid.vdop) + outs.print( (fix.vdop * 0.001), 3 ); + outs << ','; + #endif + #ifdef GPS_FIX_PDOP + if (fix.valid.pdop) + outs.print( (fix.pdop * 0.001), 3 ); + outs << ','; + #endif + + #ifdef GPS_FIX_LAT_ERR + if (fix.valid.lat_err) + outs.print( fix.lat_err(), 2 ); + outs << ','; + #endif + #ifdef GPS_FIX_LON_ERR + if (fix.valid.lon_err) + outs.print( fix.lon_err(), 2 ); + outs << ','; + #endif + #ifdef GPS_FIX_ALT_ERR + if (fix.valid.alt_err) + outs.print( fix.alt_err(), 2 ); + outs << ','; + #endif + + #ifdef GPS_FIX_GEOID_HEIGHT + if (fix.valid.geoidHeight) + outs.print( fix.geoidHeight(), 2 ); + outs << ','; + #endif + + #else + + // not USE_FLOAT ---------------------- + + #ifdef GPS_FIX_LOCATION + if (fix.valid.location) + outs << fix.latitudeL() << ',' << fix.longitudeL(); + else + outs << ','; + outs << ','; + #endif + #ifdef GPS_FIX_LOCATION_DMS + if (fix.valid.location) { + printDMS( outs, fix.latitudeDMS ); + outs.print( fix.latitudeDMS.NS() ); + outs.write( ' ' ); + if (fix.longitudeDMS.degrees < 100) + outs.write( '0' ); + printDMS( outs, fix.longitudeDMS ); + outs.print( fix.longitudeDMS.EW() ); + } + outs << ','; + #endif + #ifdef GPS_FIX_HEADING + if (fix.valid.heading) + outs << fix.heading_cd(); + outs << ','; + #endif + #ifdef GPS_FIX_SPEED + if (fix.valid.speed) + outs << fix.speed_mkn(); + outs << ','; + #endif + #ifdef GPS_FIX_ALTITUDE + if (fix.valid.altitude) + outs << fix.altitude_cm(); + outs << ','; + #endif + + #ifdef GPS_FIX_HDOP + if (fix.valid.hdop) + outs << fix.hdop; + outs << ','; + #endif + #ifdef GPS_FIX_VDOP + if (fix.valid.vdop) + outs << fix.vdop; + outs << ','; + #endif + #ifdef GPS_FIX_PDOP + if (fix.valid.pdop) + outs << fix.pdop; + outs << ','; + #endif + + #ifdef GPS_FIX_LAT_ERR + if (fix.valid.lat_err) + outs << fix.lat_err_cm; + outs << ','; + #endif + #ifdef GPS_FIX_LON_ERR + if (fix.valid.lon_err) + outs << fix.lon_err_cm; + outs << ','; + #endif + #ifdef GPS_FIX_ALT_ERR + if (fix.valid.alt_err) + outs << fix.alt_err_cm; + outs << ','; + #endif + + #ifdef GPS_FIX_GEOID_HEIGHT + if (fix.valid.geoidHeight) + outs << fix.geoidHeight_cm(); + outs << ','; + #endif + + #endif + + #ifdef GPS_FIX_SATELLITES + if (fix.valid.satellites) + outs << fix.satellites; + outs << ','; + #endif + + return outs; +} + +const char gps_fix_header[] __PROGMEM = + "Status," + + #if defined(GPS_FIX_DATE) | defined(GPS_FIX_TIME) + + "UTC " + + #if defined(GPS_FIX_DATE) + "Date" + #endif + #if defined(GPS_FIX_DATE) & defined(GPS_FIX_TIME) + "/" + #endif + #if defined(GPS_FIX_TIME) + "Time" + #endif + + #else + "s" + #endif + + "," + + #ifdef GPS_FIX_LOCATION + "Lat,Lon," + #endif + + #ifdef GPS_FIX_LOCATION_DMS + "DMS," + #endif + + #if defined(GPS_FIX_HEADING) + "Hdg," + #endif + + #if defined(GPS_FIX_SPEED) + "Spd," + #endif + + #if defined(GPS_FIX_ALTITUDE) + "Alt," + #endif + + #if defined(GPS_FIX_HDOP) + "HDOP," + #endif + + #if defined(GPS_FIX_VDOP) + "VDOP," + #endif + + #if defined(GPS_FIX_PDOP) + "PDOP," + #endif + + #if defined(GPS_FIX_LAT_ERR) + "Lat err," + #endif + + #if defined(GPS_FIX_LON_ERR) + "Lon err," + #endif + + #if defined(GPS_FIX_ALT_ERR) + "Alt err," + #endif + + #if defined(GPS_FIX_GEOID_HEIGHT) + "Geoid Ht," + #endif + + #if defined(GPS_FIX_SATELLITES) + "Sats," + #endif + + ; + +//............... + +#ifdef GPS_FIX_LOCATION_DMS + + template + static void printDMS( Print & outs, const DMS_t & dms ) + { + if (dms.degrees < 10) + outs.write( '0' ); + outs.print( dms.degrees ); + outs.write( ' ' ); + + if (dms.minutes < 10) + outs.write( '0' ); + outs.print( dms.minutes ); + outs.print( F("\' ") ); + + if (dms.seconds_whole < 10) + outs.write( '0' ); + outs.print( dms.seconds_whole ); + outs.write( '.' ); + + if (dms.seconds_frac < 100) + outs.write( '0' ); + if (dms.seconds_frac < 10) + outs.write( '0' ); + outs.print( dms.seconds_frac ); + outs.print( F("\" ") ); + + } // printDMS + +#endif + +//............... +//----------------------------- + +static const char NMEAGPS_header[] __PROGMEM = + #if defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL) | defined(NMEAGPS_TIMESTAMP_FROM_PPS) + "micros()," + #endif + + #if defined(NMEAGPS_PARSE_SATELLITES) + "[sat" + #if defined(NMEAGPS_PARSE_SATELLITE_INFO) + " elev/az @ SNR" + #endif + "]," + #endif + + #ifdef NMEAGPS_STATS + "Rx ok,Rx err,Rx chars," + #endif + + ""; + +template +void trace_header( Print & outs ) +{ + outs.print( (const __FlashStringHelper *) &gps_fix_header[0] ); + outs.print( (const __FlashStringHelper *) &NMEAGPS_header[0] ); + + outs << '\n'; +} + +//-------------------------- + +template +void trace_all( Print & outs, const NMEAGPS &gps, const gps_fix &fix ) +{ + outs << fix; + + #if defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL) | defined(NMEAGPS_TIMESTAMP_FROM_PPS) + outs << gps.UTCsecondStart(); + outs << ','; + #endif + + #if defined(NMEAGPS_PARSE_SATELLITES) + outs << '['; + + for (uint8_t i=0; i < gps.sat_count; i++) { + outs << gps.satellites[i].id; + + #if defined(NMEAGPS_PARSE_SATELLITE_INFO) + outs << ' ' << + gps.satellites[i].elevation << '/' << gps.satellites[i].azimuth; + outs << '@'; + if (gps.satellites[i].tracked) + outs << gps.satellites[i].snr; + else + outs << '-'; + #endif + + outs << ','; + } + + outs << F("],"); + #endif + + #ifdef NMEAGPS_STATS + outs << gps.statistics.ok << ',' + << gps.statistics.errors << ',' + << gps.statistics.chars << ','; + #endif + + outs << '\n'; -extern void trace_header( Print & outs ); -extern void trace_all( Print & outs, const NMEAGPS &gps, const gps_fix &fix ); +} // trace_all #endif diff --git a/src/platforms/Print.h b/src/platforms/Print.h index 1b2da9a..1236c5e 100644 --- a/src/platforms/Print.h +++ b/src/platforms/Print.h @@ -1,6 +1,8 @@ #pragma once #include +// If there is not already an implementation for your platform, +// implement these functions. class Print { public: void print(char) const; From c71471606ca29bb4f7458072df5da05386a1ccd9 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Sun, 20 Aug 2017 14:34:36 +0200 Subject: [PATCH 08/38] feat: continue work for a linux example --- examples/linux/NMEA/NMEA.cpp | 199 +++++++++++++++++++++++++++++++++++ examples/linux/serial.cpp | 125 ++++++++++++++++++++++ 2 files changed, 324 insertions(+) create mode 100644 examples/linux/NMEA/NMEA.cpp create mode 100644 examples/linux/serial.cpp diff --git a/examples/linux/NMEA/NMEA.cpp b/examples/linux/NMEA/NMEA.cpp new file mode 100644 index 0000000..c90b3f4 --- /dev/null +++ b/examples/linux/NMEA/NMEA.cpp @@ -0,0 +1,199 @@ +#include +#include + +//====================================================================== +// Program: NMEA.ino +// +// Description: This program uses the fix-oriented methods available() and +// read() to handle complete fix structures. +// +// When the last character of the LAST_SENTENCE_IN_INTERVAL (see NMEAGPS_cfg.h) +// is decoded, a completed fix structure becomes available and is returned +// from read(). The new fix is saved the 'fix_data' structure, and can be used +// anywhere, at any time. +// +// If no messages are enabled in NMEAGPS_cfg.h, or +// no 'gps_fix' members are enabled in GPSfix_cfg.h, no information will be +// parsed, copied or printed. +// +// Prerequisites: +// 1) Your GPS device has been correctly powered. +// Be careful when connecting 3.3V devices. +// 2) Your GPS device is correctly connected to an Arduino serial port. +// See GPSport.h for the default connections. +// 3) You know the default baud rate of your GPS device. +// If 9600 does not work, use NMEAdiagnostic.ino to +// scan for the correct baud rate. +// 4) LAST_SENTENCE_IN_INTERVAL is defined to be the sentence that is +// sent *last* in each update interval (usually once per second). +// The default is NMEAGPS::NMEA_RMC (see NMEAGPS_cfg.h). Other +// programs may need to use the sentence identified by NMEAorder.ino. +// 5) NMEAGPS_RECOGNIZE_ALL is defined in NMEAGPS_cfg.h +// +// 'Serial' is for debug output to the Serial Monitor window. +// +//====================================================================== + +//------------------------------------------------------------------------- +// The GPSport.h include file tries to choose a default serial port +// for the GPS device. If you know which serial port you want to use, +// delete this section and declare it here: +// +// HardwareSerial & gps_port = Serial2; // an alias +// or +// AltSoftSerial gps_port; // depends on Arduino - pins 8 & 9 on UNO +// or +// NeoSWSerial gps_port( rxpin, txpin ); // to GPS TX, RX +// or +// Search and replace all occurrences of "gps_port" with your port's name. +// +// See Installation instructions for additional information. + +#ifdef ARDUINO + #if defined( UBRR1H ) | defined( ID_USART0 ) + // Default is to use Serial1 when available. You could also + // use NeoHWSerial, especially if you want to handle GPS characters + // in an Interrupt Service Routine. + //#include + #else + // Only one serial port is available, uncomment one of the following: + //#include + //#include + #include + //#include /* NOT RECOMMENDED */ + #endif +#endif + +#include "GPSport.h" + +//------------------------------------------------------------ +// For the NeoGPS example programs, "Streamers" is common set +// of printing and formatting routines for GPS data, in a +// Comma-Separated Values text format (aka CSV). The CSV +// data will be printed to the "debug output device". +// If you don't need these formatters, simply delete this section. + +#include "Streamers.h" + +//------------------------------------------------------------ +// When NeoHWSerial is used, none of the built-in HardwareSerial +// variables can be used: Serial, Serial1, Serial2 and Serial3 +// *cannot* be used. Instead, you must use the corresponding +// NeoSerial, NeoSerial1, NeoSerial2 or NeoSerial3. This define +// is used to substitute the appropriate Serial variable in +// all debug prints below. + +#ifndef DEBUG_PORT + #ifdef NeoHWSerial_h + #define DEBUG_PORT NeoSerial + #else + #define DEBUG_PORT Serial + #endif +#endif + +#ifndef USING_GPS_PORT + #define USING_GPS_PORT "unknown port" +#endif + +//------------------------------------------------------------ +// This object parses received characters +// into the gps.fix() data structure + +static NMEAGPS gps; + +//------------------------------------------------------------ +// Define a set of GPS fix information. It will +// hold on to the various pieces as they are received from +// an RMC sentence. It can be used anywhere in your sketch. + +static gps_fix fix_data; + +//---------------------------------------------------------------- +// This function gets called about once per second, during the GPS +// quiet time. It's the best place to do anything that might take +// a while: print a bunch of things, write to SD, send an SMS, etc. +// +// By doing the "hard" work during the quiet time, the CPU can get back to +// reading the GPS chars as they come in, so that no chars are lost. + +static void doSomeWork() +{ + // Print all the things! + + trace_all( DEBUG_PORT, gps, fix_data ); + +} // doSomeWork + +//------------------------------------ +// This is the main GPS parsing loop. + +static void GPSloop() +{ + while (gps.available( gps_port )) { + fix_data = gps.read(); + doSomeWork(); + } + +} // GPSloop + +//-------------------------- + +void setup() +{ + // Start the normal trace output + DEBUG_PORT.begin(9600); + while (!DEBUG_PORT) + ; + + DEBUG_PORT.print( F("NMEA.INO: started\n") ); + DEBUG_PORT.print( F(" fix object size = ") ); + DEBUG_PORT.println( sizeof(gps.fix()) ); + DEBUG_PORT.print( F(" gps object size = ") ); + DEBUG_PORT.println( sizeof(gps) ); + DEBUG_PORT.println( F("Looking for GPS device on " USING_GPS_PORT) ); + + #ifndef NMEAGPS_RECOGNIZE_ALL + #error You must define NMEAGPS_RECOGNIZE_ALL in NMEAGPS_cfg.h! + #endif + + #ifdef NMEAGPS_INTERRUPT_PROCESSING + #error You must *NOT* define NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h! + #endif + + #if !defined( NMEAGPS_PARSE_GGA ) & !defined( NMEAGPS_PARSE_GLL ) & \ + !defined( NMEAGPS_PARSE_GSA ) & !defined( NMEAGPS_PARSE_GSV ) & \ + !defined( NMEAGPS_PARSE_RMC ) & !defined( NMEAGPS_PARSE_VTG ) & \ + !defined( NMEAGPS_PARSE_ZDA ) & !defined( NMEAGPS_PARSE_GST ) + + DEBUG_PORT.println( F("\nWARNING: No NMEA sentences are enabled: no fix data will be displayed.") ); + + #else + if (gps.merging == NMEAGPS::NO_MERGING) { + DEBUG_PORT.print ( F("\nWARNING: displaying data from ") ); + DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); + DEBUG_PORT.print ( F(" sentences ONLY, and only if ") ); + DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); + DEBUG_PORT.println( F(" is enabled.\n" + " Other sentences may be parsed, but their data will not be displayed.") ); + } + #endif + + DEBUG_PORT.print ( F("\nGPS quiet time is assumed to begin after a ") ); + DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); + DEBUG_PORT.println( F(" sentence is received.\n" + " You should confirm this with NMEAorder.ino\n") ); + + trace_header( DEBUG_PORT ); + + DEBUG_PORT.flush(); + + // Start the UART for the GPS device + gps_port.begin( 9600 ); +} + +//-------------------------- + +void loop() +{ + GPSloop(); +} diff --git a/examples/linux/serial.cpp b/examples/linux/serial.cpp new file mode 100644 index 0000000..ddcf1e2 --- /dev/null +++ b/examples/linux/serial.cpp @@ -0,0 +1,125 @@ +/* + * This code is heavily based on + * https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c + */ + +#include "serial.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +static int set_interface_attribs(int fd, int speed) +{ + struct termios tty; + + if (tcgetattr(fd, &tty) < 0) { + printf("Error from tcgetattr: %s\n", strerror(errno)); + return -1; + } + + cfsetospeed(&tty, (speed_t)speed); + cfsetispeed(&tty, (speed_t)speed); + + tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */ + tty.c_cflag &= ~CSIZE; + tty.c_cflag |= CS8; /* 8-bit characters */ + tty.c_cflag &= ~PARENB; /* no parity bit */ + tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */ + tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */ + + /* setup for non-canonical mode */ + tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + tty.c_oflag &= ~OPOST; + + /* fetch bytes as they become available */ + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 1; + + if (tcsetattr(fd, TCSANOW, &tty) != 0) { + printf("Error from tcsetattr: %s\n", strerror(errno)); + return -1; + } + return 0; +} + +void set_mincount(int fd, int mcount) +{ + struct termios tty; + + if (tcgetattr(fd, &tty) < 0) { + printf("Error tcgetattr: %s\n", strerror(errno)); + return; + } + + tty.c_cc[VMIN] = mcount ? 1 : 0; + tty.c_cc[VTIME] = 5; /* half second timer */ + + if (tcsetattr(fd, TCSANOW, &tty) < 0) + printf("Error tcsetattr: %s\n", strerror(errno)); +} + +static int fd; + +bool data_available() +{ + fd_set rfds; + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + + FD_ZERO(rfds); + FD_SET(fd, &rfds); + + int retval = select(1, &rfds, NULL, NULL, &tv) > 0; + if (retval == -1) { + printf("Error select: %s\n", strerror(errno)); + } + return retval > 0; +} + +char read() +{ + char c; + int rdlen = read(fd, &c, 1); + if (rdlen > 0) { + printf("Read: %c\n", c); + } else if (rdlen < 0) { + printf("Error from read: %s\n", strerror(errno)); + } + return '\0'; +} + +void write(const char* out) +{ + int len = strlen(out); + /* simple output */ + int wlen = write(fd, out, len); + if (wlen != len) { + printf("Error from write: %d, %d\n", wlen, errno); + } + tcdrain(fd); /* delay for output */ +} + +void init(const char *portname) +{ + if (portname == nullptr) { + portname = "/dev/ttyUSB0"; + } + + fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); + if (fd < 0) { + printf("Error opening %s: %s\n", portname, strerror(errno)); + return -1; + } + /*baudrate 9600, 8 bits, no parity, 1 stop bit */ + set_interface_attribs(fd, B9600); + //set_mincount(fd, 0); /* set to pure timed read */ + +} From cfe09772d167fdf67785e25b47ef3ecf3d44dcd9 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Sun, 20 Aug 2017 16:37:29 +0200 Subject: [PATCH 09/38] feat: add (hopefully) working linux serial example. untested. My gps module did not get a fix :( --- examples/linux/GpsPort.cpp | 23 ++++++ examples/linux/GpsPort.h | 13 ++++ examples/linux/NMEA/NMEA.cpp | 128 ++++++++++------------------------ examples/linux/NMEA/build.txt | 1 + examples/linux/Print.cpp | 16 +++++ examples/linux/System.cpp | 4 ++ examples/linux/serial.cpp | 21 +++--- examples/linux/serial.h | 15 ++++ 8 files changed, 119 insertions(+), 102 deletions(-) create mode 100644 examples/linux/GpsPort.cpp create mode 100644 examples/linux/GpsPort.h create mode 100644 examples/linux/NMEA/build.txt create mode 100644 examples/linux/Print.cpp create mode 100644 examples/linux/System.cpp create mode 100644 examples/linux/serial.h diff --git a/examples/linux/GpsPort.cpp b/examples/linux/GpsPort.cpp new file mode 100644 index 0000000..41d7cc1 --- /dev/null +++ b/examples/linux/GpsPort.cpp @@ -0,0 +1,23 @@ +#include "GpsPort.h" + +GpsPort::GpsPort(const char* usbDev) { + _device = ::init(usbDev); +} + +bool GpsPort::available() { + return true; + //bool available = ::data_available(_device); + //std::cout << "Availabe: " << available << std::endl; + //return available; +} + +char GpsPort::read() { + return ::read(_device); +} + +void GpsPort::print(char c) { + char s[2]; + s[0] = c; + s[1] = '\0'; + ::write(_device, s); +} diff --git a/examples/linux/GpsPort.h b/examples/linux/GpsPort.h new file mode 100644 index 0000000..88596ea --- /dev/null +++ b/examples/linux/GpsPort.h @@ -0,0 +1,13 @@ +#pragma once +#include "serial.h" + +class GpsPort { +private: + serial_dev_t _device; + +public: + GpsPort(const char*); + bool available(); + char read(); + void print(char); +}; diff --git a/examples/linux/NMEA/NMEA.cpp b/examples/linux/NMEA/NMEA.cpp index c90b3f4..dfb2cae 100644 --- a/examples/linux/NMEA/NMEA.cpp +++ b/examples/linux/NMEA/NMEA.cpp @@ -1,9 +1,8 @@ -#include +#include #include +#include //====================================================================== -// Program: NMEA.ino -// // Description: This program uses the fix-oriented methods available() and // read() to handle complete fix structures. // @@ -18,54 +17,18 @@ // // Prerequisites: // 1) Your GPS device has been correctly powered. -// Be careful when connecting 3.3V devices. -// 2) Your GPS device is correctly connected to an Arduino serial port. -// See GPSport.h for the default connections. +// 2) Your GPS device is correctly connected using a serial adapter. +// By default /dev/ttyUSB0 is used. // 3) You know the default baud rate of your GPS device. -// If 9600 does not work, use NMEAdiagnostic.ino to -// scan for the correct baud rate. +// By default 9600 is assumed. If this doesn't work change it in serial.cpp // 4) LAST_SENTENCE_IN_INTERVAL is defined to be the sentence that is // sent *last* in each update interval (usually once per second). // The default is NMEAGPS::NMEA_RMC (see NMEAGPS_cfg.h). Other // programs may need to use the sentence identified by NMEAorder.ino. // 5) NMEAGPS_RECOGNIZE_ALL is defined in NMEAGPS_cfg.h // -// 'Serial' is for debug output to the Serial Monitor window. -// //====================================================================== -//------------------------------------------------------------------------- -// The GPSport.h include file tries to choose a default serial port -// for the GPS device. If you know which serial port you want to use, -// delete this section and declare it here: -// -// HardwareSerial & gps_port = Serial2; // an alias -// or -// AltSoftSerial gps_port; // depends on Arduino - pins 8 & 9 on UNO -// or -// NeoSWSerial gps_port( rxpin, txpin ); // to GPS TX, RX -// or -// Search and replace all occurrences of "gps_port" with your port's name. -// -// See Installation instructions for additional information. - -#ifdef ARDUINO - #if defined( UBRR1H ) | defined( ID_USART0 ) - // Default is to use Serial1 when available. You could also - // use NeoHWSerial, especially if you want to handle GPS characters - // in an Interrupt Service Routine. - //#include - #else - // Only one serial port is available, uncomment one of the following: - //#include - //#include - #include - //#include /* NOT RECOMMENDED */ - #endif -#endif - -#include "GPSport.h" - //------------------------------------------------------------ // For the NeoGPS example programs, "Streamers" is common set // of printing and formatting routines for GPS data, in a @@ -75,26 +38,6 @@ #include "Streamers.h" -//------------------------------------------------------------ -// When NeoHWSerial is used, none of the built-in HardwareSerial -// variables can be used: Serial, Serial1, Serial2 and Serial3 -// *cannot* be used. Instead, you must use the corresponding -// NeoSerial, NeoSerial1, NeoSerial2 or NeoSerial3. This define -// is used to substitute the appropriate Serial variable in -// all debug prints below. - -#ifndef DEBUG_PORT - #ifdef NeoHWSerial_h - #define DEBUG_PORT NeoSerial - #else - #define DEBUG_PORT Serial - #endif -#endif - -#ifndef USING_GPS_PORT - #define USING_GPS_PORT "unknown port" -#endif - //------------------------------------------------------------ // This object parses received characters // into the gps.fix() data structure @@ -116,6 +59,8 @@ static gps_fix fix_data; // By doing the "hard" work during the quiet time, the CPU can get back to // reading the GPS chars as they come in, so that no chars are lost. +static Print DEBUG_PORT; + static void doSomeWork() { // Print all the things! @@ -127,7 +72,7 @@ static void doSomeWork() //------------------------------------ // This is the main GPS parsing loop. -static void GPSloop() +static void GPSloop(GpsPort gps_port) { while (gps.available( gps_port )) { fix_data = gps.read(); @@ -138,19 +83,16 @@ static void GPSloop() //-------------------------- -void setup() +GpsPort setup(char *usbDev) { // Start the normal trace output - DEBUG_PORT.begin(9600); - while (!DEBUG_PORT) - ; - - DEBUG_PORT.print( F("NMEA.INO: started\n") ); - DEBUG_PORT.print( F(" fix object size = ") ); - DEBUG_PORT.println( sizeof(gps.fix()) ); - DEBUG_PORT.print( F(" gps object size = ") ); - DEBUG_PORT.println( sizeof(gps) ); - DEBUG_PORT.println( F("Looking for GPS device on " USING_GPS_PORT) ); + DEBUG_PORT.print( "NMEA: started\n" ); + DEBUG_PORT.print( " fix object size = " ); + DEBUG_PORT.print( (uint32_t)sizeof(gps.fix()) ); + DEBUG_PORT.print( "\n gps object size = " ); + DEBUG_PORT.print( (uint32_t)sizeof(gps) ); + DEBUG_PORT.print( "\nLooking for GPS device on " ); + DEBUG_PORT.print( usbDev ); #ifndef NMEAGPS_RECOGNIZE_ALL #error You must define NMEAGPS_RECOGNIZE_ALL in NMEAGPS_cfg.h! @@ -169,31 +111,35 @@ void setup() #else if (gps.merging == NMEAGPS::NO_MERGING) { - DEBUG_PORT.print ( F("\nWARNING: displaying data from ") ); - DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); - DEBUG_PORT.print ( F(" sentences ONLY, and only if ") ); - DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); - DEBUG_PORT.println( F(" is enabled.\n" + DEBUG_PORT.print( F("\nWARNING: displaying data from ") ); + DEBUG_PORT.print( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); + DEBUG_PORT.print( F(" sentences ONLY, and only if ") ); + DEBUG_PORT.print( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); + DEBUG_PORT.print( F(" is enabled.\n" " Other sentences may be parsed, but their data will not be displayed.") ); + DEBUG_PORT.print( "\n" ); } #endif - DEBUG_PORT.print ( F("\nGPS quiet time is assumed to begin after a ") ); - DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); - DEBUG_PORT.println( F(" sentence is received.\n" - " You should confirm this with NMEAorder.ino\n") ); + DEBUG_PORT.print( "\nGPS quiet time is assumed to begin after a "); + DEBUG_PORT.print( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); + DEBUG_PORT.print( " sentence is received.\n" + " You should confirm this with NMEAorder.ino\n" ); + DEBUG_PORT.print( "\n" ); + + GpsPort gps_port = GpsPort(usbDev); trace_header( DEBUG_PORT ); - - DEBUG_PORT.flush(); - - // Start the UART for the GPS device - gps_port.begin( 9600 ); + + return gps_port; } //-------------------------- -void loop() -{ - GPSloop(); +int main(int argc, char *argv[]) { + auto gps_port = setup(argc > 1 ? argv[1] : nullptr); + for (;;) { + GPSloop(gps_port); + } + return 0; } diff --git a/examples/linux/NMEA/build.txt b/examples/linux/NMEA/build.txt new file mode 100644 index 0000000..aebc237 --- /dev/null +++ b/examples/linux/NMEA/build.txt @@ -0,0 +1 @@ +g++ -flto -Wall ../../../src/DMS.cpp ../../../src/GPSTime.cpp ../../../src/Location.cpp ../../../src/NeoTime.cpp ../../../src/NMEAGPS.cpp ../GpsPort.cpp ../Print.cpp NMEA.cpp ../serial.cpp -I ../ -I ../../../src diff --git a/examples/linux/Print.cpp b/examples/linux/Print.cpp new file mode 100644 index 0000000..887f67e --- /dev/null +++ b/examples/linux/Print.cpp @@ -0,0 +1,16 @@ +#include + +#include + +template +static void _print(T x) { + std::cout << x; +} + +void Print::print(char c) const { _print(c); } +void Print::print(uint8_t n) const { _print(n); } +void Print::print(uint16_t n) const { _print(n); } +void Print::print(uint32_t n) const { _print(n); } +void Print::print(int n) const { _print(n); } +void Print::print(const char *s) const { _print(s); } +void Print::write(char c) const { _print(c); } diff --git a/examples/linux/System.cpp b/examples/linux/System.cpp new file mode 100644 index 0000000..0c8c874 --- /dev/null +++ b/examples/linux/System.cpp @@ -0,0 +1,4 @@ +#include + +void interrupts() {} +void noInterrupts() {} diff --git a/examples/linux/serial.cpp b/examples/linux/serial.cpp index ddcf1e2..2e423fc 100644 --- a/examples/linux/serial.cpp +++ b/examples/linux/serial.cpp @@ -49,7 +49,7 @@ static int set_interface_attribs(int fd, int speed) return 0; } -void set_mincount(int fd, int mcount) +static void set_mincount(int fd, int mcount) { struct termios tty; @@ -65,16 +65,14 @@ void set_mincount(int fd, int mcount) printf("Error tcsetattr: %s\n", strerror(errno)); } -static int fd; - -bool data_available() +bool data_available(serial_dev_t fd) { fd_set rfds; struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; - FD_ZERO(rfds); + FD_ZERO(&rfds); FD_SET(fd, &rfds); int retval = select(1, &rfds, NULL, NULL, &tv) > 0; @@ -84,19 +82,19 @@ bool data_available() return retval > 0; } -char read() +char read(serial_dev_t fd) { char c; int rdlen = read(fd, &c, 1); if (rdlen > 0) { - printf("Read: %c\n", c); + return c; } else if (rdlen < 0) { printf("Error from read: %s\n", strerror(errno)); } return '\0'; } -void write(const char* out) +void write(serial_dev_t fd, const char* out) { int len = strlen(out); /* simple output */ @@ -107,13 +105,13 @@ void write(const char* out) tcdrain(fd); /* delay for output */ } -void init(const char *portname) +serial_dev_t init(const char *portname) { if (portname == nullptr) { portname = "/dev/ttyUSB0"; } - fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); + int fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); if (fd < 0) { printf("Error opening %s: %s\n", portname, strerror(errno)); return -1; @@ -121,5 +119,6 @@ void init(const char *portname) /*baudrate 9600, 8 bits, no parity, 1 stop bit */ set_interface_attribs(fd, B9600); //set_mincount(fd, 0); /* set to pure timed read */ - + + return fd; } diff --git a/examples/linux/serial.h b/examples/linux/serial.h new file mode 100644 index 0000000..8b2423e --- /dev/null +++ b/examples/linux/serial.h @@ -0,0 +1,15 @@ +#pragma once + +typedef int serial_dev_t; + +// Open portname (if nullptr /dev/ttyUSB0). +serial_dev_t init(const char *portname); + +// Write to previously initialized port. +void write(serial_dev_t, const char* out); + +// Reads one character from previously initialized port. +char read(serial_dev_t); + +// Returns true if read would not block on initialized port. +bool data_available(serial_dev_t); From 9058e0142bba7273e413e7a04312a1ce95a6da68 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Sun, 20 Aug 2017 16:38:54 +0200 Subject: [PATCH 10/38] feat: minor tweaks to get linux version to compile --- src/NeoTime.cpp | 2 +- src/Platform.h | 5 +++-- src/platforms/Print.h | 1 + src/platforms/Stream.h | 1 - 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/NeoTime.cpp b/src/NeoTime.cpp index d842bf9..81c33b9 100644 --- a/src/NeoTime.cpp +++ b/src/NeoTime.cpp @@ -33,7 +33,7 @@ bool time_t::parse(str_P s) strcpy_P(buf, s); char* sp = &buf[0]; #else - char* sp = &s[0]; + char* sp = (char *)&s[0]; #endif uint16_t value = strtoul(sp, &sp, 10); diff --git a/src/Platform.h b/src/Platform.h index 510e320..38de3c1 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -1,5 +1,7 @@ #pragma once +#include "CosaCompat.h" + /** * This file contains platform related definitions and imports. **/ @@ -16,13 +18,12 @@ #include "platforms/System.h" #include - #define __PROGMEM + //#define __PROGMEM #define PROGMEM #define pgm_read_byte(x) (*(x)) #define __FlashStringHelper char #define F(x) (x) - #define str_P char * #include diff --git a/src/platforms/Print.h b/src/platforms/Print.h index 1236c5e..d9a2ece 100644 --- a/src/platforms/Print.h +++ b/src/platforms/Print.h @@ -9,6 +9,7 @@ class Print { void print(uint8_t) const; void print(uint16_t) const; void print(uint32_t) const; + void print(int) const; void print(const char *) const; void write(char) const; }; diff --git a/src/platforms/Stream.h b/src/platforms/Stream.h index 79484db..81c1d85 100644 --- a/src/platforms/Stream.h +++ b/src/platforms/Stream.h @@ -1,6 +1,5 @@ #pragma once -#include // If there is not already an implementation for your platform, // implement these functions. class Stream { From a8b7fbe6f24600eaa214267acb88f7aae48a5fd3 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Mon, 21 Aug 2017 19:19:18 +0200 Subject: [PATCH 11/38] feat: NeoGPS finally outputs something using dummy input. --- examples/linux/GpsPort.cpp | 5 +-- examples/linux/GpsPort.dummy.cpp | 51 +++++++++++++++++++++++++++++ examples/linux/NMEA/NMEA.cpp | 2 +- examples/linux/NMEA/build.dummy.txt | 1 + examples/linux/serial.cpp | 2 +- 5 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 examples/linux/GpsPort.dummy.cpp create mode 100644 examples/linux/NMEA/build.dummy.txt diff --git a/examples/linux/GpsPort.cpp b/examples/linux/GpsPort.cpp index 41d7cc1..f3c1ab0 100644 --- a/examples/linux/GpsPort.cpp +++ b/examples/linux/GpsPort.cpp @@ -5,10 +5,7 @@ GpsPort::GpsPort(const char* usbDev) { } bool GpsPort::available() { - return true; - //bool available = ::data_available(_device); - //std::cout << "Availabe: " << available << std::endl; - //return available; + return ::data_available(_device); } char GpsPort::read() { diff --git a/examples/linux/GpsPort.dummy.cpp b/examples/linux/GpsPort.dummy.cpp new file mode 100644 index 0000000..d70d116 --- /dev/null +++ b/examples/linux/GpsPort.dummy.cpp @@ -0,0 +1,51 @@ +#include "GpsPort.h" +#include +#include + +GpsPort::GpsPort(const char* usbDev) { + (void) usbDev; + _device = 0; +} + +bool GpsPort::available() { + if (_device == 0) { + return true; + } + _device = 1; + return false; +} + +static const char * NMEA_STRING = + "$GPRMC,162254.00,A,3723.02837,N,12159.39853,W,0.820,188.36,110706,,,A*74\r\n" + "$GPVTG,188.36,T,,M,0.820,N,1.519,K,A*3F\r\n" + "$GPGGA,162254.00,3723.02837,N,12159.39853,W,1,03,2.36,525.6,M,-25.6,M,,*65\r\n" + "$GPGSA,A,2,25,01,22,,,,,,,,,,2.56,2.36,1.00*02\r\n" + "$GPGSV,4,1,14,25,15,175,30,14,80,041,,19,38,259,14,01,52,223,18*76\r\n" + "$GPGSV,4,2,14,18,16,079,,11,19,312,,14,80,041,,21,04,135,25*7D\r\n" + "$GPGSV,4,3,14,15,27,134,18,03,25,222,,22,51,057,16,09,07,036,*79\r\n" + "$GPGSV,4,4,14,07,01,181,,15,25,135,*76\r\n" + "$GPGLL,3723.02837,N,12159.39853,W,162254.00,A,A*7C\r\n" + "$GPZDA,162254.00,11,07,2006,00,00*63\r\n"; + +char GpsPort::read() { + static int runner = 0; + static int len = strlen(NMEA_STRING); + char c = NMEA_STRING[runner]; + if (c == '$') { + sleep(1); + } + runner = (runner + 1) % len; + + char nextC = NMEA_STRING[runner]; + if (nextC == '$') { + // Signal available to say false; + _device = 1; + } + + return c; +} + +void GpsPort::print(char c) { + (void) c; + return; +} diff --git a/examples/linux/NMEA/NMEA.cpp b/examples/linux/NMEA/NMEA.cpp index dfb2cae..c0b1373 100644 --- a/examples/linux/NMEA/NMEA.cpp +++ b/examples/linux/NMEA/NMEA.cpp @@ -92,7 +92,7 @@ GpsPort setup(char *usbDev) DEBUG_PORT.print( "\n gps object size = " ); DEBUG_PORT.print( (uint32_t)sizeof(gps) ); DEBUG_PORT.print( "\nLooking for GPS device on " ); - DEBUG_PORT.print( usbDev ); + DEBUG_PORT.print( usbDev == nullptr ? "default" : usbDev ); #ifndef NMEAGPS_RECOGNIZE_ALL #error You must define NMEAGPS_RECOGNIZE_ALL in NMEAGPS_cfg.h! diff --git a/examples/linux/NMEA/build.dummy.txt b/examples/linux/NMEA/build.dummy.txt new file mode 100644 index 0000000..5d1560e --- /dev/null +++ b/examples/linux/NMEA/build.dummy.txt @@ -0,0 +1 @@ +g++ -flto -g -Wall ../../../src/DMS.cpp ../../../src/GPSTime.cpp ../../../src/Location.cpp ../../../src/NeoTime.cpp ../../../src/NMEAGPS.cpp ../GpsPort.dummy.cpp ../Print.cpp NMEA.cpp ../serial.cpp -I ../ -I ../../../src diff --git a/examples/linux/serial.cpp b/examples/linux/serial.cpp index 2e423fc..773cf1b 100644 --- a/examples/linux/serial.cpp +++ b/examples/linux/serial.cpp @@ -75,7 +75,7 @@ bool data_available(serial_dev_t fd) FD_ZERO(&rfds); FD_SET(fd, &rfds); - int retval = select(1, &rfds, NULL, NULL, &tv) > 0; + int retval = select(1, &rfds, NULL, NULL, &tv); if (retval == -1) { printf("Error select: %s\n", strerror(errno)); } From e9f328f42e353ac6ea5803aa1196853c3fe3df80 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Fri, 25 Aug 2017 09:03:18 +0200 Subject: [PATCH 12/38] feat: add some files to gitignore add non working CMakeLists.txt --- .gitignore | 5 +++ CMakeLists.txt | 116 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 CMakeLists.txt diff --git a/.gitignore b/.gitignore index 96374c4..513291b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ +.kdev4 +/*.kdev4 +a.out +/build + # Windows image file caches Thumbs.db ehthumbs.db diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..458b7a6 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,116 @@ +# This file has been adapted from https://github.com/jacketizer/libnmea/blob/master/CMakeLists.txt +# (MIT License THANKS) + +cmake_minimum_required (VERSION 2.8) +project(NeoGPS CXX) + +option(NEO_GPS_BUILD_STATIC_LIB "Build static NeoGPS" ON) +option(NEO_GPS_BUILD_SHARED_LIB "Build shared NeoGPS" ON) +option(NEO_GPS_BUILD_EXAMPLES "Build examples" ON) +option(NEO_GPS_EXAMPLES_LINK_STATIC "Link examples statically" OFF) + +if (NOT NEO_GPS_BUILD_STATIC_LIB AND NOT NEO_GPS_BUILD_SHARED_LIB) + message(FATAL_ERROR "You must build either shared or static lib, or both") +endif() + +if (NOT NEO_GPS_BUILD_SHARED_LIB) + set(NEO_GPS_EXAMPLES_LINK_STATIC ON) +endif() + +if (NOT NEO_GPS_BUILD_STATIC_LIB) + message("Linking examples/unit tests to shared lib since NEO_GPS_BUILD_STATIC_LIB is turned off") + set(NEO_GPS_EXAMPLES_LINK_STATIC OFF) +endif() + +# Set some nicer output dirs. +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) + +set(NEO_GPS_SRC + src/DMS.cpp + src/GPSTime.cpp + src/Location.cpp + src/NeoTime.cpp + src/NMEAGPS.cpp + src/Streamers.cpp + src/ublox/ubxGPS.cpp + src/ublox/ubxmsg.cpp + src/ublox/ubxNMEA.cpp) + +set(NEO_GPS_HDR + src/CosaCompat.h + src/DMS.h + src/GPSfix_cfg.h + src/GPSfix.h + src/GPSport.h + src/GPSTime.h + src/Location.h + src/NeoGPS_cfg.h + src/NeoTime.h + src/NMEAGPS_cfg.h + src/NMEAGPS.h + src/Platform.h + src/Streamers.h + src/ublox/ubx_cfg.h + src/ublox/ubxGPS.h + src/ublox/ubxmsg.h + src/ublox/ubxNMEA.h) + +source_group("Headers" FILES ${NEO_GPS_HDR}) +source_group("Source" FILES ${NEO_GPS_SRC}) + +if (NEO_GPS_BUILD_STATIC_LIB) + add_library(neogps STATIC ${NEO_GPS_SRC}) + target_link_libraries(neogps dl) + install(TARGETS neogps DESTINATION lib) +endif() + +if (NEO_GPS_BUILD_SHARED_LIB) + if (POLICY CMP0042) + cmake_policy(PUSH) + cmake_policy(SET CMP0042 OLD) + endif() + + add_library(neogps_shared SHARED ${NEO_GPS_SRC}) + target_link_libraries(neogps_shared dl) + + if (UNIX) + set_target_properties(neogps_shared PROPERTIES OUTPUT_NAME neogps) + endif() + + install(TARGETS neogps_shared DESTINATION lib) + + if (POLICY CMP0042) + cmake_policy(POP) + endif() +endif() + +# And copy headers to build dir. +foreach (HDR ${PARSERS_HDRS}) + get_filename_component(HDR_NAME ${HDR} NAME_WE) + message("${HDR}") + configure_file(${HDR} ${PROJECT_BINARY_DIR}/include/neogps/${HDR_NAME}.h COPYONLY) +endforeach() + +include_directories("${PROJECT_BINARY_DIR}/include/") + +if (NEO_GPS_BUILD_EXAMPLES) + # Find all example sources. + file(GLOB EXAMPLE_SRCS + RELATIVE "${PROJECT_SOURCE_DIR}" + "${PROJECT_SOURCE_DIR}/examples/*/*.cpp") + + foreach (EXAMPLE_SRC ${EXAMPLE_SRCS}) + get_filename_component(EXAMPLE_NAME ${EXAMPLE_SRC} NAME_WE) + + add_executable(${EXAMPLE_NAME} ${EXAMPLE_SRC}) + + if (NEO_GPS_EXAMPLES_LINK_STATIC) + target_link_libraries(${EXAMPLE_NAME} neogps) + else() + target_link_libraries(${EXAMPLE_NAME} neogps_shared) + endif() + endforeach() +endif() + From b584def254596d681cacac99b1ad77a948b04d3e Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Wed, 30 Aug 2017 11:26:11 +0200 Subject: [PATCH 13/38] feat: introduced NEO_GPS_{STREAM,PORT,SYSTEM} which encapsulate platform dependent functionality. --- examples/ublox/ublox.ino | 1 + src/DMS.h | 57 +-- src/DMS.header.h | 55 ++ src/{DMS.cpp => DMS.impl.h} | 54 +- src/GPSTime.h | 87 +--- src/GPSTime.header.h | 87 ++++ src/{GPSTime.cpp => GPSTime.impl.h} | 6 +- src/GPSfix.h | 8 +- src/GPSport.h | 6 +- src/Location.h | 130 +---- src/Location.header.h | 128 +++++ src/{Location.cpp => Location.impl.h} | 21 +- src/NMEAGPS.h | 342 +------------ src/NMEAGPS.header.h | 336 ++++++++++++ src/{NMEAGPS.cpp => NMEAGPS.impl.h} | 82 ++- src/NMEAGPS_cfg.h | 18 +- src/NMEAGPSprivate.h | 7 +- src/NeoGPS_cfg.h | 5 +- src/NeoTime.h | 310 +----------- src/NeoTime.header.h | 304 +++++++++++ src/{NeoTime.cpp => NeoTime.impl.h} | 85 ++-- src/Platform.h | 40 ++ src/Streamers.h | 52 +- src/{CosaCompat.h => Streamers.header.h} | 29 +- src/{Streamers.cpp => Streamers.impl.h} | 97 ++-- src/platforms/Print.h | 27 + src/platforms/Stream.h | 18 + src/platforms/System.h | 17 + src/platforms/arduino/platform.h | 36 ++ src/platforms/linux/platform.h | 17 + src/ublox/ubxGPS.h | 334 +----------- src/ublox/ubxGPS.header.h | 332 ++++++++++++ src/ublox/{ubxGPS.cpp => ubxGPS.impl.h} | 8 +- src/ublox/ubxNMEA.h | 112 +--- src/ublox/ubxNMEA.header.h | 110 ++++ src/ublox/{ubxNMEA.cpp => ubxNMEA.impl.h} | 8 +- src/ublox/ubxmsg.h | 591 +--------------------- src/ublox/ubxmsg.header.h | 589 +++++++++++++++++++++ src/ublox/{ubxmsg.cpp => ubxmsg.impl.h} | 8 +- 39 files changed, 2388 insertions(+), 2166 deletions(-) create mode 100644 src/DMS.header.h rename src/{DMS.cpp => DMS.impl.h} (80%) create mode 100644 src/GPSTime.header.h rename src/{GPSTime.cpp => GPSTime.impl.h} (83%) create mode 100644 src/Location.header.h rename src/{Location.cpp => Location.impl.h} (87%) create mode 100644 src/NMEAGPS.header.h rename src/{NMEAGPS.cpp => NMEAGPS.impl.h} (97%) create mode 100644 src/NeoTime.header.h rename src/{NeoTime.cpp => NeoTime.impl.h} (74%) create mode 100644 src/Platform.h rename src/{CosaCompat.h => Streamers.header.h} (50%) rename src/{Streamers.cpp => Streamers.impl.h} (76%) create mode 100644 src/platforms/Print.h create mode 100644 src/platforms/Stream.h create mode 100644 src/platforms/System.h create mode 100644 src/platforms/arduino/platform.h create mode 100644 src/platforms/linux/platform.h create mode 100644 src/ublox/ubxGPS.header.h rename src/ublox/{ubxGPS.cpp => ubxGPS.impl.h} (99%) create mode 100644 src/ublox/ubxNMEA.header.h rename src/ublox/{ubxNMEA.cpp => ubxNMEA.impl.h} (95%) create mode 100644 src/ublox/ubxmsg.header.h rename src/ublox/{ubxmsg.cpp => ubxmsg.impl.h} (92%) diff --git a/examples/ublox/ublox.ino b/examples/ublox/ublox.ino index d501fac..5814446 100644 --- a/examples/ublox/ublox.ino +++ b/examples/ublox/ublox.ino @@ -289,6 +289,7 @@ static MyGPS gps( &gpsPort ); static void configNMEA( uint8_t rate ) { + (void) rate; for (uint8_t i=NMEAGPS::NMEA_FIRST_MSG; i<=NMEAGPS::NMEA_LAST_MSG; i++) { ublox::configNMEA( gps, (NMEAGPS::nmea_msg_t) i, rate ); } diff --git a/src/DMS.h b/src/DMS.h index bcd9986..a3b5891 100644 --- a/src/DMS.h +++ b/src/DMS.h @@ -1,55 +1,4 @@ -#ifndef DMS_H -#define DMS_H +#pragma once -// Copyright (C) 2014-2017, SlashDevin -// -// This file is part of NeoGPS -// -// NeoGPS is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// NeoGPS is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with NeoGPS. If not, see . - -#include "NeoGPS_cfg.h" -#include -class Print; - -enum Hemisphere_t { NORTH_H = 0, SOUTH_H = 1, EAST_H = 0, WEST_H = 1 }; - -class DMS_t -{ -public: - uint8_t degrees; - uint8_t minutes ;//NEOGPS_BF(6); - Hemisphere_t hemisphere ;//NEOGPS_BF(2); compiler bug! - uint8_t seconds_whole NEOGPS_BF(6); - uint16_t seconds_frac NEOGPS_BF(10); // 1000ths - - void init() { degrees = minutes = seconds_whole = seconds_frac = 0; - hemisphere = NORTH_H; } - - float secondsF() const { return seconds_whole + 0.001 * seconds_frac; }; - char NS () const { return (hemisphere == SOUTH_H) ? 'S' : 'N'; }; - char EW () const { return (hemisphere == WEST_H) ? 'W' : 'E'; }; - - //............................................................................. - // A utility function to convert from integer 'lat' or 'lon', scaled by 10^7 - - void From( int32_t deg_1E7 ); - - // Print DMS as the funky NMEA DDDMM.mmmm format - void printDDDMMmmmm( Print & outs ) const; - -} NEOGPS_PACKED; - -extern Print & operator << ( Print & outs, const DMS_t & ); - -#endif \ No newline at end of file +#include "DMS.header.h" +#include "DMS.impl.h" diff --git a/src/DMS.header.h b/src/DMS.header.h new file mode 100644 index 0000000..5a996c6 --- /dev/null +++ b/src/DMS.header.h @@ -0,0 +1,55 @@ +#ifndef DMS_H +#define DMS_H + +// Copyright (C) 2014-2017, SlashDevin +// +// This file is part of NeoGPS +// +// NeoGPS is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// NeoGPS is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with NeoGPS. If not, see . + +#include "NeoGPS_cfg.h" + +#include "Platform.h" + +enum Hemisphere_t { NORTH_H = 0, SOUTH_H = 1, EAST_H = 0, WEST_H = 1 }; + +class DMS_t +{ +public: + uint8_t degrees; + uint8_t minutes ;//NEOGPS_BF(6); + Hemisphere_t hemisphere ;//NEOGPS_BF(2); compiler bug! + uint8_t seconds_whole NEOGPS_BF(6); + uint16_t seconds_frac NEOGPS_BF(10); // 1000ths + + void init() { degrees = minutes = seconds_whole = seconds_frac = 0; + hemisphere = NORTH_H; } + + float secondsF() const { return seconds_whole + 0.001 * seconds_frac; }; + char NS () const { return (hemisphere == SOUTH_H) ? 'S' : 'N'; }; + char EW () const { return (hemisphere == WEST_H) ? 'W' : 'E'; }; + + //............................................................................. + // A utility function to convert from integer 'lat' or 'lon', scaled by 10^7 + + void From( int32_t deg_1E7 ); + + // Print DMS as the funky NMEA DDDMM.mmmm format + void printDDDMMmmmm( NEO_GPS_PRINT & outs ) const; + +} NEOGPS_PACKED; + +extern NEO_GPS_PRINT & operator << ( NEO_GPS_PRINT & outs, const DMS_t & ); + +#endif diff --git a/src/DMS.cpp b/src/DMS.impl.h similarity index 80% rename from src/DMS.cpp rename to src/DMS.impl.h index 198eb0a..8b53729 100644 --- a/src/DMS.cpp +++ b/src/DMS.impl.h @@ -15,9 +15,11 @@ // You should have received a copy of the GNU General Public License // along with NeoGPS. If not, see . -#include "DMS.h" +// Just to be sure. This file should only be included in DMS.h which +// protects against multiple includes already. +#pragma once -#include +#include "DMS.header.h" //---------------------------------------------------------------- // Note that no division is used, and shifts are on byte boundaries. Fast! @@ -66,26 +68,26 @@ void DMS_t::From( int32_t deg_1E7 ) //---------------------------------------------------------------- -Print & operator << ( Print & outs, const DMS_t & dms ) +NEO_GPS_PRINT & operator << ( NEO_GPS_PRINT & outs, const DMS_t & dms ) { if (dms.degrees < 10) - outs.write( '0' ); - outs.print( dms.degrees ); - outs.write( ' ' ); + outs << '0'; + outs << dms.degrees; + outs << ' '; if (dms.minutes < 10) - outs.write( '0' ); - outs.print( dms.minutes ); - outs.print( F("\' ") ); + outs << '0'; + outs << dms.minutes; + outs << F("\' "); if (dms.seconds_whole < 10) - outs.write( '0' ); - outs.print( dms.seconds_whole ); - outs.write( '.' ); + outs << '0'; + outs << dms.seconds_whole; + outs << '.'; if (dms.seconds_frac < 100) - outs.write( '0' ); + outs << '0'; if (dms.seconds_frac < 10) - outs.write( '0' ); - outs.print( dms.seconds_frac ); - outs.print( F("\" ") ); + outs << '0'; + outs << dms.seconds_frac; + outs << F("\" "); return outs; @@ -93,14 +95,14 @@ Print & operator << ( Print & outs, const DMS_t & dms ) //---------------------------------------------------------------- -void DMS_t::printDDDMMmmmm( Print & outs ) const +void DMS_t::printDDDMMmmmm( NEO_GPS_PRINT & outs ) const { - outs.print( degrees ); + outs << degrees; if (minutes < 10) - outs.print( '0' ); - outs.print( minutes ); - outs.print( '.' ); + outs << '0'; + outs << minutes; + outs << '.'; // Calculate the fractional minutes from the seconds, // *without* using floating-point numbers. @@ -112,10 +114,10 @@ void DMS_t::printDDDMMmmmm( Print & outs ) const // print leading zeroes, if necessary if (mmmm < 1000) - outs.print( '0' ); + outs << '0'; if (mmmm < 100) - outs.print( '0' ); + outs << '0'; if (mmmm < 10) - outs.print( '0' ); - outs.print( mmmm ); -} \ No newline at end of file + outs << '0'; + outs << mmmm; +} diff --git a/src/GPSTime.h b/src/GPSTime.h index 235dc07..ab53b91 100644 --- a/src/GPSTime.h +++ b/src/GPSTime.h @@ -1,85 +1,4 @@ -#ifndef GPSTIME_H -#define GPSTIME_H +#pragma once -// Copyright (C) 2014-2017, SlashDevin -// -// This file is part of NeoGPS -// -// NeoGPS is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// NeoGPS is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with NeoGPS. If not, see . - -#include "NeoTime.h" - -class GPSTime -{ - GPSTime(); - - static NeoGPS::clock_t s_start_of_week; - -public: - - /** - * GPS time is offset from UTC by a number of leap seconds. To convert a GPS - * time to UTC time, the current number of leap seconds must be known. - * See http://en.wikipedia.org/wiki/Global_Positioning_System#Leap_seconds - */ - static uint8_t leap_seconds; - - /** - * Some receivers report time WRT start of the current week, defined as - * Sunday 00:00:00. To save fairly expensive date/time calculations, - * the UTC start of week is cached - */ - static void start_of_week( NeoGPS::time_t & now ) - { - now.set_day(); - s_start_of_week = - (NeoGPS::clock_t) now - - (NeoGPS::clock_t) ((((now.day-1 ) * 24L + - now.hours ) * 60L + - now.minutes) * 60L + - now.seconds); - } - - static NeoGPS::clock_t start_of_week() - { - return s_start_of_week; - } - - /* - * Convert a GPS time-of-week to UTC. - * Requires /leap_seconds/ and /start_of_week/. - */ - static NeoGPS::clock_t TOW_to_UTC( uint32_t time_of_week ) - { return (NeoGPS::clock_t) - (start_of_week() + time_of_week - leap_seconds); } - - /** - * Set /fix/ timestamp from a GPS time-of-week in milliseconds. - * Requires /leap_seconds/ and /start_of_week/. - **/ - static bool from_TOWms - ( uint32_t time_of_week_ms, NeoGPS::time_t &dt, uint16_t &ms ) - { -//trace << PSTR("from_TOWms(") << time_of_week_ms << PSTR("), sow = ") << start_of_week() << PSTR(", leap = ") << leap_seconds << endl; - bool ok = (start_of_week() != 0) && (leap_seconds != 0); - if (ok) { - NeoGPS::clock_t tow_s = time_of_week_ms/1000UL; - dt = TOW_to_UTC( tow_s ); - ms = (uint16_t)(time_of_week_ms - tow_s*1000UL); - } - return ok; - } -}; - -#endif \ No newline at end of file +#include "GPSTime.header.h" +#include "GPSTime.impl.h" diff --git a/src/GPSTime.header.h b/src/GPSTime.header.h new file mode 100644 index 0000000..ee771ed --- /dev/null +++ b/src/GPSTime.header.h @@ -0,0 +1,87 @@ +#ifndef GPSTIME_H +#define GPSTIME_H + +// Copyright (C) 2014-2017, SlashDevin +// +// This file is part of NeoGPS +// +// NeoGPS is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// NeoGPS is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with NeoGPS. If not, see . + +#include "Platform.h" + +#include "NeoTime.header.h" + +class GPSTime +{ + GPSTime(); + + static NeoGPS::clock_t s_start_of_week; + +public: + + /** + * GPS time is offset from UTC by a number of leap seconds. To convert a GPS + * time to UTC time, the current number of leap seconds must be known. + * See http://en.wikipedia.org/wiki/Global_Positioning_System#Leap_seconds + */ + static uint8_t leap_seconds; + + /** + * Some receivers report time WRT start of the current week, defined as + * Sunday 00:00:00. To save fairly expensive date/time calculations, + * the UTC start of week is cached + */ + static void start_of_week( NeoGPS::time_t & now ) + { + now.set_day(); + s_start_of_week = + (NeoGPS::clock_t) now - + (NeoGPS::clock_t) ((((now.day-1 ) * 24L + + now.hours ) * 60L + + now.minutes) * 60L + + now.seconds); + } + + static NeoGPS::clock_t start_of_week() + { + return s_start_of_week; + } + + /* + * Convert a GPS time-of-week to UTC. + * Requires /leap_seconds/ and /start_of_week/. + */ + static NeoGPS::clock_t TOW_to_UTC( uint32_t time_of_week ) + { return (NeoGPS::clock_t) + (start_of_week() + time_of_week - leap_seconds); } + + /** + * Set /fix/ timestamp from a GPS time-of-week in milliseconds. + * Requires /leap_seconds/ and /start_of_week/. + **/ + static bool from_TOWms + ( uint32_t time_of_week_ms, NeoGPS::time_t &dt, uint16_t &ms ) + { +//trace << PSTR("from_TOWms(") << time_of_week_ms << PSTR("), sow = ") << start_of_week() << PSTR(", leap = ") << leap_seconds << endl; + bool ok = (start_of_week() != 0) && (leap_seconds != 0); + if (ok) { + NeoGPS::clock_t tow_s = time_of_week_ms/1000UL; + dt = TOW_to_UTC( tow_s ); + ms = (uint16_t)(time_of_week_ms - tow_s*1000UL); + } + return ok; + } +}; + +#endif diff --git a/src/GPSTime.cpp b/src/GPSTime.impl.h similarity index 83% rename from src/GPSTime.cpp rename to src/GPSTime.impl.h index cee247f..70bb5ca 100644 --- a/src/GPSTime.cpp +++ b/src/GPSTime.impl.h @@ -15,7 +15,11 @@ // You should have received a copy of the GNU General Public License // along with NeoGPS. If not, see . -#include "GPSTime.h" +// Just to be sure. This file should only be included in GPSTime.h which +// protects against multiple includes already. +#pragma once + +#include "GPSTime.header.h" uint8_t GPSTime::leap_seconds = 0; NeoGPS::clock_t GPSTime::s_start_of_week = 0; diff --git a/src/GPSfix.h b/src/GPSfix.h index a8eff41..d645b63 100644 --- a/src/GPSfix.h +++ b/src/GPSfix.h @@ -22,15 +22,15 @@ #include "GPSfix_cfg.h" #if defined( GPS_FIX_DATE ) | defined( GPS_FIX_TIME ) - #include "NeoTime.h" + #include "NeoTime.header.h" #endif #ifdef GPS_FIX_LOCATION_DMS - #include "DMS.h" + #include "DMS.header.h" #endif #ifdef GPS_FIX_LOCATION - #include "Location.h" + #include "Location.header.h" #endif /** @@ -495,4 +495,4 @@ class gps_fix } NEOGPS_PACKED; -#endif \ No newline at end of file +#endif diff --git a/src/GPSport.h b/src/GPSport.h index 05b3e72..ea40970 100644 --- a/src/GPSport.h +++ b/src/GPSport.h @@ -124,6 +124,10 @@ // so that you could use one of the other recommended ports. //----------------------------------------------------------- +#ifndef ARDUINO + #error "GPSport.h is only useful for the Arduino platform." +#endif + // DEFAULT file contents: // *GUESS* which port should be used. If you know what port you want to use, // *DELETE* the rest of this file and declare your own port @@ -252,4 +256,4 @@ // End of guessing game. //------------------------ -#endif \ No newline at end of file +#endif diff --git a/src/Location.h b/src/Location.h index 8b0e054..659b55e 100644 --- a/src/Location.h +++ b/src/Location.h @@ -1,128 +1,4 @@ -#ifndef NEOGPS_LOCATION_H -#define NEOGPS_LOCATION_H +#pragma once -#include - -#include "NeoGPS_cfg.h" - -// Copyright (C) 2014-2017, SlashDevin -// -// This file is part of NeoGPS -// -// NeoGPS is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// NeoGPS is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with NeoGPS. If not, see . - -class NMEAGPS; - -namespace NeoGPS { - -class Location_t -{ -public: - CONST_CLASS_DATA float LOC_SCALE = 1.0e-7; - - Location_t() {} - Location_t( int32_t lat, int32_t lon ) - : _lat(lat), _lon(lon) - {} - Location_t( float lat, float lon ) - : _lat(lat / LOC_SCALE), _lon(lon / LOC_SCALE) - {} - Location_t( double lat, double lon ) - : _lat(lat / LOC_SCALE), _lon(lon / LOC_SCALE) - {} - - int32_t lat() const { return _lat; }; - void lat( int32_t l ) { _lat = l; }; - float latF() const { return ((float) lat()) * LOC_SCALE; }; - void latF( float v ) { _lat = v * LOC_SCALE; }; - - int32_t lon() const { return _lon; }; - void lon( int32_t l ) { _lon = l; }; - float lonF() const { return ((float) lon()) * LOC_SCALE; }; - void lonF( float v ) { _lon = v * LOC_SCALE; }; - - void init() { _lat = _lon = 0; }; - - CONST_CLASS_DATA float EARTH_RADIUS_KM = 6371.0088; - CONST_CLASS_DATA float RAD_PER_DEG = PI / 180.0; - CONST_CLASS_DATA float DEG_PER_RAD = 180.0 / PI; - CONST_CLASS_DATA float MI_PER_KM = 0.621371; - - //----------------------------------- - // Distance calculations - - static float DistanceKm( const Location_t & p1, const Location_t & p2 ) - { - return DistanceRadians( p1, p2 ) * EARTH_RADIUS_KM; - } - float DistanceKm( const Location_t & p2 ) - { return DistanceKm( *this, p2 ); } - - static float DistanceMiles( const Location_t & p1, const Location_t & p2 ) - { - return DistanceRadians( p1, p2 ) * EARTH_RADIUS_KM * MI_PER_KM; - } - float DistanceMiles( const Location_t & p2 ) - { return DistanceMiles( *this, p2 ); } - - static float DistanceRadians( const Location_t & p1, const Location_t & p2 ); - float DistanceRadians( const Location_t & p2 ) - { return DistanceRadians( *this, p2 ); } - - static float EquirectDistanceRadians - ( const Location_t & p1, const Location_t & p2 ); - float EquirectDistanceRadians( const Location_t & p2 ) - { return EquirectDistanceRadians( *this, p2 ); } - - static float EquirectDistanceKm( const Location_t & p1, const Location_t & p2 ) - { - return EquirectDistanceRadians( p1, p2 ) * EARTH_RADIUS_KM; - } - float EquirectDistanceKm( const Location_t & p2 ) const - { return EquirectDistanceKm( *this, p2 ); } - - static float EquirectDistanceMiles( const Location_t & p1, const Location_t & p2 ) - { - return EquirectDistanceRadians( p1, p2 ) * EARTH_RADIUS_KM * MI_PER_KM; - } - float EquirectDistanceMiles( const Location_t & p2 ) const - { return EquirectDistanceMiles( *this, p2 ); } - - //----------------------------------- - // Bearing calculations - - static float BearingTo( const Location_t & p1, const Location_t & p2 ); // radians - float BearingTo( const Location_t & p2 ) const // radians - { return BearingTo( *this, p2 ); } - - static float BearingToDegrees( const Location_t & p1, const Location_t & p2 ) - { return BearingTo( p1, p2 ) * DEG_PER_RAD; } - float BearingToDegrees( const Location_t & p2 ) const // radians - { return BearingToDegrees( *this, p2 ); } - - //----------------------------------- - // Offset a location (note distance is in radians, not degrees) - void OffsetBy( float distR, float bearingR ); - -//private: //--------------------------------------- - friend class NMEAGPS; // This does not work?!? - - int32_t _lat; // degrees * 1e7, negative is South - int32_t _lon; // degrees * 1e7, negative is West - -} NEOGPS_PACKED; - -} // NeoGPS - -#endif \ No newline at end of file +#include "Location.header.h" +#include "Location.impl.h" diff --git a/src/Location.header.h b/src/Location.header.h new file mode 100644 index 0000000..fb81fdd --- /dev/null +++ b/src/Location.header.h @@ -0,0 +1,128 @@ +#ifndef NEOGPS_LOCATION_H +#define NEOGPS_LOCATION_H + +#include "Platform.h" + +#include "NeoGPS_cfg.h" + +// Copyright (C) 2014-2017, SlashDevin +// +// This file is part of NeoGPS +// +// NeoGPS is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// NeoGPS is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with NeoGPS. If not, see . + +class NMEAGPS; + +namespace NeoGPS { + +class Location_t +{ +public: + CONST_CLASS_DATA float LOC_SCALE = 1.0e-7; + + Location_t() {} + Location_t( int32_t lat, int32_t lon ) + : _lat(lat), _lon(lon) + {} + Location_t( float lat, float lon ) + : _lat(lat / LOC_SCALE), _lon(lon / LOC_SCALE) + {} + Location_t( double lat, double lon ) + : _lat(lat / LOC_SCALE), _lon(lon / LOC_SCALE) + {} + + int32_t lat() const { return _lat; }; + void lat( int32_t l ) { _lat = l; }; + float latF() const { return ((float) lat()) * LOC_SCALE; }; + void latF( float v ) { _lat = v * LOC_SCALE; }; + + int32_t lon() const { return _lon; }; + void lon( int32_t l ) { _lon = l; }; + float lonF() const { return ((float) lon()) * LOC_SCALE; }; + void lonF( float v ) { _lon = v * LOC_SCALE; }; + + void init() { _lat = _lon = 0; }; + + CONST_CLASS_DATA float EARTH_RADIUS_KM = 6371.0088; + CONST_CLASS_DATA float RAD_PER_DEG = PI / 180.0; + CONST_CLASS_DATA float DEG_PER_RAD = 180.0 / PI; + CONST_CLASS_DATA float MI_PER_KM = 0.621371; + + //----------------------------------- + // Distance calculations + + static float DistanceKm( const Location_t & p1, const Location_t & p2 ) + { + return DistanceRadians( p1, p2 ) * EARTH_RADIUS_KM; + } + float DistanceKm( const Location_t & p2 ) + { return DistanceKm( *this, p2 ); } + + static float DistanceMiles( const Location_t & p1, const Location_t & p2 ) + { + return DistanceRadians( p1, p2 ) * EARTH_RADIUS_KM * MI_PER_KM; + } + float DistanceMiles( const Location_t & p2 ) + { return DistanceMiles( *this, p2 ); } + + static float DistanceRadians( const Location_t & p1, const Location_t & p2 ); + float DistanceRadians( const Location_t & p2 ) + { return DistanceRadians( *this, p2 ); } + + static float EquirectDistanceRadians + ( const Location_t & p1, const Location_t & p2 ); + float EquirectDistanceRadians( const Location_t & p2 ) + { return EquirectDistanceRadians( *this, p2 ); } + + static float EquirectDistanceKm( const Location_t & p1, const Location_t & p2 ) + { + return EquirectDistanceRadians( p1, p2 ) * EARTH_RADIUS_KM; + } + float EquirectDistanceKm( const Location_t & p2 ) const + { return EquirectDistanceKm( *this, p2 ); } + + static float EquirectDistanceMiles( const Location_t & p1, const Location_t & p2 ) + { + return EquirectDistanceRadians( p1, p2 ) * EARTH_RADIUS_KM * MI_PER_KM; + } + float EquirectDistanceMiles( const Location_t & p2 ) const + { return EquirectDistanceMiles( *this, p2 ); } + + //----------------------------------- + // Bearing calculations + + static float BearingTo( const Location_t & p1, const Location_t & p2 ); // radians + float BearingTo( const Location_t & p2 ) const // radians + { return BearingTo( *this, p2 ); } + + static float BearingToDegrees( const Location_t & p1, const Location_t & p2 ) + { return BearingTo( p1, p2 ) * DEG_PER_RAD; } + float BearingToDegrees( const Location_t & p2 ) const // radians + { return BearingToDegrees( *this, p2 ); } + + //----------------------------------- + // Offset a location (note distance is in radians, not degrees) + void OffsetBy( float distR, float bearingR ); + +//private: //--------------------------------------- + friend class NMEAGPS; // This does not work?!? + + int32_t _lat; // degrees * 1e7, negative is South + int32_t _lon; // degrees * 1e7, negative is West + +} NEOGPS_PACKED; + +} // NeoGPS + +#endif diff --git a/src/Location.cpp b/src/Location.impl.h similarity index 87% rename from src/Location.cpp rename to src/Location.impl.h index 10eb453..dacfb02 100644 --- a/src/Location.cpp +++ b/src/Location.impl.h @@ -15,9 +15,12 @@ // You should have received a copy of the GNU General Public License // along with NeoGPS. If not, see . -#include "Location.h" -using namespace NeoGPS; +// Just to be sure. This file should only be included in Location.h which +// protects against multiple includes already. +#pragma once + +#include "Location.header.h" //--------------------------------------------------------------------- // Calculate dLon with integers, less one bit to avoid overflow @@ -41,8 +44,8 @@ int32_t safeDLon( int32_t p2, int32_t p1 ) //--------------------------------------------------------------------- -float Location_t::DistanceRadians - ( const Location_t & p1, const Location_t & p2 ) +float NeoGPS::Location_t::DistanceRadians + ( const NeoGPS::Location_t & p1, const NeoGPS::Location_t & p2 ) { int32_t dLonL = safeDLon( p2.lon(), p1.lon() ); int32_t dLatL = p2.lat() - p1.lat(); @@ -77,8 +80,8 @@ float Location_t::DistanceRadians //--------------------------------------------------------------------- -float Location_t::EquirectDistanceRadians - ( const Location_t & p1, const Location_t & p2 ) +float NeoGPS::Location_t::EquirectDistanceRadians + ( const NeoGPS::Location_t & p1, const NeoGPS::Location_t & p2 ) { // Equirectangular calculation from http://www.movable-type.co.uk/scripts/latlong.html @@ -91,7 +94,7 @@ float Location_t::EquirectDistanceRadians //--------------------------------------------------------------------- -float Location_t::BearingTo( const Location_t & p1, const Location_t & p2 ) +float NeoGPS::Location_t::BearingTo( const NeoGPS::Location_t & p1, const NeoGPS::Location_t & p2 ) { int32_t dLonL = safeDLon( p2.lon(), p1.lon() ); float dLon = dLonL * RAD_PER_DEG * LOC_SCALE; @@ -123,7 +126,7 @@ float Location_t::BearingTo( const Location_t & p1, const Location_t & p2 ) //--------------------------------------------------------------------- -void Location_t::OffsetBy( float distR, float bearingR ) +void NeoGPS::Location_t::OffsetBy( float distR, float bearingR ) { float lat1 = lat() * RAD_PER_DEG * LOC_SCALE; float newLat = asin( sin(lat1)*cos(distR) + @@ -134,4 +137,4 @@ void Location_t::OffsetBy( float distR, float bearingR ) _lat = (newLat / (RAD_PER_DEG * LOC_SCALE)); _lon += (dLon / (RAD_PER_DEG * LOC_SCALE)); -} // OffsetBy \ No newline at end of file +} // OffsetBy diff --git a/src/NMEAGPS.h b/src/NMEAGPS.h index 6e28372..2ce2184 100644 --- a/src/NMEAGPS.h +++ b/src/NMEAGPS.h @@ -1,340 +1,4 @@ -#ifndef NMEAGPS_H -#define NMEAGPS_H +#pragma once -// Copyright (C) 2014-2017, SlashDevin -// -// This file is part of NeoGPS -// -// NeoGPS is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// NeoGPS is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with NeoGPS. If not, see . - -#include "CosaCompat.h" - -#include -#ifdef __AVR__ - #include -#endif - -#include "GPSfix.h" -#include "NMEAGPS_cfg.h" - -//------------------------------------------------------ -// -// NMEA 0183 Parser for generic GPS Modules. -// -// As bytes are received from the device, they affect the -// internal FSM and set various members of the current /fix/. -// As multiple sentences are received, they are (optionally) -// merged into a single fix. When the last sentence in a time -// interval (usually 1 second) is received, the fix is stored -// in the (optional) buffer of fixes. -// -// Only these NMEA messages are parsed: -// GGA, GLL, GSA, GST, GSV, RMC, VTG, and ZDA. - -class NMEAGPS -{ - NMEAGPS & operator =( const NMEAGPS & ); - NMEAGPS( const NMEAGPS & ); - -public: - - NMEAGPS(); - - //....................................................................... - // NMEA standard message types (aka "sentences") - - enum nmea_msg_t { - NMEA_UNKNOWN, - - #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) - NMEA_GGA, - #endif - - #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) - NMEA_GLL, - #endif - - #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) - NMEA_GSA, - #endif - - #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) - NMEA_GST, - #endif - - #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) - NMEA_GSV, - #endif - - #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) - NMEA_RMC, - #endif - - #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) - NMEA_VTG, - #endif - - #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) - NMEA_ZDA, - #endif - - NMEAMSG_END // a bookend that tells how many enums there were - }; - - CONST_CLASS_DATA nmea_msg_t NMEA_FIRST_MSG = (nmea_msg_t) (NMEA_UNKNOWN+1); - CONST_CLASS_DATA nmea_msg_t NMEA_LAST_MSG = (nmea_msg_t) (NMEAMSG_END-1); - - //======================================================================= - // FIX-ORIENTED methods: available, read, overrun and handle - //======================================================================= - // The typical sketch should have something like this in loop(): - // - // while (gps.available( Serial1 )) { - // gps_fix fix = gps.read(); - // if (fix.valid.location) { - // ... - // } - // } - - //....................................................................... - // The available(...) functions return the number of *fixes* that - // are available to be "read" from the fix buffer. The GPS port - // object is passed in so a char can be read if port.available(). - - uint8_t available( Stream & port ) - { - if (processing_style == PS_POLLING) - while (port.available()) - handle( port.read() ); - return _available(); - } - uint8_t available() const volatile { return _available(); }; - - //....................................................................... - // Return the next available fix. When no more fixes - // are available, it returns an empty fix. - - const gps_fix read(); - - //....................................................................... - // The OVERRUN flag is set whenever a fix is not read by the time - // the next update interval starts. You must clear it when you - // detect the condition. - - bool overrun() const { return _overrun; } - void overrun( bool val ) { _overrun = val; } - - //....................................................................... - // As characters are processed, they can be categorized as - // INVALID (not part of this protocol), OK (accepted), - // or COMPLETED (end-of-message). - - enum decode_t { DECODE_CHR_INVALID, DECODE_CHR_OK, DECODE_COMPLETED }; - - //....................................................................... - // Process one character, possibly saving a buffered fix. - // It implements merging and coherency. - // This can be called from an ISR. - - decode_t handle( uint8_t c ); - - //======================================================================= - // CHARACTER-ORIENTED methods: decode, fix and is_safe - //======================================================================= - // - // *** MOST APPLICATIONS SHOULD USE THE FIX-ORIENTED METHODS *** - // - // Using `decode` is only necessary if you want finer control - // on how fix information is filtered and merged. - // - // Process one character of an NMEA GPS sentence. The internal state - // machine tracks what part of the sentence has been received. As the - // sentence is received, members of the /fix/ structure are updated. - // This character-oriented method *does not* buffer any fixes, and - // /read()/ will always return an empty fix. - // - // @return DECODE_COMPLETED when a sentence has been completely received. - - NMEAGPS_VIRTUAL decode_t decode( char c ); - - //....................................................................... - // Current fix accessor. - // *** MOST APPLICATIONS SHOULD USE read() TO GET THE CURRENT FIX *** - // /fix/ will be constantly changing as characters are received. - // - // For example, fix().longitude() may return nonsense data if - // characters for that field are currently being processed in /decode/. - - gps_fix & fix() { return m_fix; }; - - // NOTE: /is_safe/ *must* be checked before accessing members of /fix/. - // If you need access to the current /fix/ at any time, you should - // use the FIX-ORIENTED methods. - - //....................................................................... - // Determine whether the members of /fix/ are "currently" safe. - // It will return true when a complete sentence and the CRC characters - // have been received (or after a CR if no CRC is present). - // It will return false after a new sentence starts. - - bool is_safe() const volatile { return (rxState == NMEA_IDLE); } - - // NOTE: When INTERRUPT_PROCESSING is enabled, is_safe() - // and fix() could change at any time (i.e., they should be - // considered /volatile/). - - //======================================================================= - // DATA MEMBER accessors and mutators - //======================================================================= - - //....................................................................... - // Convert a nmea_msg_t to a PROGMEM string. - // Useful for printing the sentence type instead of a number. - // This can return "UNK" if the message is not a valid number. - - const __FlashStringHelper *string_for( nmea_msg_t msg ) const; - - //....................................................................... - // Most recent NMEA sentence type received. - - enum nmea_msg_t nmeaMessage NEOGPS_BF(8); - - //....................................................................... - // Storage for Talker and Manufacturer IDs - - #ifdef NMEAGPS_SAVE_TALKER_ID - char talker_id[2]; - #endif - - #ifdef NMEAGPS_SAVE_MFR_ID - char mfr_id[3]; - #endif - - //....................................................................... - // Various parsing statistics - - #ifdef NMEAGPS_STATS - struct statistics_t { - uint32_t ok; // count of successfully parsed sentences - uint32_t errors; // NMEA checksum or other message errors - uint32_t chars; - void init() - { - ok = 0L; - errors = 0L; - chars = 0L; - } - } statistics; - #endif - - //....................................................................... - // SATELLITE VIEW array - - #ifdef NMEAGPS_PARSE_SATELLITES - struct satellite_view_t - { - uint8_t id; - #ifdef NMEAGPS_PARSE_SATELLITE_INFO - uint8_t elevation; // 0..99 deg - uint16_t azimuth; // 0..359 deg - uint8_t snr NEOGPS_BF(7); // 0..99 dBHz - bool tracked NEOGPS_BF(1); - #endif - } NEOGPS_PACKED; - - satellite_view_t satellites[ NMEAGPS_MAX_SATELLITES ]; - uint8_t sat_count; // in the above array - - bool satellites_valid() const { return (sat_count >= m_fix.satellites); } - #endif - - //....................................................................... - // Reset the parsing process. - // This is used internally after a CS error, or could be used - // externally to abort processing if it has been too long - // since any data was received. - - void reset() - { - rxState = NMEA_IDLE; - } - - //======================================================================= - // CORRELATING Arduino micros() WITH UTC. - //======================================================================= - - #if defined(NMEAGPS_TIMESTAMP_FROM_PPS) | \ - defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL) - protected: - uint32_t _UTCsecondStart; - #if defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL) & \ - ( defined(GPS_FIX_DATE) | defined(GPS_FIX_TIME) ) - uint32_t _IntervalStart; // quiet time just ended - #endif - public: - - // The micros() value when the current UTC second started - uint32_t UTCsecondStart() const - { lock(); - uint32_t ret = _UTCsecondStart; - unlock(); - return ret; - }; - void UTCsecondStart( uint32_t us ) { _UTCsecondStart = us; }; - - // The elapsed time since the start of the current UTC second - uint32_t UTCus() const { return micros() - UTCsecondStart(); }; - uint32_t UTCms() const { return UTCus() / 1000UL; }; - - // If you have attached a Pin Change interrupt routine to the PPS pin: - // - // const int PPSpin = 5; - // void PPSisr() { gps.UTCsecondStart( micros() ); }; - // void setup() - // { - // attachInterrupt( digitalPinToInterrupt(PPSpin), PPSisr, RISING ); - // } - // - // If you are using an Input Capture pin, calculate the elapsed - // microseconds since the capture time (based on the TIMER - // frequency): - // - // void savePPSus() // called as an ISR or from a test in loop - // { - // uint32_t elapsedUS = (currentCount - captureCount) * countUS; - // gps.UTCsecondStart( micros() - elapsedUS ); - // } - #endif - - //======================================================================= - // COMMUNICATING WITH THE GPS DEVICE: poll, send and send_P - //======================================================================= - - //....................................................................... - // Request the specified NMEA sentence. Not all devices will respond. - - static void poll( Stream *device, nmea_msg_t msg ); - - //....................................................................... - // Send a message to the GPS device. - // The '$' is optional, and the '*' and CS will be added automatically. - - static void send( Stream *device, const char *msg ); - static void send_P( Stream *device, const __FlashStringHelper *msg ); - - #include "NMEAGPSprivate.h" - -} NEOGPS_PACKED; - -#endif +#include "NMEAGPS.header.h" +#include "NMEAGPS.impl.h" diff --git a/src/NMEAGPS.header.h b/src/NMEAGPS.header.h new file mode 100644 index 0000000..1daa73f --- /dev/null +++ b/src/NMEAGPS.header.h @@ -0,0 +1,336 @@ +#ifndef NMEAGPS_H +#define NMEAGPS_H + +// Copyright (C) 2014-2017, SlashDevin +// +// This file is part of NeoGPS +// +// NeoGPS is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// NeoGPS is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with NeoGPS. If not, see . + +#include "Platform.h" + +#include "GPSfix.h" +#include "NMEAGPS_cfg.h" + +//------------------------------------------------------ +// +// NMEA 0183 Parser for generic GPS Modules. +// +// As bytes are received from the device, they affect the +// internal FSM and set various members of the current /fix/. +// As multiple sentences are received, they are (optionally) +// merged into a single fix. When the last sentence in a time +// interval (usually 1 second) is received, the fix is stored +// in the (optional) buffer of fixes. +// +// Only these NMEA messages are parsed: +// GGA, GLL, GSA, GST, GSV, RMC, VTG, and ZDA. + +class NMEAGPS +{ + NMEAGPS & operator =( const NMEAGPS & ); + NMEAGPS( const NMEAGPS & ); + +public: + + NMEAGPS(); + + //....................................................................... + // NMEA standard message types (aka "sentences") + + enum nmea_msg_t { + NMEA_UNKNOWN, + + #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) + NMEA_GGA, + #endif + + #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) + NMEA_GLL, + #endif + + #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) + NMEA_GSA, + #endif + + #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) + NMEA_GST, + #endif + + #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) + NMEA_GSV, + #endif + + #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) + NMEA_RMC, + #endif + + #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) + NMEA_VTG, + #endif + + #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) + NMEA_ZDA, + #endif + + NMEAMSG_END // a bookend that tells how many enums there were + }; + + CONST_CLASS_DATA nmea_msg_t NMEA_FIRST_MSG = (nmea_msg_t) (NMEA_UNKNOWN+1); + CONST_CLASS_DATA nmea_msg_t NMEA_LAST_MSG = (nmea_msg_t) (NMEAMSG_END-1); + + //======================================================================= + // FIX-ORIENTED methods: available, read, overrun and handle + //======================================================================= + // The typical sketch should have something like this in loop(): + // + // while (gps.available( Serial1 )) { + // gps_fix fix = gps.read(); + // if (fix.valid.location) { + // ... + // } + // } + + //....................................................................... + // The available(...) functions return the number of *fixes* that + // are available to be "read" from the fix buffer. The GPS port + // object is passed in so a char can be read if port.available(). + + uint8_t available( NEO_GPS_STREAM & port ) + { + if (processing_style == PS_POLLING) + while (port.available()) + handle( port.read() ); + return _available(); + } + uint8_t available() const volatile { return _available(); }; + + //....................................................................... + // Return the next available fix. When no more fixes + // are available, it returns an empty fix. + + const gps_fix read(); + + //....................................................................... + // The OVERRUN flag is set whenever a fix is not read by the time + // the next update interval starts. You must clear it when you + // detect the condition. + + bool overrun() const { return _overrun; } + void overrun( bool val ) { _overrun = val; } + + //....................................................................... + // As characters are processed, they can be categorized as + // INVALID (not part of this protocol), OK (accepted), + // or COMPLETED (end-of-message). + + enum decode_t { DECODE_CHR_INVALID, DECODE_CHR_OK, DECODE_COMPLETED }; + + //....................................................................... + // Process one character, possibly saving a buffered fix. + // It implements merging and coherency. + // This can be called from an ISR. + + decode_t handle( uint8_t c ); + + //======================================================================= + // CHARACTER-ORIENTED methods: decode, fix and is_safe + //======================================================================= + // + // *** MOST APPLICATIONS SHOULD USE THE FIX-ORIENTED METHODS *** + // + // Using `decode` is only necessary if you want finer control + // on how fix information is filtered and merged. + // + // Process one character of an NMEA GPS sentence. The internal state + // machine tracks what part of the sentence has been received. As the + // sentence is received, members of the /fix/ structure are updated. + // This character-oriented method *does not* buffer any fixes, and + // /read()/ will always return an empty fix. + // + // @return DECODE_COMPLETED when a sentence has been completely received. + + NMEAGPS_VIRTUAL decode_t decode( char c ); + + //....................................................................... + // Current fix accessor. + // *** MOST APPLICATIONS SHOULD USE read() TO GET THE CURRENT FIX *** + // /fix/ will be constantly changing as characters are received. + // + // For example, fix().longitude() may return nonsense data if + // characters for that field are currently being processed in /decode/. + + gps_fix & fix() { return m_fix; }; + + // NOTE: /is_safe/ *must* be checked before accessing members of /fix/. + // If you need access to the current /fix/ at any time, you should + // use the FIX-ORIENTED methods. + + //....................................................................... + // Determine whether the members of /fix/ are "currently" safe. + // It will return true when a complete sentence and the CRC characters + // have been received (or after a CR if no CRC is present). + // It will return false after a new sentence starts. + + bool is_safe() const volatile { return (rxState == NMEA_IDLE); } + + // NOTE: When INTERRUPT_PROCESSING is enabled, is_safe() + // and fix() could change at any time (i.e., they should be + // considered /volatile/). + + //======================================================================= + // DATA MEMBER accessors and mutators + //======================================================================= + + //....................................................................... + // Convert a nmea_msg_t to a PROGMEM string. + // Useful for printing the sentence type instead of a number. + // This can return "UNK" if the message is not a valid number. + + const __FlashStringHelper *string_for( nmea_msg_t msg ) const; + + //....................................................................... + // Most recent NMEA sentence type received. + + enum nmea_msg_t nmeaMessage NEOGPS_BF(8); + + //....................................................................... + // Storage for Talker and Manufacturer IDs + + #ifdef NMEAGPS_SAVE_TALKER_ID + char talker_id[2]; + #endif + + #ifdef NMEAGPS_SAVE_MFR_ID + char mfr_id[3]; + #endif + + //....................................................................... + // Various parsing statistics + + #ifdef NMEAGPS_STATS + struct statistics_t { + uint32_t ok; // count of successfully parsed sentences + uint32_t errors; // NMEA checksum or other message errors + uint32_t chars; + void init() + { + ok = 0L; + errors = 0L; + chars = 0L; + } + } statistics; + #endif + + //....................................................................... + // SATELLITE VIEW array + + #ifdef NMEAGPS_PARSE_SATELLITES + struct satellite_view_t + { + uint8_t id; + #ifdef NMEAGPS_PARSE_SATELLITE_INFO + uint8_t elevation; // 0..99 deg + uint16_t azimuth; // 0..359 deg + uint8_t snr NEOGPS_BF(7); // 0..99 dBHz + bool tracked NEOGPS_BF(1); + #endif + } NEOGPS_PACKED; + + satellite_view_t satellites[ NMEAGPS_MAX_SATELLITES ]; + uint8_t sat_count; // in the above array + + bool satellites_valid() const { return (sat_count >= m_fix.satellites); } + #endif + + //....................................................................... + // Reset the parsing process. + // This is used internally after a CS error, or could be used + // externally to abort processing if it has been too long + // since any data was received. + + void reset() + { + rxState = NMEA_IDLE; + } + + //======================================================================= + // CORRELATING Arduino micros() WITH UTC. + //======================================================================= + + #if defined ARDUINO && \ + (defined(NMEAGPS_TIMESTAMP_FROM_PPS) || \ + defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL)) + protected: + uint32_t _UTCsecondStart; + #if defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL) & \ + ( defined(GPS_FIX_DATE) | defined(GPS_FIX_TIME) ) + uint32_t _IntervalStart; // quiet time just ended + #endif + public: + + // The micros() value when the current UTC second started + uint32_t UTCsecondStart() const + { lock(); + uint32_t ret = _UTCsecondStart; + unlock(); + return ret; + }; + void UTCsecondStart( uint32_t us ) { _UTCsecondStart = us; }; + + // The elapsed time since the start of the current UTC second + uint32_t UTCus() const { return micros() - UTCsecondStart(); }; + uint32_t UTCms() const { return UTCus() / 1000UL; }; + + // If you have attached a Pin Change interrupt routine to the PPS pin: + // + // const int PPSpin = 5; + // void PPSisr() { gps.UTCsecondStart( micros() ); }; + // void setup() + // { + // attachInterrupt( digitalPinToInterrupt(PPSpin), PPSisr, RISING ); + // } + // + // If you are using an Input Capture pin, calculate the elapsed + // microseconds since the capture time (based on the TIMER + // frequency): + // + // void savePPSus() // called as an ISR or from a test in loop + // { + // uint32_t elapsedUS = (currentCount - captureCount) * countUS; + // gps.UTCsecondStart( micros() - elapsedUS ); + // } + #endif + + //======================================================================= + // COMMUNICATING WITH THE GPS DEVICE: poll, send and send_P + //======================================================================= + + //....................................................................... + // Request the specified NMEA sentence. Not all devices will respond. + + static void poll( NEO_GPS_STREAM *device, nmea_msg_t msg ); + + //....................................................................... + // Send a message to the GPS device. + // The '$' is optional, and the '*' and CS will be added automatically. + + static void send( NEO_GPS_STREAM *device, const char *msg ); + static void send_P( NEO_GPS_STREAM *device, const __FlashStringHelper *msg ); + + #include "NMEAGPSprivate.h" + +} NEOGPS_PACKED; + +#endif diff --git a/src/NMEAGPS.cpp b/src/NMEAGPS.impl.h similarity index 97% rename from src/NMEAGPS.cpp rename to src/NMEAGPS.impl.h index 5920ee4..64b9910 100644 --- a/src/NMEAGPS.cpp +++ b/src/NMEAGPS.impl.h @@ -15,9 +15,15 @@ // You should have received a copy of the GNU General Public License // along with NeoGPS. If not, see . -#include "NMEAGPS.h" -#include +// Just to be sure. This file should only be included in NMEAGPS.h which +// protects against multiple includes already. +#pragma once + +#pragma push_macro( "CR" ) +#pragma push_macro( "LF" ) + +#include "NMEAGPS.header.h" // Check configurations @@ -724,6 +730,8 @@ bool NMEAGPS::parseGGA( char chr ) case 9: return parseAlt( chr ); case 11: return parseGeoidHeight( chr ); } + #else + (void) chr; #endif return true; @@ -740,6 +748,8 @@ bool NMEAGPS::parseGLL( char chr ) case 5: return parseTime( chr ); case 7: return parseFix( chr ); } + #else + (void) chr; #endif return true; @@ -805,6 +815,8 @@ bool NMEAGPS::parseGSA( char chr ) #endif #endif } + #else + (void) chr; #endif return true; @@ -822,6 +834,8 @@ bool NMEAGPS::parseGST( char chr ) case 7: return parse_lon_err( chr ); case 8: return parse_alt_err( chr ); } + #else + (void) chr; #endif return true; @@ -869,6 +883,8 @@ bool NMEAGPS::parseGSV( char chr ) } } } + #else + (void) chr; #endif return true; @@ -889,6 +905,8 @@ bool NMEAGPS::parseRMC( char chr ) case 9: return parseDDMMYY ( chr ); // case 12: return parseFix ( chr ); ublox only! } + #else + (void) chr; #endif return true; @@ -905,6 +923,8 @@ bool NMEAGPS::parseVTG( char chr ) case 5: return parseSpeed( chr ); case 9: return parseFix( chr ); } + #else + (void) chr; #endif return true; @@ -942,6 +962,8 @@ bool NMEAGPS::parseZDA( char chr ) break; #endif } + #else + (void) chr; #endif return true; @@ -966,6 +988,8 @@ bool NMEAGPS::parseTime(char chr) m_fix.valid.time = true; break; } + #else + (void) chr; #endif return true; @@ -988,6 +1012,8 @@ bool NMEAGPS::parseDDMMYY( char chr ) m_fix.valid.date = true; break; } + #else + (void) chr; #endif return true; @@ -1141,6 +1167,7 @@ bool NMEAGPS::parseFloat( uint16_t & val, char chr, uint8_t max_decimal ) static uint32_t divu3( uint32_t n ) { + // FIXME for all microcontrollers interesting #ifdef __AVR__ uint32_t q = (n >> 2) + (n >> 4); // q = n*0.0101 (approx). q = q + (q >> 4); // q = n*0.01010101. @@ -1251,7 +1278,7 @@ bool NMEAGPS::parseDDDMM done = true; - } else if (validateChars() && !isdigit(chr)) { + } else if (validateChars() && !( chr >= '0' && chr <= '9' )) { sentenceInvalid(); } else if (!decimal) { @@ -1340,6 +1367,8 @@ bool NMEAGPS::parseLat( char chr ) } } } + #else + (void) chr; #endif return true; @@ -1373,6 +1402,8 @@ bool NMEAGPS::parseNS( char chr ) sentenceInvalid(); } } + #else + (void) chr; #endif return true; @@ -1417,6 +1448,8 @@ bool NMEAGPS::parseLon( char chr ) } } } + #else + (void) chr; #endif return true; @@ -1451,6 +1484,8 @@ bool NMEAGPS::parseEW( char chr ) sentenceInvalid(); } } + #else + (void) chr; #endif return true; @@ -1472,6 +1507,8 @@ bool NMEAGPS::parseSpeed( char chr ) sentenceInvalid(); } } + #else + (void) chr; #endif return true; @@ -1495,6 +1532,8 @@ bool NMEAGPS::parseHeading( char chr ) sentenceInvalid(); } } + #else + (void) chr; #endif return true; @@ -1510,6 +1549,8 @@ bool NMEAGPS::parseAlt(char chr ) NMEAGPS_INVALIDATE( altitude ); if (parseFloat( m_fix.alt, chr, 2 )) m_fix.valid.altitude = (chrCount != 0); + #else + (void) chr; #endif return true; @@ -1525,6 +1566,8 @@ bool NMEAGPS::parseGeoidHeight( char chr ) NMEAGPS_INVALIDATE( geoidHeight ); if (parseFloat( m_fix.geoidHt, chr, 2 )) m_fix.valid.geoidHeight = (chrCount != 0); + #else + (void) chr; #endif return true; @@ -1541,6 +1584,8 @@ bool NMEAGPS::parseSatellites( char chr ) if (parseInt( m_fix.satellites, chr )) { m_fix.valid.satellites = true; } + #else + (void) chr; #endif return true; @@ -1556,6 +1601,8 @@ bool NMEAGPS::parseHDOP( char chr ) NMEAGPS_INVALIDATE( hdop ); if (parseFloat( m_fix.hdop, chr, 3 )) m_fix.valid.hdop = (chrCount != 0); + #else + (void) chr; #endif return true; @@ -1571,6 +1618,8 @@ bool NMEAGPS::parseVDOP( char chr ) NMEAGPS_INVALIDATE( vdop ); if (parseFloat( m_fix.vdop, chr, 3 )) m_fix.valid.vdop = (chrCount != 0); + #else + (void) chr; #endif return true; @@ -1586,6 +1635,8 @@ bool NMEAGPS::parsePDOP( char chr ) NMEAGPS_INVALIDATE( pdop ); if (parseFloat( m_fix.pdop, chr, 3 )) m_fix.valid.pdop = (chrCount != 0); + #else + (void) chr; #endif return true; @@ -1601,6 +1652,8 @@ bool NMEAGPS::parse_lat_err( char chr ) NMEAGPS_INVALIDATE( lat_err ); if (parseFloat( m_fix.lat_err_cm, chr, 2 )) m_fix.valid.lat_err = (chrCount != 0); + #else + (void) chr; #endif return true; @@ -1616,6 +1669,8 @@ bool NMEAGPS::parse_lon_err( char chr ) NMEAGPS_INVALIDATE( lon_err ); if (parseFloat( m_fix.lon_err_cm, chr, 2 )) m_fix.valid.lon_err = (chrCount != 0); + #else + (void) chr; #endif return true; @@ -1631,6 +1686,8 @@ bool NMEAGPS::parse_alt_err( char chr ) NMEAGPS_INVALIDATE( alt_err ); if (parseFloat( m_fix.alt_err_cm, chr, 2 )) m_fix.valid.alt_err = (chrCount != 0); + #else + (void) chr; #endif return true; @@ -1670,7 +1727,7 @@ const gps_fix NMEAGPS::read() //---------------------------------------------------------------- -void NMEAGPS::poll( Stream *device, nmea_msg_t msg ) +void NMEAGPS::poll( NEO_GPS_STREAM *device, nmea_msg_t msg ) { // Only the ublox documentation references talker ID "EI". // Other manufacturer's devices use "II" and "GP" talker IDs for the GPQ sentence. @@ -1745,13 +1802,13 @@ void NMEAGPS::poll( Stream *device, nmea_msg_t msg ) //---------------------------------------------------------------- -static void send_trailer( Stream *device, uint8_t crc ) +static void send_trailer( NEO_GPS_STREAM *device, uint8_t crc ) { - device->print('*'); + device->print( '*' ); char hexDigit = formatHex( crc>>4 ); device->print( hexDigit ); - + hexDigit = formatHex( crc ); device->print( hexDigit ); @@ -1762,12 +1819,12 @@ static void send_trailer( Stream *device, uint8_t crc ) //---------------------------------------------------------------- -void NMEAGPS::send( Stream *device, const char *msg ) +void NMEAGPS::send( NEO_GPS_STREAM *device, const char *msg ) { if (msg && *msg) { if (*msg == '$') msg++; - device->print('$'); + device->print( '$' ); uint8_t sent_trailer = 0; uint8_t crc = 0; while (*msg) { @@ -1786,13 +1843,13 @@ void NMEAGPS::send( Stream *device, const char *msg ) //---------------------------------------------------------------- -void NMEAGPS::send_P( Stream *device, const __FlashStringHelper *msg ) +void NMEAGPS::send_P( NEO_GPS_STREAM *device, const __FlashStringHelper *msg ) { if (msg) { const char *ptr = (const char *)msg; char chr = pgm_read_byte(ptr++); - device->print('$'); + device->print( '$' ); if (chr == '$') chr = pgm_read_byte(ptr++); uint8_t sent_trailer = 0; @@ -1812,3 +1869,6 @@ void NMEAGPS::send_P( Stream *device, const __FlashStringHelper *msg ) } } // send_P + +#pragma pop_macro( "LF" ) +#pragma pop_macro( "CR" ) diff --git a/src/NMEAGPS_cfg.h b/src/NMEAGPS_cfg.h index c20bdef..9fe8429 100644 --- a/src/NMEAGPS_cfg.h +++ b/src/NMEAGPS_cfg.h @@ -31,13 +31,13 @@ // 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_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 +#define NMEAGPS_PARSE_VTG +#define NMEAGPS_PARSE_ZDA //------------------------------------------------------ // Select which sentence is sent *last* by your GPS device @@ -206,8 +206,8 @@ // optionally, all the info for each satellite. // -//#define NMEAGPS_PARSE_SATELLITES -//#define NMEAGPS_PARSE_SATELLITE_INFO +#define NMEAGPS_PARSE_SATELLITES +#define NMEAGPS_PARSE_SATELLITE_INFO #ifdef NMEAGPS_PARSE_SATELLITES #define NMEAGPS_MAX_SATELLITES (20) @@ -335,4 +335,4 @@ #error You cannot enable both TIMESTAMP_FROM_INTERVAL and PPS in NMEAGPS_cfg.h! #endif -#endif \ No newline at end of file +#endif diff --git a/src/NMEAGPSprivate.h b/src/NMEAGPSprivate.h index f38b3a6..d3695e0 100644 --- a/src/NMEAGPSprivate.h +++ b/src/NMEAGPSprivate.h @@ -15,6 +15,9 @@ // You should have received a copy of the GNU General Public License // along with NeoGPS. If not, see . +// This pragma doesn't make much sense, but will make some IDEs happy. +#pragma once + protected: //....................................................................... // Table entry for NMEA sentence type string and its offset @@ -89,13 +92,13 @@ void lock() const { if (processing_style == PS_INTERRUPT) - noInterrupts(); + NEO_GPS_SYSTEM::lock(); } void unlock() const { if (processing_style == PS_INTERRUPT) - interrupts(); + NEO_GPS_SYSTEM::unlock(); } protected: diff --git a/src/NeoGPS_cfg.h b/src/NeoGPS_cfg.h index 5f8c8fd..8199bc8 100644 --- a/src/NeoGPS_cfg.h +++ b/src/NeoGPS_cfg.h @@ -89,7 +89,10 @@ * */ -#if (ARDUINO < 10606) | ((10700 <= ARDUINO) & (ARDUINO <= 10799)) | ((107000 <= ARDUINO) & (ARDUINO <= 107999)) +#if defined ARDUINO && \ + ((ARDUINO < 10606) || \ + ((10700 <= ARDUINO) && (ARDUINO <= 10799)) || \ + ((107000 <= ARDUINO) && (ARDUINO <= 107999))) #define CONST_CLASS_DATA static const diff --git a/src/NeoTime.h b/src/NeoTime.h index 846bb4d..fa33a0a 100644 --- a/src/NeoTime.h +++ b/src/NeoTime.h @@ -1,308 +1,4 @@ -#ifndef TIME_H -#define TIME_H +#pragma once -// Copyright (C) 2014-2017, SlashDevin -// -// This file is part of NeoGPS -// -// NeoGPS is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// NeoGPS is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with NeoGPS. If not, see . - -#include - -#include "NeoGPS_cfg.h" -#include "CosaCompat.h" - -namespace NeoGPS { - -//------------------------------------------------------ -// Enable/disable run-time modification of the epoch. -// If this is defined, epoch mutators are available. -// If this is not defined, the epoch is a hard-coded constant. -// Only epoch accessors are available. -//#define TIME_EPOCH_MODIFIABLE - -/** - * Number of seconds elapsed since January 1 of the Epoch Year, - * 00:00:00 +0000 (UTC). - */ -typedef uint32_t clock_t; - -const uint8_t SECONDS_PER_MINUTE = 60; -const uint8_t MINUTES_PER_HOUR = 60; -const uint16_t SECONDS_PER_HOUR = (uint16_t) SECONDS_PER_MINUTE * MINUTES_PER_HOUR; -const uint8_t HOURS_PER_DAY = 24; -const uint32_t SECONDS_PER_DAY = (uint32_t) SECONDS_PER_HOUR * HOURS_PER_DAY; -const uint8_t DAYS_PER_WEEK = 7; - -/** - * Common date/time structure - */ -struct time_t { - - enum weekday_t { - SUNDAY = 1, - MONDAY = 2, - TUESDAY = 3, - WEDNESDAY = 4, - THURSDAY = 5, - FRIDAY = 6, - SATURDAY = 7 - }; - - // NTP epoch year and weekday (Monday) - static const uint16_t NTP_EPOCH_YEAR = 1900; - static const uint8_t NTP_EPOCH_WEEKDAY = MONDAY; - - // POSIX epoch year and weekday (Thursday) - static const uint16_t POSIX_EPOCH_YEAR = 1970; - static const uint8_t POSIX_EPOCH_WEEKDAY = THURSDAY; - - // Y2K epoch year and weekday (Saturday) - static const uint16_t Y2K_EPOCH_YEAR = 2000; - static const uint8_t Y2K_EPOCH_WEEKDAY = SATURDAY; - - uint8_t seconds; //!< 00-59 - uint8_t minutes; //!< 00-59 - uint8_t hours; //!< 00-23 - uint8_t day; //!< 01-07 Day of Week - uint8_t date; //!< 01-31 Day of Month - uint8_t month; //!< 01-12 - uint8_t year; //!< 00-99 - - /** - * Constructor. - */ - time_t() {} - - /** - * Construct from seconds since the Epoch. - * @param[in] c clock. - */ - time_t(clock_t c); - - /** - * Initialize to January 1 of the Epoch Year, 00:00:00 - */ - void init(); - - /** - * Convert to seconds. - * @return seconds from epoch. - */ - operator clock_t() const; - - /** - * Offset by a number of seconds. - * @param[in] seconds to offset. - * @return *this - */ - void operator +=( clock_t offset ) - { *this = offset + operator clock_t(); } - - /** - * Set day member from current value. This is a relatively expensive - * operation, so the weekday is only calculated when requested. - */ - void set_day() - { - day = weekday_for(days()); - } - - /** - * Convert to days. - * @return days from January 1 of the epoch year. - */ - uint16_t days() const; - - /** - * Calculate day of the current year. - * @return days from January 1, which is day zero. - */ - uint16_t day_of_year() const; - - /** - * Calculate 4-digit year from internal 2-digit year member. - * @return 4-digit year. - */ - uint16_t full_year() const - { - return full_year(year); - } - - /** - * Calculate 4-digit year from a 2-digit year - * @param[in] year (4-digit). - * @return true if /year/ is a leap year. - */ - static uint16_t full_year( uint8_t year ) - { - uint16_t y = year; - - if (y < pivot_year()) - y += 100 * (epoch_year()/100 + 1); - else - y += 100 * (epoch_year()/100); - - return y; - } - - /** - * Determine whether the current year is a leap year. - * @returns true if the two-digit /year/ member is a leap year. - */ - bool is_leap() const - { - return is_leap(full_year()); - } - - /** - * Determine whether the 4-digit /year/ is a leap year. - * @param[in] year (4-digit). - * @return true if /year/ is a leap year. - */ - static bool is_leap(uint16_t year) - { - if (year % 4) return false; - uint16_t y = year % 400; - return (y == 0) || ((y != 100) && (y != 200) && (y != 300)); - } - - /** - * Calculate how many days are in the specified year. - * @param[in] year (4-digit). - * @return number of days. - */ - static uint16_t days_per(uint16_t year) - { - return (365 + is_leap(year)); - } - - /** - * Determine the day of the week for the specified day number - * @param[in] day number as counted from January 1 of the epoch year. - * @return weekday number 1..7, as for the /day/ member. - */ - static uint8_t weekday_for(uint16_t dayno) - { - return ((dayno+epoch_weekday()-1) % DAYS_PER_WEEK) + 1; - } - - /** - * Check that all members, EXCEPT FOR day, are set to a coherent date/time. - * @return true if valid date/time. - */ - bool is_valid() const - { - return - ((year <= 99) && - (1 <= month) && (month <= 12) && - ((1 <= date) && - ((date <= pgm_read_byte(&days_in[month])) || - ((month == 2) && is_leap() && (date == 29)))) && - (hours <= 23) && - (minutes <= 59) && - (seconds <= 59)); - } - - /** - * Set the epoch year for all time_t operations. Note that the pivot - * year defaults to the epoch_year % 100. Valid years will be in the - * range epoch_year..epoch_year+99. Selecting a different pivot year - * will slide this range to the right. - * @param[in] y epoch year to set. - * See also /full_year/. - */ - #ifdef TIME_EPOCH_MODIFIABLE - static void epoch_year(uint16_t y) - { - s_epoch_year = y; - epoch_offset( s_epoch_year % 100 ); - pivot_year( epoch_offset() ); - } - #endif - - /** - * Get the epoch year. - * @return year. - */ - static uint16_t epoch_year() - { - return (s_epoch_year); - } - - static uint8_t epoch_weekday() { return s_epoch_weekday; }; -#ifdef TIME_EPOCH_MODIFIABLE - static void epoch_weekday( uint8_t ew ) { s_epoch_weekday = ew; }; -#endif - - /** - * The pivot year determine the range of years WRT the epoch_year - * For example, an epoch year of 2000 and a pivot year of 80 will - * allow years in the range 1980 to 2079. Default 0 for Y2K_EPOCH. - */ - static uint8_t pivot_year() { return s_pivot_year; }; - #ifdef TIME_EPOCH_MODIFIABLE - static void pivot_year( uint8_t py ) { s_pivot_year = py; }; - #endif - - #ifdef TIME_EPOCH_MODIFIABLE - /** - * Use the current year for the epoch year. This will result in the - * best performance of conversions, but dates/times before January 1 - * of the epoch year cannot be represented. - */ - static void use_fastest_epoch(); - #endif - - /** - * Parse a character string and fill out members. - * @param[in] s PROGMEM character string with format "YYYY-MM-DD HH:MM:SS". - * @return success. - */ - bool parse(str_P s); - - static const uint8_t days_in[] PROGMEM; // month index is 1..12, PROGMEM - -protected: - static uint8_t epoch_offset() { return s_epoch_offset; }; - - #ifdef TIME_EPOCH_MODIFIABLE - static void epoch_offset( uint8_t eo ) { s_epoch_offset = eo; }; - - static uint16_t s_epoch_year; - static uint8_t s_pivot_year; - static uint8_t s_epoch_offset; - static uint8_t s_epoch_weekday; - #else - static const uint16_t s_epoch_year = Y2K_EPOCH_YEAR; - static const uint8_t s_pivot_year = s_epoch_year % 100; - static const uint8_t s_epoch_offset = s_pivot_year; - static const uint8_t s_epoch_weekday = Y2K_EPOCH_WEEKDAY; - #endif - -} NEOGPS_PACKED; - -}; // namespace NeoGPS - -class Print; - -/** - * Print the date/time to the given stream with the format "YYYY-MM-DD HH:MM:SS". - * @param[in] outs output stream. - * @param[in] t time structure. - * @return iostream. - */ -Print & operator <<( Print & outs, const NeoGPS::time_t &t ); - -#endif +#include "NeoTime.header.h" +#include "NeoTime.impl.h" diff --git a/src/NeoTime.header.h b/src/NeoTime.header.h new file mode 100644 index 0000000..911d45e --- /dev/null +++ b/src/NeoTime.header.h @@ -0,0 +1,304 @@ +#ifndef TIME_H +#define TIME_H + +// Copyright (C) 2014-2017, SlashDevin +// +// This file is part of NeoGPS +// +// NeoGPS is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// NeoGPS is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with NeoGPS. If not, see . + +#include "Platform.h" + +#include "NeoGPS_cfg.h" + +namespace NeoGPS { + +//------------------------------------------------------ +// Enable/disable run-time modification of the epoch. +// If this is defined, epoch mutators are available. +// If this is not defined, the epoch is a hard-coded constant. +// Only epoch accessors are available. +//#define TIME_EPOCH_MODIFIABLE + +/** + * Number of seconds elapsed since January 1 of the Epoch Year, + * 00:00:00 +0000 (UTC). + */ +typedef uint32_t clock_t; + +const uint8_t SECONDS_PER_MINUTE = 60; +const uint8_t MINUTES_PER_HOUR = 60; +const uint16_t SECONDS_PER_HOUR = (uint16_t) SECONDS_PER_MINUTE * MINUTES_PER_HOUR; +const uint8_t HOURS_PER_DAY = 24; +const uint32_t SECONDS_PER_DAY = (uint32_t) SECONDS_PER_HOUR * HOURS_PER_DAY; +const uint8_t DAYS_PER_WEEK = 7; + +/** + * Common date/time structure + */ +struct time_t { + + enum weekday_t { + SUNDAY = 1, + MONDAY = 2, + TUESDAY = 3, + WEDNESDAY = 4, + THURSDAY = 5, + FRIDAY = 6, + SATURDAY = 7 + }; + + // NTP epoch year and weekday (Monday) + static const uint16_t NTP_EPOCH_YEAR = 1900; + static const uint8_t NTP_EPOCH_WEEKDAY = MONDAY; + + // POSIX epoch year and weekday (Thursday) + static const uint16_t POSIX_EPOCH_YEAR = 1970; + static const uint8_t POSIX_EPOCH_WEEKDAY = THURSDAY; + + // Y2K epoch year and weekday (Saturday) + static const uint16_t Y2K_EPOCH_YEAR = 2000; + static const uint8_t Y2K_EPOCH_WEEKDAY = SATURDAY; + + uint8_t seconds; //!< 00-59 + uint8_t minutes; //!< 00-59 + uint8_t hours; //!< 00-23 + uint8_t day; //!< 01-07 Day of Week + uint8_t date; //!< 01-31 Day of Month + uint8_t month; //!< 01-12 + uint8_t year; //!< 00-99 + + /** + * Constructor. + */ + time_t() {} + + /** + * Construct from seconds since the Epoch. + * @param[in] c clock. + */ + time_t(clock_t c); + + /** + * Initialize to January 1 of the Epoch Year, 00:00:00 + */ + void init(); + + /** + * Convert to seconds. + * @return seconds from epoch. + */ + operator clock_t() const; + + /** + * Offset by a number of seconds. + * @param[in] offset in seconds. + */ + void operator +=( clock_t offset ) + { *this = offset + operator clock_t(); } + + /** + * Set day member from current value. This is a relatively expensive + * operation, so the weekday is only calculated when requested. + */ + void set_day() + { + day = weekday_for(days()); + } + + /** + * Convert to days. + * @return days from January 1 of the epoch year. + */ + uint16_t days() const; + + /** + * Calculate day of the current year. + * @return days from January 1, which is day zero. + */ + uint16_t day_of_year() const; + + /** + * Calculate 4-digit year from internal 2-digit year member. + * @return 4-digit year. + */ + uint16_t full_year() const + { + return full_year(year); + } + + /** + * Calculate 4-digit year from a 2-digit year + * @param[in] year (4-digit). + * @return true if /year/ is a leap year. + */ + static uint16_t full_year( uint8_t year ) + { + uint16_t y = year; + + if (y < pivot_year()) + y += 100 * (epoch_year()/100 + 1); + else + y += 100 * (epoch_year()/100); + + return y; + } + + /** + * Determine whether the current year is a leap year. + * @returns true if the two-digit /year/ member is a leap year. + */ + bool is_leap() const + { + return is_leap(full_year()); + } + + /** + * Determine whether the 4-digit /year/ is a leap year. + * @param[in] year (4-digit). + * @return true if /year/ is a leap year. + */ + static bool is_leap(uint16_t year) + { + if (year % 4) return false; + uint16_t y = year % 400; + return (y == 0) || ((y != 100) && (y != 200) && (y != 300)); + } + + /** + * Calculate how many days are in the specified year. + * @param[in] year (4-digit). + * @return number of days. + */ + static uint16_t days_per(uint16_t year) + { + return (365 + is_leap(year)); + } + + /** + * Determine the day of the week for the specified day number + * @param[in] dayno number as counted from January 1 of the epoch year. + * @return weekday number 1..7, as for the /day/ member. + */ + static uint8_t weekday_for(uint16_t dayno) + { + return ((dayno+epoch_weekday()-1) % DAYS_PER_WEEK) + 1; + } + + /** + * Check that all members, EXCEPT FOR day, are set to a coherent date/time. + * @return true if valid date/time. + */ + bool is_valid() const + { + return + ((year <= 99) && + (1 <= month) && (month <= 12) && + ((1 <= date) && + ((date <= pgm_read_byte(&days_in[month])) || + ((month == 2) && is_leap() && (date == 29)))) && + (hours <= 23) && + (minutes <= 59) && + (seconds <= 59)); + } + + /** + * Set the epoch year for all time_t operations. Note that the pivot + * year defaults to the epoch_year % 100. Valid years will be in the + * range epoch_year..epoch_year+99. Selecting a different pivot year + * will slide this range to the right. + * @param[in] y epoch year to set. + * See also /full_year/. + */ + #ifdef TIME_EPOCH_MODIFIABLE + static void epoch_year(uint16_t y) + { + s_epoch_year = y; + epoch_offset( s_epoch_year % 100 ); + pivot_year( epoch_offset() ); + } + #endif + + /** + * Get the epoch year. + * @return year. + */ + static uint16_t epoch_year() + { + return (s_epoch_year); + } + + static uint8_t epoch_weekday() { return s_epoch_weekday; }; +#ifdef TIME_EPOCH_MODIFIABLE + static void epoch_weekday( uint8_t ew ) { s_epoch_weekday = ew; }; +#endif + + /** + * The pivot year determine the range of years WRT the epoch_year + * For example, an epoch year of 2000 and a pivot year of 80 will + * allow years in the range 1980 to 2079. Default 0 for Y2K_EPOCH. + */ + static uint8_t pivot_year() { return s_pivot_year; }; + #ifdef TIME_EPOCH_MODIFIABLE + static void pivot_year( uint8_t py ) { s_pivot_year = py; }; + #endif + + #ifdef TIME_EPOCH_MODIFIABLE + /** + * Use the current year for the epoch year. This will result in the + * best performance of conversions, but dates/times before January 1 + * of the epoch year cannot be represented. + */ + static void use_fastest_epoch(); + #endif + + /** + * Parse a character string and fill out members. + * @param[in] s PROGMEM character string with format "YYYY-MM-DD HH:MM:SS". + * @return success. + */ + bool parse(str_P s); + + static const uint8_t days_in[] PROGMEM; // month index is 1..12, PROGMEM + +protected: + static uint8_t epoch_offset() { return s_epoch_offset; }; + + #ifdef TIME_EPOCH_MODIFIABLE + static void epoch_offset( uint8_t eo ) { s_epoch_offset = eo; }; + + static uint16_t s_epoch_year; + static uint8_t s_pivot_year; + static uint8_t s_epoch_offset; + static uint8_t s_epoch_weekday; + #else + static const uint16_t s_epoch_year = Y2K_EPOCH_YEAR; + static const uint8_t s_pivot_year = s_epoch_year % 100; + static const uint8_t s_epoch_offset = s_pivot_year; + static const uint8_t s_epoch_weekday = Y2K_EPOCH_WEEKDAY; + #endif + +} NEOGPS_PACKED; + +}; // namespace NeoGPS + +/** + * Print the date/time to the given stream with the format "YYYY-MM-DD HH:MM:SS". + * @param[in] outs output stream. + * @param[in] t time structure. + * @return iostream. + */ +NEO_GPS_PRINT & operator <<( NEO_GPS_PRINT & outs, const NeoGPS::time_t &t ); + +#endif diff --git a/src/NeoTime.cpp b/src/NeoTime.impl.h similarity index 74% rename from src/NeoTime.cpp rename to src/NeoTime.impl.h index 92adc8a..f428f85 100644 --- a/src/NeoTime.cpp +++ b/src/NeoTime.impl.h @@ -15,43 +15,48 @@ // You should have received a copy of the GNU General Public License // along with NeoGPS. If not, see . -#include "NeoTime.h" + +// Just to be sure. This file should only be included in NeoTime.h which +// protects against multiple includes already. +#pragma once + +#include "NeoTime.header.h" // For strtoul declaration #include -#include - -Print & operator<<( Print& outs, const NeoGPS::time_t& t ) +NEO_GPS_PRINT & operator<<( NEO_GPS_PRINT& outs, const NeoGPS::time_t& t ) { - outs.print( t.full_year( t.year ) ); - outs.write( '-' ); - if (t.month < 10) outs.write( '0' ); - outs.print( t.month ); - outs.write( '-' ); - if (t.date < 10) outs.write( '0' ); - outs.print( t.date ); - outs.write( ' ' ); - if (t.hours < 10) outs.write( '0' ); - outs.print( t.hours ); - outs.write( ':' ); - if (t.minutes < 10) outs.write( '0' ); - outs.print( t.minutes ); - outs.write( ':' ); - if (t.seconds < 10) outs.write( '0' ); - outs.print( t.seconds ); + outs << t.full_year( t.year ); + outs << '-'; + if (t.month < 10) outs << '0'; + outs << t.month; + outs << '-'; + if (t.date < 10) outs << '0'; + outs << t.date; + outs << ' '; + if (t.hours < 10) outs << '0'; + outs << t.hours; + outs << ':'; + if (t.minutes < 10) outs << '0'; + outs << t.minutes; + outs << ':'; + if (t.seconds < 10) outs << '0'; + outs << t.seconds; return outs; } -using NeoGPS::time_t; - -bool time_t::parse(str_P s) +bool NeoGPS::time_t::parse(str_P s) { - static size_t BUF_MAX = 32; - char buf[BUF_MAX]; - strcpy_P(buf, s); - char* sp = &buf[0]; + #ifdef AVR + static size_t BUF_MAX = 32; + char buf[BUF_MAX]; + strcpy_P(buf, s); + char* sp = &buf[0]; + #else + char* sp = (char *)&s[0]; + #endif uint16_t value = strtoul(sp, &sp, 10); if (*sp != '-') return false; @@ -82,17 +87,17 @@ bool time_t::parse(str_P s) } #ifdef TIME_EPOCH_MODIFIABLE - uint16_t time_t::s_epoch_year = Y2K_EPOCH_YEAR; - uint8_t time_t::s_epoch_offset = 0; - uint8_t time_t::s_epoch_weekday = Y2K_EPOCH_WEEKDAY; - uint8_t time_t::s_pivot_year = 0; + uint16_t NeoGPS::time_t::s_epoch_year = Y2K_EPOCH_YEAR; + uint8_t NeoGPS::time_t::s_epoch_offset = 0; + uint8_t NeoGPS::time_t::s_epoch_weekday = Y2K_EPOCH_WEEKDAY; + uint8_t NeoGPS::time_t::s_pivot_year = 0; #endif -const uint8_t time_t::days_in[] __PROGMEM = { +const uint8_t NeoGPS::time_t::days_in[] __PROGMEM = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; -time_t::time_t(clock_t c) +NeoGPS::time_t::time_t(clock_t c) { uint16_t dayno = c / SECONDS_PER_DAY; c -= dayno * (uint32_t) SECONDS_PER_DAY; @@ -133,7 +138,7 @@ time_t::time_t(clock_t c) seconds = c_ms - (minutes * SECONDS_PER_MINUTE); } -void time_t::init() +void NeoGPS::time_t::init() { seconds = hours = @@ -144,7 +149,7 @@ void time_t::init() day = epoch_weekday(); } -time_t::operator clock_t() const +NeoGPS::time_t::operator clock_t() const { clock_t c = days() * SECONDS_PER_DAY; if (hours < 18) @@ -157,7 +162,7 @@ time_t::operator clock_t() const return (c); } -uint16_t time_t::days() const +uint16_t NeoGPS::time_t::days() const { uint16_t day_count = day_of_year(); @@ -168,7 +173,7 @@ uint16_t time_t::days() const return (day_count); } -uint16_t time_t::day_of_year() const +uint16_t NeoGPS::time_t::day_of_year() const { uint16_t dayno = date - 1; bool leap_year = is_leap(); @@ -182,7 +187,7 @@ uint16_t time_t::day_of_year() const } #ifdef TIME_EPOCH_MODIFIABLE - void time_t::use_fastest_epoch() + void NeoGPS::time_t::use_fastest_epoch() { // Figure out when we were compiled and use the year for a really // fast epoch_year. Format "MMM DD YYYY" @@ -196,7 +201,7 @@ uint16_t time_t::day_of_year() const epoch_year ( Y2K_EPOCH_YEAR ); epoch_weekday ( Y2K_EPOCH_WEEKDAY ); - time_t this_year(0); + NeoGPS::time_t this_year(0); this_year.year = compile_year % 100; this_year.set_day(); uint8_t compile_weekday = this_year.day; @@ -205,4 +210,4 @@ uint16_t time_t::day_of_year() const epoch_weekday( compile_weekday ); pivot_year ( this_year.year ); } -#endif \ No newline at end of file +#endif diff --git a/src/Platform.h b/src/Platform.h new file mode 100644 index 0000000..d00a59c --- /dev/null +++ b/src/Platform.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +#ifdef ARDUINO + #include +#elif defined LINUX + #include +#else + #include + #include + #include +#endif + +#ifdef __AVR__ + #include + #include +#else + #define PGM_P const char * + #define pgm_read_byte(x) (*(x)) + #define __FlashStringHelper char + #define F(x) (x) +#endif + +typedef PGM_P str_P; + +#include + +#ifndef PI + #define PI 3.14159265358979323846 +#endif +#ifndef TWO_PI + #define TWO_PI PI * 2.0 +#endif + +#ifndef PROGMEM + #define PROGMEM +#endif + +#define __PROGMEM PROGMEM diff --git a/src/Streamers.h b/src/Streamers.h index f942931..26c27f3 100644 --- a/src/Streamers.h +++ b/src/Streamers.h @@ -1,50 +1,4 @@ -#ifndef STREAMERS_H -#define STREAMERS_H +#pragma once -// Copyright (C) 2014-2017, SlashDevin -// -// This file is part of NeoGPS -// -// NeoGPS is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// NeoGPS is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with NeoGPS. If not, see . - -#include - -extern Print & operator <<( Print & outs, const bool b ); -extern Print & operator <<( Print & outs, const char c ); -extern Print & operator <<( Print & outs, const uint16_t v ); -extern Print & operator <<( Print & outs, const uint32_t v ); -extern Print & operator <<( Print & outs, const int32_t v ); -extern Print & operator <<( Print & outs, const uint8_t v ); -extern Print & operator <<( Print & outs, const __FlashStringHelper *s ); - -class gps_fix; - -/** - * Print valid fix data to the given stream with the format - * "status,dateTime,lat,lon,heading,speed,altitude,satellites, - * hdop,vdop,pdop,lat_err,lon_err,alt_err" - * The "header" above contains the actual compile-time configuration. - * A comma-separated field will be empty if the data is NOT valid. - * @param[in] outs output stream. - * @param[in] fix gps_fix instance. - * @return iostream. - */ -extern Print & operator <<( Print &outs, const gps_fix &fix ); - -class NMEAGPS; - -extern void trace_header( Print & outs ); -extern void trace_all( Print & outs, const NMEAGPS &gps, const gps_fix &fix ); - -#endif \ No newline at end of file +#include "Streamers.header.h" +#include "Streamers.impl.h" diff --git a/src/CosaCompat.h b/src/Streamers.header.h similarity index 50% rename from src/CosaCompat.h rename to src/Streamers.header.h index ad9c080..e82690f 100644 --- a/src/CosaCompat.h +++ b/src/Streamers.header.h @@ -1,5 +1,4 @@ -#ifndef COSACOMPAT_H -#define COSACOMPAT_H +#pragma once // Copyright (C) 2014-2017, SlashDevin // @@ -18,17 +17,23 @@ // You should have received a copy of the GNU General Public License // along with NeoGPS. If not, see . -#ifdef __AVR__ +#include "Platform.h" - #include +#include -#else +/** + * Print valid fix data to the given stream with the format + * "status,dateTime,lat,lon,heading,speed,altitude,satellites, + * hdop,vdop,pdop,lat_err,lon_err,alt_err" + * The "header" above contains the actual compile-time configuration. + * A comma-separated field will be empty if the data is NOT valid. + * @param[in] outs output stream. + * @param[in] fix gps_fix instance. + * @return The outs object. + */ +NEO_GPS_PRINT & operator <<( NEO_GPS_PRINT &outs, const gps_fix &fix ); - #define PGM_P const char * +extern void trace_header( NEO_GPS_PRINT & outs ); +extern void trace_all( NEO_GPS_PRINT & outs, const NMEAGPS &gps, const gps_fix &fix ); -#endif - -typedef PGM_P str_P; -#define __PROGMEM PROGMEM - -#endif \ No newline at end of file +#include diff --git a/src/Streamers.cpp b/src/Streamers.impl.h similarity index 76% rename from src/Streamers.cpp rename to src/Streamers.impl.h index 1c2ab04..b33d54b 100644 --- a/src/Streamers.cpp +++ b/src/Streamers.impl.h @@ -15,26 +15,14 @@ // You should have received a copy of the GNU General Public License // along with NeoGPS. If not, see . -#include "Streamers.h" -#include "NMEAGPS.h" +// Just to be sure. This file should only be included in Streamers.h which +// protects against multiple includes already. +#pragma once -//#define USE_FLOAT +#include "Streamers.header.h" -Print& operator <<( Print &outs, const bool b ) - { outs.print( b ? 't' : 'f' ); return outs; } +#include "GPSfix.h" -Print& operator <<( Print &outs, const char c ) { outs.print(c); return outs; } - -Print& operator <<( Print &outs, const uint16_t v ) { outs.print(v); return outs; } - -Print& operator <<( Print &outs, const uint32_t v ) { outs.print(v); return outs; } - -Print& operator <<( Print &outs, const int32_t v ) { outs.print(v); return outs; } - -Print& operator <<( Print &outs, const uint8_t v ) { outs.print(v); return outs; } - -Print& operator <<( Print &outs, const __FlashStringHelper *s ) -{ outs.print(s); return outs; } //------------------------------------------ @@ -119,36 +107,35 @@ const char gps_fix_header[] __PROGMEM = #ifdef GPS_FIX_LOCATION_DMS - static void printDMS( Print & outs, const DMS_t & dms ) + static void printDMS( NEO_GPS_PRINT & outs, const DMS_t & dms ) { if (dms.degrees < 10) - outs.write( '0' ); - outs.print( dms.degrees ); - outs.write( ' ' ); + outs << '0'; + outs << dms.degrees << ' '; if (dms.minutes < 10) - outs.write( '0' ); - outs.print( dms.minutes ); - outs.print( F("\' ") ); + outs << '0'; + outs << dms.minutes; + outs << F("\' "); if (dms.seconds_whole < 10) - outs.write( '0' ); - outs.print( dms.seconds_whole ); - outs.write( '.' ); + outs << '0'; + outs << dms.seconds_whole; + outs << '.'; if (dms.seconds_frac < 100) - outs.write( '0' ); + outs << '0'; if (dms.seconds_frac < 10) - outs.write( '0' ); - outs.print( dms.seconds_frac ); - outs.print( F("\" ") ); + outs << '0'; + outs << dms.seconds_frac; + outs << F("\" "); } // printDMS #endif //............... -Print & operator <<( Print &outs, const gps_fix &fix ) +NEO_GPS_PRINT & operator <<( NEO_GPS_PRINT &outs, const gps_fix &fix ) { if (fix.valid.status) outs << (uint8_t) fix.status; @@ -187,9 +174,9 @@ Print & operator <<( Print &outs, const gps_fix &fix ) #ifdef USE_FLOAT #ifdef GPS_FIX_LOCATION if (fix.valid.location) { - outs.print( fix.latitude(), 6 ); + printFloat(outs, fix.latitude(), 6); outs << ','; - outs.print( fix.longitude(), 6 ); + printFloat(outs, fix.longitude(), 6); } else outs << ','; outs << ','; @@ -197,66 +184,66 @@ Print & operator <<( Print &outs, const gps_fix &fix ) #ifdef GPS_FIX_LOCATION_DMS if (fix.valid.location) { printDMS( outs, fix.latitudeDMS ); - outs.print( fix.latitudeDMS.NS() ); + outs << fix.latitudeDMS.NS(); outs.write( ' ' ); if (fix.longitudeDMS.degrees < 100) - outs.write( '0' ); + outs << '0'; printDMS( outs, fix.longitudeDMS ); - outs.print( fix.longitudeDMS.EW() ); + outs << fix.longitudeDMS.EW(); } outs << ','; #endif #ifdef GPS_FIX_HEADING if (fix.valid.heading) - outs.print( fix.heading(), 2 ); + printFloat( outs, fix.heading(), 2); outs << ','; #endif #ifdef GPS_FIX_SPEED if (fix.valid.speed) - outs.print( fix.speed(), 3 ); // knots + printFloat( outs, fix.speed(), 3); outs << ','; #endif #ifdef GPS_FIX_ALTITUDE if (fix.valid.altitude) - outs.print( fix.altitude(), 2 ); + printFloat( outs, fix.altitude(), 2); outs << ','; #endif #ifdef GPS_FIX_HDOP if (fix.valid.hdop) - outs.print( (fix.hdop * 0.001), 3 ); + printFloat( outs, (fix.hdop * 0.001), 3 ); outs << ','; #endif #ifdef GPS_FIX_VDOP if (fix.valid.vdop) - outs.print( (fix.vdop * 0.001), 3 ); + printFloat( outs, (fix.vdop * 0.001), 3 ); outs << ','; #endif #ifdef GPS_FIX_PDOP if (fix.valid.pdop) - outs.print( (fix.pdop * 0.001), 3 ); + printFloat( outs, (fix.pdop * 0.001), 3 ); outs << ','; #endif #ifdef GPS_FIX_LAT_ERR if (fix.valid.lat_err) - outs.print( fix.lat_err(), 2 ); + printFloat( outs, fix.lat_err(), 2 ); outs << ','; #endif #ifdef GPS_FIX_LON_ERR if (fix.valid.lon_err) - outs.print( fix.lon_err(), 2 ); + printFloat( outs, fix.lon_err(), 2 ); outs << ','; #endif #ifdef GPS_FIX_ALT_ERR if (fix.valid.alt_err) - outs.print( fix.alt_err(), 2 ); + printFloat( outs, fix.alt_err(), 2 ); outs << ','; #endif #ifdef GPS_FIX_GEOID_HEIGHT if (fix.valid.geoidHeight) - outs.print( fix.geoidHeight(), 2 ); + printFloat( outs, fix.geoidHeight(), 2 ); outs << ','; #endif @@ -274,12 +261,12 @@ Print & operator <<( Print &outs, const gps_fix &fix ) #ifdef GPS_FIX_LOCATION_DMS if (fix.valid.location) { printDMS( outs, fix.latitudeDMS ); - outs.print( fix.latitudeDMS.NS() ); - outs.write( ' ' ); + outs << fix.latitudeDMS.NS(); + outs << ' '; if (fix.longitudeDMS.degrees < 100) - outs.write( '0' ); + outs << '0'; printDMS( outs, fix.longitudeDMS ); - outs.print( fix.longitudeDMS.EW() ); + outs << fix.longitudeDMS.EW(); } outs << ','; #endif @@ -369,17 +356,17 @@ static const char NMEAGPS_header[] __PROGMEM = ""; -void trace_header( Print & outs ) +void trace_header( NEO_GPS_PRINT & outs ) { - outs.print( (const __FlashStringHelper *) &gps_fix_header[0] ); - outs.print( (const __FlashStringHelper *) &NMEAGPS_header[0] ); + outs << ((const __FlashStringHelper *) &gps_fix_header[0]); + outs << ((const __FlashStringHelper *) &NMEAGPS_header[0]); outs << '\n'; } //-------------------------- -void trace_all( Print & outs, const NMEAGPS &gps, const gps_fix &fix ) +void trace_all( NEO_GPS_PRINT & outs, const NMEAGPS &gps, const gps_fix &fix ) { outs << fix; diff --git a/src/platforms/Print.h b/src/platforms/Print.h new file mode 100644 index 0000000..b794ac2 --- /dev/null +++ b/src/platforms/Print.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#ifndef NEO_GPS_PRINT + #define NEO_GPS_PRINT NeoGPS::Print +#endif + +/** + * This file implements a non working dummy implemenation for Print + **/ +namespace NeoGPS { + + class Print { + }; + + Print & operator << ( Print & print, char ) { return print; } + Print & operator << ( Print & print, uint8_t ) { return print; } + Print & operator << ( Print & print, uint16_t ) { return print; } + Print & operator << ( Print & print, uint32_t ) { return print; } + Print & operator << ( Print & print, int32_t ) { return print; } + Print & operator << ( Print & print, const char * ) { return print; } + + #ifdef USE_FLOAT + void printFloat( Print &, float f, uint8_t decPlaces ) {} + #endif +} diff --git a/src/platforms/Stream.h b/src/platforms/Stream.h new file mode 100644 index 0000000..72d8bd4 --- /dev/null +++ b/src/platforms/Stream.h @@ -0,0 +1,18 @@ +#pragma once + +#ifndef NEO_GPS_STREAM + #define NEO_GPS_STREAM NeoGPS::Stream +#endif + +/** + * This file implements a non working dummy implementation for Stream. + **/ +namespace NeoGPS { + + class Stream { + public: + bool available() { return false; } + char read() { return '\0'; } + void print(char) {} + }; +} diff --git a/src/platforms/System.h b/src/platforms/System.h new file mode 100644 index 0000000..ae99866 --- /dev/null +++ b/src/platforms/System.h @@ -0,0 +1,17 @@ +#pragma once + +#ifndef NEO_GPS_SYSTEM + #define NEO_GPS_SYSTEM NeoGPS::System +#endif + +/** + * This file implements a non working dummy implementation for interrupts and noInterrupts. + **/ +namespace NeoGPS { + + class System { + public: + static void lock() {} + static void unlock() {} + }; +} diff --git a/src/platforms/arduino/platform.h b/src/platforms/arduino/platform.h new file mode 100644 index 0000000..049bf08 --- /dev/null +++ b/src/platforms/arduino/platform.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include +#include + +#define NEO_GPS_SYSTEM System + +#define NEO_GPS_STREAM Stream + +#define NEO_GPS_PRINT Print + +class System { +public: + static void lock() { noInterrupts(); } + static void unlock() { interrutps(); } +}; + +template +void printFloat( Print &outs, T f, uint8_t decimalPlaces) { outs.print(f, decimalPlaces); } + +Print& operator <<( Print &outs, const bool b ) { outs.print( b ? 't' : 'f' ); return outs; } + +Print& operator <<( Print &outs, const char c ) { outs.print(c); return outs; } + +Print& operator <<( Print &outs, const uint16_t v ) { outs.print(v); return outs; } + +Print& operator <<( Print &outs, const uint32_t v ) { outs.print(v); return outs; } + +Print& operator <<( Print &outs, const int32_t v ) { outs.print(v); return outs; } + +Print& operator <<( Print &outs, const uint8_t v ) { outs.print(v); return outs; } + +Print& operator <<( Print &outs, const __FlashStringHelper *s ) { outs.print(s); return outs; } + diff --git a/src/platforms/linux/platform.h b/src/platforms/linux/platform.h new file mode 100644 index 0000000..b3e94f4 --- /dev/null +++ b/src/platforms/linux/platform.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +#define NEO_GPS_SYSTEM System + +#define NEO_GPS_STREAM GpsStream + +#define NEO_GPS_PRINT std::iostream + +class System { +public: + static void lock() {} + static void unlock() {} +}; + + diff --git a/src/ublox/ubxGPS.h b/src/ublox/ubxGPS.h index f052034..829b388 100644 --- a/src/ublox/ubxGPS.h +++ b/src/ublox/ubxGPS.h @@ -1,332 +1,4 @@ -#ifndef _UBXGPS_H_ -#define _UBXGPS_H_ +#pragma once -// Copyright (C) 2014-2017, SlashDevin -// -// This file is part of NeoGPS -// -// NeoGPS is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// NeoGPS is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with NeoGPS. If not, see . - -#include "NMEAGPS_cfg.h" -// Disable the entire file if derived types are not allowed. -#ifdef NMEAGPS_DERIVED_TYPES - -#include "ublox/ubxNMEA.h" -#include "ublox/ubxmsg.h" -#include "GPSTime.h" -#include "ublox/ubx_cfg.h" - -#include -#include - -// NOTE: millis() is used for ACK timing - - -class ubloxGPS : public ubloxNMEA -{ - ubloxGPS & operator =( const ubloxGPS & ); - ubloxGPS( const ubloxGPS & ); - -public: - - // Constructor needs to know the device to handle the UBX binary protocol - ubloxGPS( Stream *device ) - : - storage( (ublox::msg_t *) NULL ), - reply( (ublox::msg_t *) NULL ), - reply_expected( false ), - ack_expected( false ), - m_device( device ) - {}; - - // ublox binary UBX message type. - enum ubx_msg_t { - UBX_MSG = PUBX_LAST_MSG+1 - }; - static const nmea_msg_t UBX_FIRST_MSG = (nmea_msg_t) UBX_MSG; - static const nmea_msg_t UBX_LAST_MSG = (nmea_msg_t) UBX_MSG; - - - //................................................................ - // Process one character of ublox message. The internal state - // machine tracks what part of the sentence has been received. As the - // tracks what part of the sentence has been received so far. As the - // sentence is received, members of the /fix/ structure are updated. - // @return DECODE_COMPLETED when a sentence has been completely received. - - decode_t decode( char c ); - - //................................................................ - // Received message header. Payload is only stored if /storage/ is - // overridden for that message type. This is the UBX-specific - // version of "nmeaMessage". - - ublox::msg_t & rx() { return m_rx_msg; } - - //................................................................ - - bool enable_msg( ublox::msg_class_t msg_class, ublox::msg_id_t msg_id ) - { - return send( ublox::cfg_msg_t( msg_class, msg_id, 1 ) ); - } - - bool disable_msg( ublox::msg_class_t msg_class, ublox::msg_id_t msg_id ) - { - return send( ublox::cfg_msg_t( msg_class, msg_id, 0 ) ); - } - - //................................................................ - // Send a message (non-blocking). - // Although multiple /send_request/s can be issued, - // all replies will be handled identically. - - bool send_request( const ublox::msg_t & msg ) - { - write( msg ); - return true; - } - - bool send_request_P( const ublox::msg_t & msg ) - { - write_P( msg ); - return true; - } - - //................................................................ - // Send a message and wait for a reply (blocking). - // No event will be generated for the reply. - // If /msg/ is a UBX_CFG, this will wait for a UBX_CFG_ACK/NAK - // and return true if ACKed. - // If /msg/ is a poll, this will wait for the reply. - // If /msg/ is neither, this will return true immediately. - // If /msg/ is both, this will wait for both the reply and the ACK/NAK. - // If /storage_for/ is implemented, those messages will continue - // to be saved while waiting for this reply. - - bool send( const ublox::msg_t & msg, ublox::msg_t *reply_msg = (ublox::msg_t *) NULL ); - bool send_P( const ublox::msg_t & msg, ublox::msg_t *reply_msg = (ublox::msg_t *) NULL ); - using NMEAGPS::send_P; - - //................................................................ - // Ask for a specific message (non-blocking). - // The message will receive be received later. - // See also /send_request/. - - bool poll_request( const ublox::msg_t & msg ) - { - ublox::msg_t poll_msg( msg.msg_class, msg.msg_id, 0 ); - return send_request( poll_msg ); - } - - bool poll_request_P( const ublox::msg_t & msg ) - { - ublox::msg_t poll_msg( (ublox::msg_class_t) pgm_read_byte( &msg.msg_class ), - (ublox::msg_id_t) pgm_read_byte( &msg.msg_id ), 0 ); - return send_request( poll_msg ); - } - - //................................................................ - // Ask for a specific message (blocking). - // See also /send/. - bool poll( ublox::msg_t & msg ) - { - ublox::msg_t poll_msg( msg.msg_class, msg.msg_id, 0 ); - return send( poll_msg, &msg ); - } - - bool poll_P( const ublox::msg_t & msg, ublox::msg_t *reply_msg = (ublox::msg_t *) NULL ) - { - ublox::msg_t poll_msg( (ublox::msg_class_t) pgm_read_byte( &msg.msg_class ), - (ublox::msg_id_t) pgm_read_byte( &msg.msg_id ), 0 ); - return send( poll_msg, reply_msg ); - } - - //................................................................ - // Return the Stream that was passed into the constructor. - - Stream *Device() const { return (Stream *)m_device; }; - -protected: - - /* - * Some UBX messages can be larger than 256 bytes, so - * hide the 8-bit NMEAGPS::chrCount with this 16-bit version. - */ - uint16_t chrCount; - - bool parseField( char chr ); - - enum ubxState_t { - UBX_IDLE = NMEA_IDLE, - UBX_SYNC2 = NMEA_LAST_STATE+1, - UBX_HEAD, - UBX_RECEIVING_DATA, - UBX_CRC_A, - UBX_CRC_B - }; - static const ubxState_t UBX_FIRST_STATE = UBX_SYNC2; - static const ubxState_t UBX_LAST_STATE = UBX_CRC_B; - - inline void write - ( uint8_t c, uint8_t & crc_a, uint8_t & crc_b ) const - { - m_device->print( (char) c ); - crc_a += c; - crc_b += crc_a; - }; - void write( const ublox::msg_t & msg ); - void write_P( const ublox::msg_t & msg ); - - //................................................................ - // When the processing style is polling (not interrupt), this - // should be called frequently by any internal methods that block - // to make sure received chars continue to be processed. - - virtual void run() - { - if (processing_style == PS_POLLING) - while (Device()->available()) - handle( Device()->read() ); - // else - // handled by interrupts - } - - void wait_for_idle(); - bool wait_for_ack(); - // NOTE: /run/ is called from these blocking functions - - - bool waiting() const - { - return (ack_expected && (!ack_received && !nak_received)) || - (reply_expected && !reply_received); - } - - bool receiving() const - { - return (rxState != (rxState_t)UBX_IDLE) || (m_device && m_device->available()); - } - - // Override this if the contents of a particular message need to be saved. - // This may execute in an interrupt context, so be quick! - // NOTE: the ublox::msg_t.length will get stepped on, so you may need to - // set it every time if you are using a union for your storage. - - virtual ublox::msg_t *storage_for( const ublox::msg_t & rx_msg ) - { return (ublox::msg_t *) NULL; } - - virtual bool intervalCompleted() const - { - return ((nmeaMessage == (nmea_msg_t) UBX_MSG) && - (m_rx_msg.msg_class == UBX_LAST_MSG_CLASS_IN_INTERVAL) && - (m_rx_msg.msg_id == UBX_LAST_MSG_ID_IN_INTERVAL)) - || - NMEAGPS::intervalCompleted(); - } - -private: - ublox::msg_t *storage; // cached ptr to hold a received msg. - - // Storage for a specific received message. - // Used internally by send & poll variants. - // Checked and used before /storage_for/ is called. - - ublox::msg_t *reply; - - struct { - bool reply_expected NEOGPS_BF(1); - bool reply_received NEOGPS_BF(1); - bool ack_expected NEOGPS_BF(1); - bool ack_received NEOGPS_BF(1); - bool nak_received NEOGPS_BF(1); - bool ack_same_as_sent NEOGPS_BF(1); - } NEOGPS_PACKED; - struct ublox::msg_hdr_t sent; - - struct rx_msg_t : ublox::msg_t - { - uint8_t crc_a; // accumulated as packet received - uint8_t crc_b; // accumulated as packet received - - rx_msg_t() - { - init(); - } - - void init() - { - msg_class = ublox::UBX_UNK; - msg_id = ublox::UBX_ID_UNK; - length = 0; - crc_a = 0; - crc_b = 0; - } - - } NEOGPS_PACKED; - - rx_msg_t m_rx_msg; - - void rxBegin(); - bool rxEnd(); - - static const uint8_t SYNC_1 = 0xB5; - static const uint8_t SYNC_2 = 0x62; - - Stream *m_device; - - bool parseNavStatus ( uint8_t chr ); - bool parseNavDOP ( uint8_t chr ); - bool parseNavPosLLH ( uint8_t chr ); - bool parseNavVelNED ( uint8_t chr ); - bool parseNavTimeGPS( uint8_t chr ); - bool parseNavTimeUTC( uint8_t chr ); - bool parseNavSVInfo ( uint8_t chr ); - - bool parseHnrPvt( uint8_t chr ); - - bool parseFix( uint8_t c ); - - bool parseTOW( uint8_t chr ) - { - #if defined(GPS_FIX_TIME) & defined(GPS_FIX_DATE) - if (chrCount == 0) { - m_fix.valid.date = - m_fix.valid.time = false; - } - - ((uint8_t *) &m_fix.dateTime)[ chrCount ] = chr; - - if (chrCount == 3) { - uint32_t tow = *((uint32_t *) &m_fix.dateTime); - //trace << PSTR("@ ") << tow; - - uint16_t ms; - if (GPSTime::from_TOWms( tow, m_fix.dateTime, ms )) { - m_fix.dateTime_cs = ms / 10; - m_fix.valid.time = true; - m_fix.valid.date = true; - } else - m_fix.dateTime.init(); - //trace << PSTR(".") << m_fix.dateTime_cs; - } - #endif - - return true; - } - -} NEOGPS_PACKED; - -#endif // NMEAGPS_DERIVED_TYPES enabled - -#endif +#include "ubxGPS.header.h" +#include "ubxGPS.impl.h" diff --git a/src/ublox/ubxGPS.header.h b/src/ublox/ubxGPS.header.h new file mode 100644 index 0000000..f052034 --- /dev/null +++ b/src/ublox/ubxGPS.header.h @@ -0,0 +1,332 @@ +#ifndef _UBXGPS_H_ +#define _UBXGPS_H_ + +// Copyright (C) 2014-2017, SlashDevin +// +// This file is part of NeoGPS +// +// NeoGPS is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// NeoGPS is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with NeoGPS. If not, see . + +#include "NMEAGPS_cfg.h" +// Disable the entire file if derived types are not allowed. +#ifdef NMEAGPS_DERIVED_TYPES + +#include "ublox/ubxNMEA.h" +#include "ublox/ubxmsg.h" +#include "GPSTime.h" +#include "ublox/ubx_cfg.h" + +#include +#include + +// NOTE: millis() is used for ACK timing + + +class ubloxGPS : public ubloxNMEA +{ + ubloxGPS & operator =( const ubloxGPS & ); + ubloxGPS( const ubloxGPS & ); + +public: + + // Constructor needs to know the device to handle the UBX binary protocol + ubloxGPS( Stream *device ) + : + storage( (ublox::msg_t *) NULL ), + reply( (ublox::msg_t *) NULL ), + reply_expected( false ), + ack_expected( false ), + m_device( device ) + {}; + + // ublox binary UBX message type. + enum ubx_msg_t { + UBX_MSG = PUBX_LAST_MSG+1 + }; + static const nmea_msg_t UBX_FIRST_MSG = (nmea_msg_t) UBX_MSG; + static const nmea_msg_t UBX_LAST_MSG = (nmea_msg_t) UBX_MSG; + + + //................................................................ + // Process one character of ublox message. The internal state + // machine tracks what part of the sentence has been received. As the + // tracks what part of the sentence has been received so far. As the + // sentence is received, members of the /fix/ structure are updated. + // @return DECODE_COMPLETED when a sentence has been completely received. + + decode_t decode( char c ); + + //................................................................ + // Received message header. Payload is only stored if /storage/ is + // overridden for that message type. This is the UBX-specific + // version of "nmeaMessage". + + ublox::msg_t & rx() { return m_rx_msg; } + + //................................................................ + + bool enable_msg( ublox::msg_class_t msg_class, ublox::msg_id_t msg_id ) + { + return send( ublox::cfg_msg_t( msg_class, msg_id, 1 ) ); + } + + bool disable_msg( ublox::msg_class_t msg_class, ublox::msg_id_t msg_id ) + { + return send( ublox::cfg_msg_t( msg_class, msg_id, 0 ) ); + } + + //................................................................ + // Send a message (non-blocking). + // Although multiple /send_request/s can be issued, + // all replies will be handled identically. + + bool send_request( const ublox::msg_t & msg ) + { + write( msg ); + return true; + } + + bool send_request_P( const ublox::msg_t & msg ) + { + write_P( msg ); + return true; + } + + //................................................................ + // Send a message and wait for a reply (blocking). + // No event will be generated for the reply. + // If /msg/ is a UBX_CFG, this will wait for a UBX_CFG_ACK/NAK + // and return true if ACKed. + // If /msg/ is a poll, this will wait for the reply. + // If /msg/ is neither, this will return true immediately. + // If /msg/ is both, this will wait for both the reply and the ACK/NAK. + // If /storage_for/ is implemented, those messages will continue + // to be saved while waiting for this reply. + + bool send( const ublox::msg_t & msg, ublox::msg_t *reply_msg = (ublox::msg_t *) NULL ); + bool send_P( const ublox::msg_t & msg, ublox::msg_t *reply_msg = (ublox::msg_t *) NULL ); + using NMEAGPS::send_P; + + //................................................................ + // Ask for a specific message (non-blocking). + // The message will receive be received later. + // See also /send_request/. + + bool poll_request( const ublox::msg_t & msg ) + { + ublox::msg_t poll_msg( msg.msg_class, msg.msg_id, 0 ); + return send_request( poll_msg ); + } + + bool poll_request_P( const ublox::msg_t & msg ) + { + ublox::msg_t poll_msg( (ublox::msg_class_t) pgm_read_byte( &msg.msg_class ), + (ublox::msg_id_t) pgm_read_byte( &msg.msg_id ), 0 ); + return send_request( poll_msg ); + } + + //................................................................ + // Ask for a specific message (blocking). + // See also /send/. + bool poll( ublox::msg_t & msg ) + { + ublox::msg_t poll_msg( msg.msg_class, msg.msg_id, 0 ); + return send( poll_msg, &msg ); + } + + bool poll_P( const ublox::msg_t & msg, ublox::msg_t *reply_msg = (ublox::msg_t *) NULL ) + { + ublox::msg_t poll_msg( (ublox::msg_class_t) pgm_read_byte( &msg.msg_class ), + (ublox::msg_id_t) pgm_read_byte( &msg.msg_id ), 0 ); + return send( poll_msg, reply_msg ); + } + + //................................................................ + // Return the Stream that was passed into the constructor. + + Stream *Device() const { return (Stream *)m_device; }; + +protected: + + /* + * Some UBX messages can be larger than 256 bytes, so + * hide the 8-bit NMEAGPS::chrCount with this 16-bit version. + */ + uint16_t chrCount; + + bool parseField( char chr ); + + enum ubxState_t { + UBX_IDLE = NMEA_IDLE, + UBX_SYNC2 = NMEA_LAST_STATE+1, + UBX_HEAD, + UBX_RECEIVING_DATA, + UBX_CRC_A, + UBX_CRC_B + }; + static const ubxState_t UBX_FIRST_STATE = UBX_SYNC2; + static const ubxState_t UBX_LAST_STATE = UBX_CRC_B; + + inline void write + ( uint8_t c, uint8_t & crc_a, uint8_t & crc_b ) const + { + m_device->print( (char) c ); + crc_a += c; + crc_b += crc_a; + }; + void write( const ublox::msg_t & msg ); + void write_P( const ublox::msg_t & msg ); + + //................................................................ + // When the processing style is polling (not interrupt), this + // should be called frequently by any internal methods that block + // to make sure received chars continue to be processed. + + virtual void run() + { + if (processing_style == PS_POLLING) + while (Device()->available()) + handle( Device()->read() ); + // else + // handled by interrupts + } + + void wait_for_idle(); + bool wait_for_ack(); + // NOTE: /run/ is called from these blocking functions + + + bool waiting() const + { + return (ack_expected && (!ack_received && !nak_received)) || + (reply_expected && !reply_received); + } + + bool receiving() const + { + return (rxState != (rxState_t)UBX_IDLE) || (m_device && m_device->available()); + } + + // Override this if the contents of a particular message need to be saved. + // This may execute in an interrupt context, so be quick! + // NOTE: the ublox::msg_t.length will get stepped on, so you may need to + // set it every time if you are using a union for your storage. + + virtual ublox::msg_t *storage_for( const ublox::msg_t & rx_msg ) + { return (ublox::msg_t *) NULL; } + + virtual bool intervalCompleted() const + { + return ((nmeaMessage == (nmea_msg_t) UBX_MSG) && + (m_rx_msg.msg_class == UBX_LAST_MSG_CLASS_IN_INTERVAL) && + (m_rx_msg.msg_id == UBX_LAST_MSG_ID_IN_INTERVAL)) + || + NMEAGPS::intervalCompleted(); + } + +private: + ublox::msg_t *storage; // cached ptr to hold a received msg. + + // Storage for a specific received message. + // Used internally by send & poll variants. + // Checked and used before /storage_for/ is called. + + ublox::msg_t *reply; + + struct { + bool reply_expected NEOGPS_BF(1); + bool reply_received NEOGPS_BF(1); + bool ack_expected NEOGPS_BF(1); + bool ack_received NEOGPS_BF(1); + bool nak_received NEOGPS_BF(1); + bool ack_same_as_sent NEOGPS_BF(1); + } NEOGPS_PACKED; + struct ublox::msg_hdr_t sent; + + struct rx_msg_t : ublox::msg_t + { + uint8_t crc_a; // accumulated as packet received + uint8_t crc_b; // accumulated as packet received + + rx_msg_t() + { + init(); + } + + void init() + { + msg_class = ublox::UBX_UNK; + msg_id = ublox::UBX_ID_UNK; + length = 0; + crc_a = 0; + crc_b = 0; + } + + } NEOGPS_PACKED; + + rx_msg_t m_rx_msg; + + void rxBegin(); + bool rxEnd(); + + static const uint8_t SYNC_1 = 0xB5; + static const uint8_t SYNC_2 = 0x62; + + Stream *m_device; + + bool parseNavStatus ( uint8_t chr ); + bool parseNavDOP ( uint8_t chr ); + bool parseNavPosLLH ( uint8_t chr ); + bool parseNavVelNED ( uint8_t chr ); + bool parseNavTimeGPS( uint8_t chr ); + bool parseNavTimeUTC( uint8_t chr ); + bool parseNavSVInfo ( uint8_t chr ); + + bool parseHnrPvt( uint8_t chr ); + + bool parseFix( uint8_t c ); + + bool parseTOW( uint8_t chr ) + { + #if defined(GPS_FIX_TIME) & defined(GPS_FIX_DATE) + if (chrCount == 0) { + m_fix.valid.date = + m_fix.valid.time = false; + } + + ((uint8_t *) &m_fix.dateTime)[ chrCount ] = chr; + + if (chrCount == 3) { + uint32_t tow = *((uint32_t *) &m_fix.dateTime); + //trace << PSTR("@ ") << tow; + + uint16_t ms; + if (GPSTime::from_TOWms( tow, m_fix.dateTime, ms )) { + m_fix.dateTime_cs = ms / 10; + m_fix.valid.time = true; + m_fix.valid.date = true; + } else + m_fix.dateTime.init(); + //trace << PSTR(".") << m_fix.dateTime_cs; + } + #endif + + return true; + } + +} NEOGPS_PACKED; + +#endif // NMEAGPS_DERIVED_TYPES enabled + +#endif diff --git a/src/ublox/ubxGPS.cpp b/src/ublox/ubxGPS.impl.h similarity index 99% rename from src/ublox/ubxGPS.cpp rename to src/ublox/ubxGPS.impl.h index cb4bb7d..8a7e51e 100644 --- a/src/ublox/ubxGPS.cpp +++ b/src/ublox/ubxGPS.impl.h @@ -15,11 +15,15 @@ // You should have received a copy of the GNU General Public License // along with NeoGPS. If not, see . +// Just to be sure. This file should only be included in ubxGPS.h which +// protects against multiple includes already. +#pragma once + #include "NMEAGPS_cfg.h" // Disable the entire file if derived types are not allowed. #ifdef NMEAGPS_DERIVED_TYPES -#include "ublox/ubxGPS.h" +#include "ubxGPS.header.h" // Check configurations @@ -37,8 +41,6 @@ #endif -using namespace ublox; - //---------------------------------- void ubloxGPS::rxBegin() diff --git a/src/ublox/ubxNMEA.h b/src/ublox/ubxNMEA.h index 5ce707e..b436993 100644 --- a/src/ublox/ubxNMEA.h +++ b/src/ublox/ubxNMEA.h @@ -1,110 +1,4 @@ -#ifndef _UBXNMEA_H_ -#define _UBXNMEA_H_ +#pragma once -// Copyright (C) 2014-2017, SlashDevin -// -// This file is part of NeoGPS -// -// NeoGPS is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// NeoGPS is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with NeoGPS. If not, see . - -#include "NMEAGPS_cfg.h" - -// Disable the entire file if derived types are not allowed. -#ifdef NMEAGPS_DERIVED_TYPES - -#include "NMEAGPS.h" - -//------------------------------------------------------------ -// Enable/disable the parsing of specific proprietary NMEA sentences. -// -// Configuring out a sentence prevents its fields from being parsed. -// However, the sentence type may still be recognized by /decode/ and -// stored in member /nmeaMessage/. No valid flags would be available. - -//#define NMEAGPS_PARSE_PUBX_00 -//#define NMEAGPS_PARSE_PUBX_04 - -// Ublox proprietary messages do not have a message type. These -// messages start with "$PUBX," which ends with the manufacturer ID. The -// message type is actually specified by the first numeric field. In order -// to parse these messages, /parse_mfr_ID/ must be overridden to set the -// /nmeaMessage/ to PUBX_00 during /parseCommand/. When the first numeric -// field is completed by /parseField/, it may change /nmeamessage/ to one -// of the other PUBX message types. - -#if (defined(NMEAGPS_PARSE_PUBX_00) | defined(NMEAGPS_PARSE_PUBX_04)) - - #if !defined(NMEAGPS_PARSE_PROPRIETARY) - #error NMEAGPS_PARSE_PROPRIETARY must be defined in NMEAGPS_cfg.h in order to parse PUBX messages! - #endif - - #if !defined(NMEAGPS_PARSE_MFR_ID) - #error NMEAGPS_PARSE_MFR_ID must be defined in NMEAGPS_cfg.h in order to parse PUBX messages! - #endif -#endif - -//============================================================= -// NMEA 0183 Parser for ublox Neo-6 GPS Modules. -// -// @section Limitations -// Very limited support for ublox proprietary NMEA messages. -// Only NMEA messages of types PUBX,00 and PUBX,04 are parsed. -// - -class ubloxNMEA : public NMEAGPS -{ - ubloxNMEA( const ubloxNMEA & ); - -public: - - ubloxNMEA() {}; - - /** ublox proprietary NMEA message types. */ - enum pubx_msg_t { - PUBX_00 = NMEA_LAST_MSG+1, - #if defined(NMEAGPS_PARSE_PUBX_04) | defined(NMEAGPS_RECOGNIZE_ALL) - PUBX_04, - #endif - PUBX_END - }; - static const nmea_msg_t PUBX_FIRST_MSG = (nmea_msg_t) PUBX_00; - static const nmea_msg_t PUBX_LAST_MSG = (nmea_msg_t) (PUBX_END-1); - -protected: - bool parseMfrID( char chr ) - { bool ok; - switch (chrCount) { - case 1: ok = (chr == 'U'); break; - case 2: ok = (chr == 'B'); break; - default: if (chr == 'X') { - ok = true; - nmeaMessage = (nmea_msg_t) PUBX_00; - } else - ok = false; - break; - } - return ok; - }; - - bool parsePUBX_00( char chr ); - bool parsePUBX_04( char chr ); - - bool parseField( char chr ); - - bool parseFix( char chr ); -} NEOGPS_PACKED; - -#endif // NMEAGPS_DERIVED_TYPES enabled - -#endif +#include "ubxNMEA.header.h" +#include "ubxNMEA.impl.h" diff --git a/src/ublox/ubxNMEA.header.h b/src/ublox/ubxNMEA.header.h new file mode 100644 index 0000000..5ce707e --- /dev/null +++ b/src/ublox/ubxNMEA.header.h @@ -0,0 +1,110 @@ +#ifndef _UBXNMEA_H_ +#define _UBXNMEA_H_ + +// Copyright (C) 2014-2017, SlashDevin +// +// This file is part of NeoGPS +// +// NeoGPS is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// NeoGPS is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with NeoGPS. If not, see . + +#include "NMEAGPS_cfg.h" + +// Disable the entire file if derived types are not allowed. +#ifdef NMEAGPS_DERIVED_TYPES + +#include "NMEAGPS.h" + +//------------------------------------------------------------ +// Enable/disable the parsing of specific proprietary NMEA sentences. +// +// Configuring out a sentence prevents its fields from being parsed. +// However, the sentence type may still be recognized by /decode/ and +// stored in member /nmeaMessage/. No valid flags would be available. + +//#define NMEAGPS_PARSE_PUBX_00 +//#define NMEAGPS_PARSE_PUBX_04 + +// Ublox proprietary messages do not have a message type. These +// messages start with "$PUBX," which ends with the manufacturer ID. The +// message type is actually specified by the first numeric field. In order +// to parse these messages, /parse_mfr_ID/ must be overridden to set the +// /nmeaMessage/ to PUBX_00 during /parseCommand/. When the first numeric +// field is completed by /parseField/, it may change /nmeamessage/ to one +// of the other PUBX message types. + +#if (defined(NMEAGPS_PARSE_PUBX_00) | defined(NMEAGPS_PARSE_PUBX_04)) + + #if !defined(NMEAGPS_PARSE_PROPRIETARY) + #error NMEAGPS_PARSE_PROPRIETARY must be defined in NMEAGPS_cfg.h in order to parse PUBX messages! + #endif + + #if !defined(NMEAGPS_PARSE_MFR_ID) + #error NMEAGPS_PARSE_MFR_ID must be defined in NMEAGPS_cfg.h in order to parse PUBX messages! + #endif +#endif + +//============================================================= +// NMEA 0183 Parser for ublox Neo-6 GPS Modules. +// +// @section Limitations +// Very limited support for ublox proprietary NMEA messages. +// Only NMEA messages of types PUBX,00 and PUBX,04 are parsed. +// + +class ubloxNMEA : public NMEAGPS +{ + ubloxNMEA( const ubloxNMEA & ); + +public: + + ubloxNMEA() {}; + + /** ublox proprietary NMEA message types. */ + enum pubx_msg_t { + PUBX_00 = NMEA_LAST_MSG+1, + #if defined(NMEAGPS_PARSE_PUBX_04) | defined(NMEAGPS_RECOGNIZE_ALL) + PUBX_04, + #endif + PUBX_END + }; + static const nmea_msg_t PUBX_FIRST_MSG = (nmea_msg_t) PUBX_00; + static const nmea_msg_t PUBX_LAST_MSG = (nmea_msg_t) (PUBX_END-1); + +protected: + bool parseMfrID( char chr ) + { bool ok; + switch (chrCount) { + case 1: ok = (chr == 'U'); break; + case 2: ok = (chr == 'B'); break; + default: if (chr == 'X') { + ok = true; + nmeaMessage = (nmea_msg_t) PUBX_00; + } else + ok = false; + break; + } + return ok; + }; + + bool parsePUBX_00( char chr ); + bool parsePUBX_04( char chr ); + + bool parseField( char chr ); + + bool parseFix( char chr ); +} NEOGPS_PACKED; + +#endif // NMEAGPS_DERIVED_TYPES enabled + +#endif diff --git a/src/ublox/ubxNMEA.cpp b/src/ublox/ubxNMEA.impl.h similarity index 95% rename from src/ublox/ubxNMEA.cpp rename to src/ublox/ubxNMEA.impl.h index 4858a3c..46ded86 100644 --- a/src/ublox/ubxNMEA.cpp +++ b/src/ublox/ubxNMEA.impl.h @@ -15,7 +15,11 @@ // You should have received a copy of the GNU General Public License // along with NeoGPS. If not, see . -#include "ublox/ubxNMEA.h" +// Just to be sure. This file should only be included in ubxNMEA.h which +// protects against multiple includes already. +#pragma once + +#include "ubxNMEA.header.h" // Disable the entire file if derived types are not allowed. #ifdef NMEAGPS_DERIVED_TYPES @@ -144,4 +148,4 @@ bool ubloxNMEA::parseFix( char chr ) return true; } -#endif \ No newline at end of file +#endif diff --git a/src/ublox/ubxmsg.h b/src/ublox/ubxmsg.h index 57cda43..36d964d 100644 --- a/src/ublox/ubxmsg.h +++ b/src/ublox/ubxmsg.h @@ -1,589 +1,4 @@ -#ifndef UBXMSG_H -#define UBXMSG_H +#pragma once -// Copyright (C) 2014-2017, SlashDevin -// -// This file is part of NeoGPS -// -// NeoGPS is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// NeoGPS is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with NeoGPS. If not, see . - -#include "NMEAGPS_cfg.h" - -// Disable the entire file if derived types are not allowed. -#ifdef NMEAGPS_DERIVED_TYPES - -#include "NMEAGPS.h" -class ubloxGPS; - -namespace ublox { - - enum msg_class_t - { UBX_NAV = 0x01, // Navigation results - UBX_RXM = 0x02, // Receiver Manager messages - UBX_INF = 0x04, // Informational messages - UBX_ACK = 0x05, // ACK/NAK replies to CFG messages - UBX_CFG = 0x06, // Configuration input messages - UBX_MON = 0x0A, // Monitoring messages - UBX_AID = 0x0B, // Assist Now aiding messages - UBX_TIM = 0x0D, // Timing messages - UBX_HNR = 0x28, // High rate navigation results - UBX_NMEA = 0xF0, // NMEA Standard messages - UBX_PUBX = 0xF1, // NMEA proprietary messages (PUBX) - UBX_UNK = 0xFF - } __attribute__((packed)); - - enum msg_id_t - { - UBX_ACK_NAK = 0x00, // Reply to CFG messages - UBX_ACK_ACK = 0x01, // Reply to CFG messages - UBX_CFG_MSG = 0x01, // Configure which messages to send - UBX_CFG_RST = 0x04, // Reset command - UBX_CFG_RATE = 0x08, // Configure message rate - UBX_CFG_NMEA = 0x17, // Configure NMEA protocol - UBX_CFG_NAV5 = 0x24, // Configure navigation engine settings - UBX_MON_VER = 0x04, // Monitor Receiver/Software version - UBX_NAV_POSLLH = 0x02, // Current Position - UBX_NAV_STATUS = 0x03, // Receiver Navigation Status - UBX_NAV_DOP = 0x04, // Dilutions of Precision - UBX_NAV_ODO = 0x09, // Odometer Solution (NEO-M8 only) - UBX_NAV_RESETODO = 0x10, // Reset Odometer (NEO-M8 only) - UBX_NAV_VELNED = 0x12, // Current Velocity - UBX_NAV_TIMEGPS = 0x20, // Current GPS Time - UBX_NAV_TIMEUTC = 0x21, // Current UTC Time - UBX_NAV_SVINFO = 0x30, // Space Vehicle Information - UBX_HNR_PVT = 0x00, // High rate Position, Velocity and Time - UBX_ID_UNK = 0xFF - } __attribute__((packed)); - - struct msg_hdr_t { - msg_class_t msg_class; - msg_id_t msg_id; - bool same_kind( const msg_hdr_t & msg ) const - { return (msg_class == msg.msg_class) && (msg_id == msg.msg_id); } - } __attribute__((packed)); - - struct msg_t : msg_hdr_t { - uint16_t length; // should be sizeof(this)-sizeof(msg_hdr_t) - #define UBX_MSG_LEN(msg) (sizeof(msg) - sizeof(ublox::msg_t)) - - msg_t() - { - length = 0; - }; - msg_t( enum msg_class_t m, enum msg_id_t i, uint16_t l = 0 ) - { - msg_class = m; - msg_id = i; - length = l; - } - void init() - { - uint8_t *mem = (uint8_t *) this; - memset( &mem[ sizeof(msg_t) ], 0, length ); - } - } __attribute__((packed)); - - /** - * Configure message intervals. - */ - - enum ubx_nmea_msg_t { // msg_id's for UBX_NMEA msg_class - UBX_GPGGA = 0x00, - UBX_GPGLL = 0x01, - UBX_GPGSA = 0x02, - UBX_GPGSV = 0x03, - UBX_GPRMC = 0x04, - UBX_GPVTG = 0x05, - UBX_GPGST = 0x07, - UBX_GPZDA = 0x08 - } __attribute__((packed)); - - struct cfg_msg_t : msg_t { - msg_class_t cfg_msg_class; - msg_id_t cfg_msg; - uint8_t rate; - - cfg_msg_t( msg_class_t m, msg_id_t i, uint8_t r ) - : msg_t( UBX_CFG, UBX_CFG_MSG, UBX_MSG_LEN(*this) ) - { - cfg_msg_class = m; - cfg_msg = i; - rate = r; - }; - } __attribute__((packed)); - - extern bool configNMEA( ubloxGPS &gps, NMEAGPS::nmea_msg_t msgType, uint8_t rate ); - - // Reset command - struct cfg_reset_t : msg_t { - - struct bbr_section_t - { - bool ephermeris :1; - bool almanac :1; - bool health :1; - bool klobuchard :1; - bool position :1; - bool clock_drift :1; - bool osc_param :1; - bool utc_param :1; - bool rtc :1; - bool reserved1 :2; - bool sfdr_param :1; - bool sfdr_veh_mon_param :1; - bool tct_param :1; - bool reserved2 :1; - bool autonomous_orbit_param:1; - } __attribute__((packed)); - - enum reset_mode_t - { - HW_RESET = 0x00, - CONTROLLED_SW_RESET = 0x01, - CONTROLLED_SW_RESET_GPS_ONLY = 0x02, - HW_RESET_AFTER_SHUTDOWN = 0x04, - CONTROLLED_GPS_STOP = 0x08, - CONTROLLED_GPS_START = 0x09 - } __attribute__((packed)); - - bbr_section_t clear_bbr_section; - reset_mode_t reset_mode : 8; - uint8_t reserved : 8; - - cfg_reset_t() - : msg_t( UBX_CFG, UBX_CFG_RST, UBX_MSG_LEN(*this) ) - { init(); } - - } __attribute__((packed)); - - // Configure navigation rate - enum time_ref_t { - UBX_TIME_REF_UTC=0, - UBX_TIME_REF_GPS=1 - } __attribute__((packed)); - - struct cfg_rate_t : msg_t { - uint16_t GPS_meas_rate; - uint16_t nav_rate; - enum time_ref_t time_ref:16; - - cfg_rate_t( uint16_t gr, uint16_t nr, enum time_ref_t tr ) - : msg_t( UBX_CFG, UBX_CFG_RATE, UBX_MSG_LEN(*this) ) - { - GPS_meas_rate = gr; - nav_rate = nr; - time_ref = tr; - } - } __attribute__((packed)); - - // Navigation Engine Expert Settings - enum dyn_model_t { - UBX_DYN_MODEL_PORTABLE = 0, - UBX_DYN_MODEL_STATIONARY = 2, - UBX_DYN_MODEL_PEDESTRIAN = 3, - UBX_DYN_MODEL_AUTOMOTIVE = 4, - UBX_DYN_MODEL_SEA = 5, - UBX_DYN_MODEL_AIR_1G = 6, - UBX_DYN_MODEL_AIR_2G = 7, - UBX_DYN_MODEL_AIR_4G = 8 - } __attribute__((packed)); - - enum position_fix_t { - UBX_POS_FIX_2D_ONLY = 1, - UBX_POS_FIX_3D_ONLY = 2, - UBX_POS_FIX_AUTO = 3 - } __attribute__((packed)); - - struct cfg_nav5_t : msg_t { - struct parameter_mask_t { - bool dyn_model :1; - bool min_elev :1; - bool fix :1; - bool dr_limit :1; - bool pos_mask :1; - bool time_mask :1; - bool static_hold_thr :1; - bool dgps_timeout :1; - int _unused_ :8; - } __attribute__((packed)); - - union { - struct parameter_mask_t apply; - uint16_t apply_word; - } __attribute__((packed)); - - enum dyn_model_t dyn_model:8; - enum position_fix_t fix_mode:8; - int32_t fixed_alt; // m MSL x0.01 - uint32_t fixed_alt_variance; // m^2 x0.0001 - int8_t min_elev; // deg - uint8_t dr_limit; // s - uint16_t pos_dop_mask; // x0.1 - uint16_t time_dop_mask; // x0.1 - uint16_t pos_acc_mask; // m - uint16_t time_acc_mask; // m - uint8_t static_hold_thr; // cm/s - uint8_t dgps_timeout; // s - uint32_t always_zero_1; - uint32_t always_zero_2; - uint32_t always_zero_3; - - cfg_nav5_t() : msg_t( UBX_CFG, UBX_CFG_NAV5, UBX_MSG_LEN(*this) ) - { - apply_word = 0xFF00; - always_zero_1 = - always_zero_2 = - always_zero_3 = 0; - } - - } __attribute__((packed)); - - // Geodetic Position Solution - struct nav_posllh_t : msg_t { - uint32_t time_of_week; // mS - int32_t lon; // deg * 1e7 - int32_t lat; // deg * 1e7 - int32_t height_above_ellipsoid; // mm - int32_t height_MSL; // mm - uint32_t horiz_acc; // mm - uint32_t vert_acc; // mm - - nav_posllh_t() : msg_t( UBX_NAV, UBX_NAV_POSLLH, UBX_MSG_LEN(*this) ) {}; - } __attribute__((packed)); - - // Receiver Navigation Status - struct nav_status_t : msg_t { - uint32_t time_of_week; // mS - enum status_t { - NAV_STAT_NONE, - NAV_STAT_DR_ONLY, - NAV_STAT_2D, - NAV_STAT_3D, - NAV_STAT_GPS_DR, - NAV_STAT_TIME_ONLY - } __attribute__((packed)) - status; - - struct flags_t { - bool gps_fix:1; - bool diff_soln:1; - bool week:1; - bool time_of_week:1; - } __attribute__((packed)) - flags; - - static gps_fix::status_t to_status( enum gps_fix::status_t status, flags_t flags ) - { - if (!flags.gps_fix) - return gps_fix::STATUS_NONE; - if (flags.diff_soln) - return gps_fix::STATUS_DGPS; - return status; - } - - struct { - bool dgps_input:1; - bool _skip_:6; - bool map_matching:1; - } __attribute__((packed)) - fix_status; - - enum { - PSM_ACQUISITION, - PSM_TRACKING, - PSM_POWER_OPTIMIZED_TRACKING, - PSM_INACTIVE - } - power_safe:2; // FW > v7.01 - - uint32_t time_to_first_fix; // ms time tag - uint32_t uptime; // ms since startup/reset - - nav_status_t() : msg_t( UBX_NAV, UBX_NAV_STATUS, UBX_MSG_LEN(*this) ) {}; - } __attribute__((packed)); - - // Dilutions of Precision - struct nav_dop_t : msg_t { - uint32_t time_of_week; // mS - - uint16_t gdop; // Geometric - uint16_t pdop; // Position - uint16_t tdop; // Time - uint16_t vdop; // Vertical - uint16_t hdop; // Horizontal - uint16_t ndop; // Northing - uint16_t edop; // Easting - - nav_dop_t() : msg_t( UBX_NAV, UBX_NAV_DOP, UBX_MSG_LEN(*this) ) {}; - } __attribute__((packed)); - - // Odometer Solution (NEO-M8 only) - struct nav_odo_t : msg_t { - uint8_t version; - uint8_t reserved[3]; - uint32_t time_of_week; // mS - uint32_t distance; // m - uint32_t total_distance; // m - uint32_t distanceSTD; // m (1-sigma) - - nav_odo_t() : msg_t( UBX_NAV, UBX_NAV_ODO, UBX_MSG_LEN(*this) ) {}; - } __attribute__((packed)); - - // Reset Odometer (NEO-M8 only) - struct nav_resetodo_t : msg_t { - // no payload, it's just a command - - nav_resetodo_t() : msg_t( UBX_NAV, UBX_NAV_RESETODO, UBX_MSG_LEN(*this) ) {}; - } __attribute__((packed)); - - // Velocity Solution in North/East/Down - struct nav_velned_t : msg_t { - uint32_t time_of_week; // mS - int32_t vel_north; // cm/s - int32_t vel_east; // cm/s - int32_t vel_down; // cm/s - uint32_t speed_3D; // cm/s - uint32_t speed_2D; // cm/s - int32_t heading; // degrees * 1e5 - uint32_t speed_acc; // cm/s - uint32_t heading_acc; // degrees * 1e5 - - nav_velned_t() : msg_t( UBX_NAV, UBX_NAV_VELNED, UBX_MSG_LEN(*this) ) {}; - } __attribute__((packed)); - - // GPS Time Solution - struct nav_timegps_t : msg_t { - uint32_t time_of_week; // mS - int32_t fractional_ToW; // nS - int16_t week; - int8_t leap_seconds; // GPS-UTC - struct valid_t { - bool time_of_week:1; - bool week:1; - bool leap_seconds:1; - } __attribute__((packed)) - valid; - - nav_timegps_t() : msg_t( UBX_NAV, UBX_NAV_TIMEGPS, UBX_MSG_LEN(*this) ) {}; - } __attribute__((packed)); - - // UTC Time Solution - struct nav_timeutc_t : msg_t { - uint32_t time_of_week; // mS - uint32_t time_accuracy; // nS - int32_t fractional_ToW; // nS - uint16_t year; // 1999..2099 - uint8_t month; // 1..12 - uint8_t day; // 1..31 - uint8_t hour; // 0..23 - uint8_t minute; // 0..59 - uint8_t second; // 0..59 - struct valid_t { - bool time_of_week:1; - bool week_number:1; - bool UTC:1; - } __attribute__((packed)) - valid; - - nav_timeutc_t() : msg_t( UBX_NAV, UBX_NAV_TIMEUTC, UBX_MSG_LEN(*this) ) {}; - } __attribute__((packed)); - - // Space Vehicle Information - struct nav_svinfo_t : msg_t { - uint32_t time_of_week; // mS - uint8_t num_channels; - enum { ANTARIS_OR_4, UBLOX_5, UBLOX_6 } chipgen:8; - uint16_t reserved2; - struct sv_t { - uint8_t channel; // 255 = no channel - uint8_t id; // Satellite ID - bool used_for_nav:1; - bool diff_corr :1; // differential correction available - bool orbit_avail :1; // orbit info available - bool orbit_eph :1; // orbit info is ephemeris - bool unhealthy :1; // SV should not be used - bool orbit_alm :1; // orbit info is Almanac Plus - bool orbit_AOP :1; // orbit info is AssistNow Autonomous - bool smoothed :1; // Carrier smoothed pseudorange used - enum { - IDLE, - SEARCHING, - ACQUIRED, - UNUSABLE, - CODE_LOCK, - CODE_AND_CARRIER_LOCK_1, - CODE_AND_CARRIER_LOCK_2, - CODE_AND_CARRIER_LOCK_3 - } - quality:8; - uint8_t snr; // dbHz - uint8_t elevation; // degrees - uint16_t azimuth; // degrees - uint32_t pr_res; // pseudo range residual in cm - }; - - // Calculate the number of bytes required to hold the - // specified number of channels. - static uint16_t size_for( uint8_t channels ) - { return sizeof(nav_svinfo_t) + (uint16_t)channels * sizeof(sv_t); } - - // Initialze the msg_hdr for the specified number of channels - void init( uint8_t max_channels ) - { - msg_class = UBX_NAV; - msg_id = UBX_NAV_SVINFO; - length = size_for( max_channels ) - sizeof(ublox::msg_t); - } - - } __attribute__((packed)); - - // High Rate PVT - struct hnr_pvt_t : msg_t { - uint32_t time_of_week; // mS - uint16_t year; // 1999..2099 - uint8_t month; // 1..12 - uint8_t day; // 1..31 - uint8_t hour; // 0..23 - uint8_t minute; // 0..59 - uint8_t second; // 0..59 - struct valid_t { - bool date:1; - bool time:1; - bool fully_resolved:1; - } __attribute__((packed)) - valid; - int32_t fractional_ToW; // nS - - nav_status_t::status_t status; - - struct flags_t { - bool gps_fix:1; - bool diff_soln:1; - bool week:1; - bool time_of_week:1; - bool heading_valid:1; - } __attribute__((packed)) - flags; - - static gps_fix::status_t to_status( enum gps_fix::status_t status, flags_t flags ) - { - if (!flags.gps_fix) - return gps_fix::STATUS_NONE; - if (flags.diff_soln) - return gps_fix::STATUS_DGPS; - return status; - } - - uint16_t reserved1; - - int32_t lon; // deg * 1e7 - int32_t lat; // deg * 1e7 - int32_t height_above_ellipsoid; // mm - int32_t height_MSL; // mm - - int32_t speed_2D; // mm/s - int32_t speed_3D; // mm/s - int32_t heading_motion; // degrees * 1e5 - int32_t heading_vehicle; // degrees * 1e5 - - uint32_t horiz_acc; // mm - uint32_t vert_acc; // mm - uint32_t speed_acc; // mm/s - uint32_t heading_acc; // degrees * 1e5 - - uint32_t reserved4; - - hnr_pvt_t() : msg_t( UBX_HNR, UBX_HNR_PVT, UBX_MSG_LEN(*this) ) {}; - } __attribute__((packed)); - - struct cfg_nmea_t : msg_t { - bool always_output_pos :1; // invalid or failed - bool output_invalid_pos :1; - bool output_invalid_time:1; - bool output_invalid_date:1; - bool use_GPS_only :1; - bool output_heading :1; // even if frozen - bool __not_used__ :2; - enum { - NMEA_V_2_1 = 0x21, - NMEA_V_2_3 = 0x23, - NMEA_V_4_0 = 0x40, // Neo M8 family only - NMEA_V_4_1 = 0x41 // Neo M8 family only - } - nmea_version : 8; - enum { - SV_PER_TALKERID_UNLIMITED = 0, - SV_PER_TALKERID_8 = 8, - SV_PER_TALKERID_12 = 12, - SV_PER_TALKERID_16 = 16 - } - num_sats_per_talker_id : 8; - bool compatibility_mode:1; - bool considering_mode :1; - bool max_line_length_82:1; // Neo M8 family only - uint8_t __not_used_1__ :5; - - cfg_nmea_t() : msg_t( UBX_CFG, UBX_CFG_NMEA, UBX_MSG_LEN(*this) ) {}; - - } __attribute__((packed)); - - struct cfg_nmea_v1_t : cfg_nmea_t { - bool filter_gps :1; - bool filter_sbas :1; - uint8_t __not_used_2__:2; - bool filter_qzss :1; - bool filter_glonass:1; - bool filter_beidou :1; - uint32_t __not_used_3__:25; - - bool proprietary_sat_numbering; // for non-NMEA satellites - enum { - MAIN_TALKER_ID_COMPUTED, - MAIN_TALKER_ID_GP, - MAIN_TALKER_ID_GL, - MAIN_TALKER_ID_GN, - MAIN_TALKER_ID_GA, - MAIN_TALKER_ID_GB - } - main_talker_id : 8; - bool gsv_uses_main_talker_id; // false means COMPUTED - enum cfg_nmea_version_t { - CFG_NMEA_V_0, // length = 12 - CFG_NMEA_V_1 // length = 20 (default) - } - version : 8; - - // Remaining fields are CFG_NMEA_V_1 only! - char beidou_talker_id[2]; // NULs mean default - uint8_t __reserved__[6]; - - cfg_nmea_v1_t( cfg_nmea_version_t v = CFG_NMEA_V_1 ) - { - version = v; - if (version == CFG_NMEA_V_0) - length = 12; - else { - length = 20; - for (uint8_t i=0; i<8;) // fills 'reserved' too - beidou_talker_id[i++] = 0; - } - }; - - } __attribute__((packed)); - -}; - -#endif // NMEAGPS_DERIVED_TYPES enabled - -#endif \ No newline at end of file +#include "ubxmsg.header.h" +#include "ubxmsg.impl.h" diff --git a/src/ublox/ubxmsg.header.h b/src/ublox/ubxmsg.header.h new file mode 100644 index 0000000..8e49f6e --- /dev/null +++ b/src/ublox/ubxmsg.header.h @@ -0,0 +1,589 @@ +#ifndef UBXMSG_H +#define UBXMSG_H + +// Copyright (C) 2014-2017, SlashDevin +// +// This file is part of NeoGPS +// +// NeoGPS is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// NeoGPS is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with NeoGPS. If not, see . + +#include "NMEAGPS_cfg.h" + +// Disable the entire file if derived types are not allowed. +#ifdef NMEAGPS_DERIVED_TYPES + +#include "NMEAGPS.h" +class ubloxGPS; + +namespace ublox { + + enum msg_class_t + { UBX_NAV = 0x01, // Navigation results + UBX_RXM = 0x02, // Receiver Manager messages + UBX_INF = 0x04, // Informational messages + UBX_ACK = 0x05, // ACK/NAK replies to CFG messages + UBX_CFG = 0x06, // Configuration input messages + UBX_MON = 0x0A, // Monitoring messages + UBX_AID = 0x0B, // Assist Now aiding messages + UBX_TIM = 0x0D, // Timing messages + UBX_HNR = 0x28, // High rate navigation results + UBX_NMEA = 0xF0, // NMEA Standard messages + UBX_PUBX = 0xF1, // NMEA proprietary messages (PUBX) + UBX_UNK = 0xFF + } __attribute__((packed)); + + enum msg_id_t + { + UBX_ACK_NAK = 0x00, // Reply to CFG messages + UBX_ACK_ACK = 0x01, // Reply to CFG messages + UBX_CFG_MSG = 0x01, // Configure which messages to send + UBX_CFG_RST = 0x04, // Reset command + UBX_CFG_RATE = 0x08, // Configure message rate + UBX_CFG_NMEA = 0x17, // Configure NMEA protocol + UBX_CFG_NAV5 = 0x24, // Configure navigation engine settings + UBX_MON_VER = 0x04, // Monitor Receiver/Software version + UBX_NAV_POSLLH = 0x02, // Current Position + UBX_NAV_STATUS = 0x03, // Receiver Navigation Status + UBX_NAV_DOP = 0x04, // Dilutions of Precision + UBX_NAV_ODO = 0x09, // Odometer Solution (NEO-M8 only) + UBX_NAV_RESETODO = 0x10, // Reset Odometer (NEO-M8 only) + UBX_NAV_VELNED = 0x12, // Current Velocity + UBX_NAV_TIMEGPS = 0x20, // Current GPS Time + UBX_NAV_TIMEUTC = 0x21, // Current UTC Time + UBX_NAV_SVINFO = 0x30, // Space Vehicle Information + UBX_HNR_PVT = 0x00, // High rate Position, Velocity and Time + UBX_ID_UNK = 0xFF + } __attribute__((packed)); + + struct msg_hdr_t { + msg_class_t msg_class; + msg_id_t msg_id; + bool same_kind( const msg_hdr_t & msg ) const + { return (msg_class == msg.msg_class) && (msg_id == msg.msg_id); } + } __attribute__((packed)); + + struct msg_t : msg_hdr_t { + uint16_t length; // should be sizeof(this)-sizeof(msg_hdr_t) + #define UBX_MSG_LEN(msg) (sizeof(msg) - sizeof(ublox::msg_t)) + + msg_t() + { + length = 0; + }; + msg_t( enum msg_class_t m, enum msg_id_t i, uint16_t l = 0 ) + { + msg_class = m; + msg_id = i; + length = l; + } + void init() + { + uint8_t *mem = (uint8_t *) this; + memset( &mem[ sizeof(msg_t) ], 0, length ); + } + } __attribute__((packed)); + + /** + * Configure message intervals. + */ + + enum ubx_nmea_msg_t { // msg_id's for UBX_NMEA msg_class + UBX_GPGGA = 0x00, + UBX_GPGLL = 0x01, + UBX_GPGSA = 0x02, + UBX_GPGSV = 0x03, + UBX_GPRMC = 0x04, + UBX_GPVTG = 0x05, + UBX_GPGST = 0x07, + UBX_GPZDA = 0x08 + } __attribute__((packed)); + + struct cfg_msg_t : msg_t { + msg_class_t cfg_msg_class; + msg_id_t cfg_msg; + uint8_t rate; + + cfg_msg_t( msg_class_t m, msg_id_t i, uint8_t r ) + : msg_t( UBX_CFG, UBX_CFG_MSG, UBX_MSG_LEN(*this) ) + { + cfg_msg_class = m; + cfg_msg = i; + rate = r; + }; + } __attribute__((packed)); + + extern bool configNMEA( ubloxGPS &gps, NMEAGPS::nmea_msg_t msgType, uint8_t rate ); + + // Reset command + struct cfg_reset_t : msg_t { + + struct bbr_section_t + { + bool ephermeris :1; + bool almanac :1; + bool health :1; + bool klobuchard :1; + bool position :1; + bool clock_drift :1; + bool osc_param :1; + bool utc_param :1; + bool rtc :1; + bool reserved1 :2; + bool sfdr_param :1; + bool sfdr_veh_mon_param :1; + bool tct_param :1; + bool reserved2 :1; + bool autonomous_orbit_param:1; + } __attribute__((packed)); + + enum reset_mode_t + { + HW_RESET = 0x00, + CONTROLLED_SW_RESET = 0x01, + CONTROLLED_SW_RESET_GPS_ONLY = 0x02, + HW_RESET_AFTER_SHUTDOWN = 0x04, + CONTROLLED_GPS_STOP = 0x08, + CONTROLLED_GPS_START = 0x09 + } __attribute__((packed)); + + bbr_section_t clear_bbr_section; + reset_mode_t reset_mode : 8; + uint8_t reserved : 8; + + cfg_reset_t() + : msg_t( UBX_CFG, UBX_CFG_RST, UBX_MSG_LEN(*this) ) + { init(); } + + } __attribute__((packed)); + + // Configure navigation rate + enum time_ref_t { + UBX_TIME_REF_UTC=0, + UBX_TIME_REF_GPS=1 + } __attribute__((packed)); + + struct cfg_rate_t : msg_t { + uint16_t GPS_meas_rate; + uint16_t nav_rate; + enum time_ref_t time_ref:16; + + cfg_rate_t( uint16_t gr, uint16_t nr, enum time_ref_t tr ) + : msg_t( UBX_CFG, UBX_CFG_RATE, UBX_MSG_LEN(*this) ) + { + GPS_meas_rate = gr; + nav_rate = nr; + time_ref = tr; + } + } __attribute__((packed)); + + // Navigation Engine Expert Settings + enum dyn_model_t { + UBX_DYN_MODEL_PORTABLE = 0, + UBX_DYN_MODEL_STATIONARY = 2, + UBX_DYN_MODEL_PEDESTRIAN = 3, + UBX_DYN_MODEL_AUTOMOTIVE = 4, + UBX_DYN_MODEL_SEA = 5, + UBX_DYN_MODEL_AIR_1G = 6, + UBX_DYN_MODEL_AIR_2G = 7, + UBX_DYN_MODEL_AIR_4G = 8 + } __attribute__((packed)); + + enum position_fix_t { + UBX_POS_FIX_2D_ONLY = 1, + UBX_POS_FIX_3D_ONLY = 2, + UBX_POS_FIX_AUTO = 3 + } __attribute__((packed)); + + struct cfg_nav5_t : msg_t { + struct parameter_mask_t { + bool dyn_model :1; + bool min_elev :1; + bool fix :1; + bool dr_limit :1; + bool pos_mask :1; + bool time_mask :1; + bool static_hold_thr :1; + bool dgps_timeout :1; + int _unused_ :8; + } __attribute__((packed)); + + union { + struct parameter_mask_t apply; + uint16_t apply_word; + } __attribute__((packed)); + + enum dyn_model_t dyn_model:8; + enum position_fix_t fix_mode:8; + int32_t fixed_alt; // m MSL x0.01 + uint32_t fixed_alt_variance; // m^2 x0.0001 + int8_t min_elev; // deg + uint8_t dr_limit; // s + uint16_t pos_dop_mask; // x0.1 + uint16_t time_dop_mask; // x0.1 + uint16_t pos_acc_mask; // m + uint16_t time_acc_mask; // m + uint8_t static_hold_thr; // cm/s + uint8_t dgps_timeout; // s + uint32_t always_zero_1; + uint32_t always_zero_2; + uint32_t always_zero_3; + + cfg_nav5_t() : msg_t( UBX_CFG, UBX_CFG_NAV5, UBX_MSG_LEN(*this) ) + { + apply_word = 0xFF00; + always_zero_1 = + always_zero_2 = + always_zero_3 = 0; + } + + } __attribute__((packed)); + + // Geodetic Position Solution + struct nav_posllh_t : msg_t { + uint32_t time_of_week; // mS + int32_t lon; // deg * 1e7 + int32_t lat; // deg * 1e7 + int32_t height_above_ellipsoid; // mm + int32_t height_MSL; // mm + uint32_t horiz_acc; // mm + uint32_t vert_acc; // mm + + nav_posllh_t() : msg_t( UBX_NAV, UBX_NAV_POSLLH, UBX_MSG_LEN(*this) ) {}; + } __attribute__((packed)); + + // Receiver Navigation Status + struct nav_status_t : msg_t { + uint32_t time_of_week; // mS + enum status_t { + NAV_STAT_NONE, + NAV_STAT_DR_ONLY, + NAV_STAT_2D, + NAV_STAT_3D, + NAV_STAT_GPS_DR, + NAV_STAT_TIME_ONLY + } __attribute__((packed)) + status; + + struct flags_t { + bool gps_fix:1; + bool diff_soln:1; + bool week:1; + bool time_of_week:1; + } __attribute__((packed)) + flags; + + static gps_fix::status_t to_status( enum gps_fix::status_t status, flags_t flags ) + { + if (!flags.gps_fix) + return gps_fix::STATUS_NONE; + if (flags.diff_soln) + return gps_fix::STATUS_DGPS; + return status; + } + + struct { + bool dgps_input:1; + bool _skip_:6; + bool map_matching:1; + } __attribute__((packed)) + fix_status; + + enum { + PSM_ACQUISITION, + PSM_TRACKING, + PSM_POWER_OPTIMIZED_TRACKING, + PSM_INACTIVE + } + power_safe:2; // FW > v7.01 + + uint32_t time_to_first_fix; // ms time tag + uint32_t uptime; // ms since startup/reset + + nav_status_t() : msg_t( UBX_NAV, UBX_NAV_STATUS, UBX_MSG_LEN(*this) ) {}; + } __attribute__((packed)); + + // Dilutions of Precision + struct nav_dop_t : msg_t { + uint32_t time_of_week; // mS + + uint16_t gdop; // Geometric + uint16_t pdop; // Position + uint16_t tdop; // Time + uint16_t vdop; // Vertical + uint16_t hdop; // Horizontal + uint16_t ndop; // Northing + uint16_t edop; // Easting + + nav_dop_t() : msg_t( UBX_NAV, UBX_NAV_DOP, UBX_MSG_LEN(*this) ) {}; + } __attribute__((packed)); + + // Odometer Solution (NEO-M8 only) + struct nav_odo_t : msg_t { + uint8_t version; + uint8_t reserved[3]; + uint32_t time_of_week; // mS + uint32_t distance; // m + uint32_t total_distance; // m + uint32_t distanceSTD; // m (1-sigma) + + nav_odo_t() : msg_t( UBX_NAV, UBX_NAV_ODO, UBX_MSG_LEN(*this) ) {}; + } __attribute__((packed)); + + // Reset Odometer (NEO-M8 only) + struct nav_resetodo_t : msg_t { + // no payload, it's just a command + + nav_resetodo_t() : msg_t( UBX_NAV, UBX_NAV_RESETODO, UBX_MSG_LEN(*this) ) {}; + } __attribute__((packed)); + + // Velocity Solution in North/East/Down + struct nav_velned_t : msg_t { + uint32_t time_of_week; // mS + int32_t vel_north; // cm/s + int32_t vel_east; // cm/s + int32_t vel_down; // cm/s + uint32_t speed_3D; // cm/s + uint32_t speed_2D; // cm/s + int32_t heading; // degrees * 1e5 + uint32_t speed_acc; // cm/s + uint32_t heading_acc; // degrees * 1e5 + + nav_velned_t() : msg_t( UBX_NAV, UBX_NAV_VELNED, UBX_MSG_LEN(*this) ) {}; + } __attribute__((packed)); + + // GPS Time Solution + struct nav_timegps_t : msg_t { + uint32_t time_of_week; // mS + int32_t fractional_ToW; // nS + int16_t week; + int8_t leap_seconds; // GPS-UTC + struct valid_t { + bool time_of_week:1; + bool week:1; + bool leap_seconds:1; + } __attribute__((packed)) + valid; + + nav_timegps_t() : msg_t( UBX_NAV, UBX_NAV_TIMEGPS, UBX_MSG_LEN(*this) ) {}; + } __attribute__((packed)); + + // UTC Time Solution + struct nav_timeutc_t : msg_t { + uint32_t time_of_week; // mS + uint32_t time_accuracy; // nS + int32_t fractional_ToW; // nS + uint16_t year; // 1999..2099 + uint8_t month; // 1..12 + uint8_t day; // 1..31 + uint8_t hour; // 0..23 + uint8_t minute; // 0..59 + uint8_t second; // 0..59 + struct valid_t { + bool time_of_week:1; + bool week_number:1; + bool UTC:1; + } __attribute__((packed)) + valid; + + nav_timeutc_t() : msg_t( UBX_NAV, UBX_NAV_TIMEUTC, UBX_MSG_LEN(*this) ) {}; + } __attribute__((packed)); + + // Space Vehicle Information + struct nav_svinfo_t : msg_t { + uint32_t time_of_week; // mS + uint8_t num_channels; + enum { ANTARIS_OR_4, UBLOX_5, UBLOX_6 } chipgen:8; + uint16_t reserved2; + struct sv_t { + uint8_t channel; // 255 = no channel + uint8_t id; // Satellite ID + bool used_for_nav:1; + bool diff_corr :1; // differential correction available + bool orbit_avail :1; // orbit info available + bool orbit_eph :1; // orbit info is ephemeris + bool unhealthy :1; // SV should not be used + bool orbit_alm :1; // orbit info is Almanac Plus + bool orbit_AOP :1; // orbit info is AssistNow Autonomous + bool smoothed :1; // Carrier smoothed pseudorange used + enum { + IDLE, + SEARCHING, + ACQUIRED, + UNUSABLE, + CODE_LOCK, + CODE_AND_CARRIER_LOCK_1, + CODE_AND_CARRIER_LOCK_2, + CODE_AND_CARRIER_LOCK_3 + } + quality:8; + uint8_t snr; // dbHz + uint8_t elevation; // degrees + uint16_t azimuth; // degrees + uint32_t pr_res; // pseudo range residual in cm + }; + + // Calculate the number of bytes required to hold the + // specified number of channels. + static uint16_t size_for( uint8_t channels ) + { return sizeof(nav_svinfo_t) + (uint16_t)channels * sizeof(sv_t); } + + // Initialze the msg_hdr for the specified number of channels + void init( uint8_t max_channels ) + { + msg_class = UBX_NAV; + msg_id = UBX_NAV_SVINFO; + length = size_for( max_channels ) - sizeof(ublox::msg_t); + } + + } __attribute__((packed)); + + // High Rate PVT + struct hnr_pvt_t : msg_t { + uint32_t time_of_week; // mS + uint16_t year; // 1999..2099 + uint8_t month; // 1..12 + uint8_t day; // 1..31 + uint8_t hour; // 0..23 + uint8_t minute; // 0..59 + uint8_t second; // 0..59 + struct valid_t { + bool date:1; + bool time:1; + bool fully_resolved:1; + } __attribute__((packed)) + valid; + int32_t fractional_ToW; // nS + + nav_status_t::status_t status; + + struct flags_t { + bool gps_fix:1; + bool diff_soln:1; + bool week:1; + bool time_of_week:1; + bool heading_valid:1; + } __attribute__((packed)) + flags; + + static gps_fix::status_t to_status( enum gps_fix::status_t status, flags_t flags ) + { + if (!flags.gps_fix) + return gps_fix::STATUS_NONE; + if (flags.diff_soln) + return gps_fix::STATUS_DGPS; + return status; + } + + uint16_t reserved1; + + int32_t lon; // deg * 1e7 + int32_t lat; // deg * 1e7 + int32_t height_above_ellipsoid; // mm + int32_t height_MSL; // mm + + int32_t speed_2D; // mm/s + int32_t speed_3D; // mm/s + int32_t heading_motion; // degrees * 1e5 + int32_t heading_vehicle; // degrees * 1e5 + + uint32_t horiz_acc; // mm + uint32_t vert_acc; // mm + uint32_t speed_acc; // mm/s + uint32_t heading_acc; // degrees * 1e5 + + uint32_t reserved4; + + hnr_pvt_t() : msg_t( UBX_HNR, UBX_HNR_PVT, UBX_MSG_LEN(*this) ) {}; + } __attribute__((packed)); + + struct cfg_nmea_t : msg_t { + bool always_output_pos :1; // invalid or failed + bool output_invalid_pos :1; + bool output_invalid_time:1; + bool output_invalid_date:1; + bool use_GPS_only :1; + bool output_heading :1; // even if frozen + bool __not_used__ :2; + enum { + NMEA_V_2_1 = 0x21, + NMEA_V_2_3 = 0x23, + NMEA_V_4_0 = 0x40, // Neo M8 family only + NMEA_V_4_1 = 0x41 // Neo M8 family only + } + nmea_version : 8; + enum { + SV_PER_TALKERID_UNLIMITED = 0, + SV_PER_TALKERID_8 = 8, + SV_PER_TALKERID_12 = 12, + SV_PER_TALKERID_16 = 16 + } + num_sats_per_talker_id : 8; + bool compatibility_mode:1; + bool considering_mode :1; + bool max_line_length_82:1; // Neo M8 family only + uint8_t __not_used_1__ :5; + + cfg_nmea_t() : msg_t( UBX_CFG, UBX_CFG_NMEA, UBX_MSG_LEN(*this) ) {}; + + } __attribute__((packed)); + + struct cfg_nmea_v1_t : cfg_nmea_t { + bool filter_gps :1; + bool filter_sbas :1; + uint8_t __not_used_2__:2; + bool filter_qzss :1; + bool filter_glonass:1; + bool filter_beidou :1; + uint32_t __not_used_3__:25; + + bool proprietary_sat_numbering; // for non-NMEA satellites + enum { + MAIN_TALKER_ID_COMPUTED, + MAIN_TALKER_ID_GP, + MAIN_TALKER_ID_GL, + MAIN_TALKER_ID_GN, + MAIN_TALKER_ID_GA, + MAIN_TALKER_ID_GB + } + main_talker_id : 8; + bool gsv_uses_main_talker_id; // false means COMPUTED + enum cfg_nmea_version_t { + CFG_NMEA_V_0, // length = 12 + CFG_NMEA_V_1 // length = 20 (default) + } + version : 8; + + // Remaining fields are CFG_NMEA_V_1 only! + char beidou_talker_id[2]; // NULs mean default + uint8_t __reserved__[6]; + + cfg_nmea_v1_t( cfg_nmea_version_t v = CFG_NMEA_V_1 ) + { + version = v; + if (version == CFG_NMEA_V_0) + length = 12; + else { + length = 20; + for (uint8_t i=0; i<8;) // fills 'reserved' too + beidou_talker_id[i++] = 0; + } + }; + + } __attribute__((packed)); + +}; + +#endif // NMEAGPS_DERIVED_TYPES enabled + +#endif diff --git a/src/ublox/ubxmsg.cpp b/src/ublox/ubxmsg.impl.h similarity index 92% rename from src/ublox/ubxmsg.cpp rename to src/ublox/ubxmsg.impl.h index 2ac4f1a..62dfa6d 100644 --- a/src/ublox/ubxmsg.cpp +++ b/src/ublox/ubxmsg.impl.h @@ -15,7 +15,11 @@ // You should have received a copy of the GNU General Public License // along with NeoGPS. If not, see . -#include "ublox/ubxGPS.h" +// Just to be sure. This file should only be included in ubxmsg.h which +// protects against multiple includes already. +#pragma once + +#include "ubxGPS.header.h" // Disable the entire file if derived types are not allowed. #ifdef NMEAGPS_DERIVED_TYPES @@ -68,4 +72,4 @@ bool ublox::configNMEA( ubloxGPS &gps, NMEAGPS::nmea_msg_t msgType, uint8_t rate return gps.send( cfg_msg_t( UBX_NMEA, msg_id, rate ) ); } -#endif \ No newline at end of file +#endif From 482cfdeeb61546c06292282104c6384055b6b85a Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Wed, 30 Aug 2017 12:48:04 +0200 Subject: [PATCH 14/38] feat: implement LINUX platform shims --- src/platforms/Print.h | 3 +- src/platforms/Stream.h | 2 +- src/platforms/System.h | 2 +- src/platforms/linux/GpsPort.cpp | 22 ++++++ src/platforms/linux/GpsPort.h | 14 ++++ src/platforms/linux/platform.h | 35 ++++++--- src/platforms/linux/serial.cpp | 124 ++++++++++++++++++++++++++++++++ src/platforms/linux/serial.h | 15 ++++ 8 files changed, 204 insertions(+), 13 deletions(-) create mode 100644 src/platforms/linux/GpsPort.cpp create mode 100644 src/platforms/linux/GpsPort.h create mode 100644 src/platforms/linux/serial.cpp create mode 100644 src/platforms/linux/serial.h diff --git a/src/platforms/Print.h b/src/platforms/Print.h index b794ac2..a4c6a1b 100644 --- a/src/platforms/Print.h +++ b/src/platforms/Print.h @@ -4,7 +4,6 @@ #ifndef NEO_GPS_PRINT #define NEO_GPS_PRINT NeoGPS::Print -#endif /** * This file implements a non working dummy implemenation for Print @@ -25,3 +24,5 @@ namespace NeoGPS { void printFloat( Print &, float f, uint8_t decPlaces ) {} #endif } + +#endif diff --git a/src/platforms/Stream.h b/src/platforms/Stream.h index 72d8bd4..11872a7 100644 --- a/src/platforms/Stream.h +++ b/src/platforms/Stream.h @@ -2,7 +2,6 @@ #ifndef NEO_GPS_STREAM #define NEO_GPS_STREAM NeoGPS::Stream -#endif /** * This file implements a non working dummy implementation for Stream. @@ -16,3 +15,4 @@ namespace NeoGPS { void print(char) {} }; } +#endif diff --git a/src/platforms/System.h b/src/platforms/System.h index ae99866..58495d2 100644 --- a/src/platforms/System.h +++ b/src/platforms/System.h @@ -2,7 +2,6 @@ #ifndef NEO_GPS_SYSTEM #define NEO_GPS_SYSTEM NeoGPS::System -#endif /** * This file implements a non working dummy implementation for interrupts and noInterrupts. @@ -15,3 +14,4 @@ namespace NeoGPS { static void unlock() {} }; } +#endif diff --git a/src/platforms/linux/GpsPort.cpp b/src/platforms/linux/GpsPort.cpp new file mode 100644 index 0000000..8fb47ff --- /dev/null +++ b/src/platforms/linux/GpsPort.cpp @@ -0,0 +1,22 @@ +#pragma once + +#include "GpsPort.header.h" + +GpsPort::GpsPort(const char* usbDev) { + _device = ::init(usbDev); +} + +bool GpsPort::available() { + return ::data_available(_device); +} + +char GpsPort::read() { + return ::read(_device); +} + +void GpsPort::print(char c) { + char s[2]; + s[0] = c; + s[1] = '\0'; + ::write(_device, s); +} diff --git a/src/platforms/linux/GpsPort.h b/src/platforms/linux/GpsPort.h new file mode 100644 index 0000000..f601040 --- /dev/null +++ b/src/platforms/linux/GpsPort.h @@ -0,0 +1,14 @@ +#pragma once +#include "serial.h" + +class GpsPort { +private: + serial_dev_t _device; + +public: + GpsPort(const char*); + bool available(); + char read(); + void print(char); +}; + diff --git a/src/platforms/linux/platform.h b/src/platforms/linux/platform.h index b3e94f4..8971833 100644 --- a/src/platforms/linux/platform.h +++ b/src/platforms/linux/platform.h @@ -1,17 +1,32 @@ #pragma once -#include +#ifndef NEO_GPS_PRINT + #include + #include + + #define NEO_GPS_PRINT std::iostream + + #ifdef USE_FLOAT + void printFloat( std::iostream & io, float f, uint8_t decPlaces ) { + std::streamsize ss = std::cout.precision(); + io << std::setprecision(decPlaces) << std::fixed << f << std::setprecision(ss); + } + #endif +#endif -#define NEO_GPS_SYSTEM System +#ifndef NEO_GPS_STREAM + #include "GpsPort.h" + #define NEO_GPS_STREAM GpsPort +#endif -#define NEO_GPS_STREAM GpsStream +#ifndef NEO_GPS_SYSTEM + #define NEO_GPS_SYSTEM System -#define NEO_GPS_PRINT std::iostream - -class System { -public: - static void lock() {} - static void unlock() {} -}; + class System { + public: + static void lock() {} + static void unlock() {} + }; +#endif diff --git a/src/platforms/linux/serial.cpp b/src/platforms/linux/serial.cpp new file mode 100644 index 0000000..773cf1b --- /dev/null +++ b/src/platforms/linux/serial.cpp @@ -0,0 +1,124 @@ +/* + * This code is heavily based on + * https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c + */ + +#include "serial.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +static int set_interface_attribs(int fd, int speed) +{ + struct termios tty; + + if (tcgetattr(fd, &tty) < 0) { + printf("Error from tcgetattr: %s\n", strerror(errno)); + return -1; + } + + cfsetospeed(&tty, (speed_t)speed); + cfsetispeed(&tty, (speed_t)speed); + + tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */ + tty.c_cflag &= ~CSIZE; + tty.c_cflag |= CS8; /* 8-bit characters */ + tty.c_cflag &= ~PARENB; /* no parity bit */ + tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */ + tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */ + + /* setup for non-canonical mode */ + tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + tty.c_oflag &= ~OPOST; + + /* fetch bytes as they become available */ + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 1; + + if (tcsetattr(fd, TCSANOW, &tty) != 0) { + printf("Error from tcsetattr: %s\n", strerror(errno)); + return -1; + } + return 0; +} + +static void set_mincount(int fd, int mcount) +{ + struct termios tty; + + if (tcgetattr(fd, &tty) < 0) { + printf("Error tcgetattr: %s\n", strerror(errno)); + return; + } + + tty.c_cc[VMIN] = mcount ? 1 : 0; + tty.c_cc[VTIME] = 5; /* half second timer */ + + if (tcsetattr(fd, TCSANOW, &tty) < 0) + printf("Error tcsetattr: %s\n", strerror(errno)); +} + +bool data_available(serial_dev_t fd) +{ + fd_set rfds; + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + int retval = select(1, &rfds, NULL, NULL, &tv); + if (retval == -1) { + printf("Error select: %s\n", strerror(errno)); + } + return retval > 0; +} + +char read(serial_dev_t fd) +{ + char c; + int rdlen = read(fd, &c, 1); + if (rdlen > 0) { + return c; + } else if (rdlen < 0) { + printf("Error from read: %s\n", strerror(errno)); + } + return '\0'; +} + +void write(serial_dev_t fd, const char* out) +{ + int len = strlen(out); + /* simple output */ + int wlen = write(fd, out, len); + if (wlen != len) { + printf("Error from write: %d, %d\n", wlen, errno); + } + tcdrain(fd); /* delay for output */ +} + +serial_dev_t init(const char *portname) +{ + if (portname == nullptr) { + portname = "/dev/ttyUSB0"; + } + + int fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); + if (fd < 0) { + printf("Error opening %s: %s\n", portname, strerror(errno)); + return -1; + } + /*baudrate 9600, 8 bits, no parity, 1 stop bit */ + set_interface_attribs(fd, B9600); + //set_mincount(fd, 0); /* set to pure timed read */ + + return fd; +} diff --git a/src/platforms/linux/serial.h b/src/platforms/linux/serial.h new file mode 100644 index 0000000..8b2423e --- /dev/null +++ b/src/platforms/linux/serial.h @@ -0,0 +1,15 @@ +#pragma once + +typedef int serial_dev_t; + +// Open portname (if nullptr /dev/ttyUSB0). +serial_dev_t init(const char *portname); + +// Write to previously initialized port. +void write(serial_dev_t, const char* out); + +// Reads one character from previously initialized port. +char read(serial_dev_t); + +// Returns true if read would not block on initialized port. +bool data_available(serial_dev_t); From 7728a7261f7b4a87c384fcb2df706abd53c165d4 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Thu, 31 Aug 2017 18:22:55 +0200 Subject: [PATCH 15/38] feat: remove linux serial.* move code into GpsPort directly. --- src/GPSfix.h | 6 +- src/Platform.h | 2 - src/platforms/linux/GpsPort.cpp | 22 ----- src/platforms/linux/GpsPort.h | 14 +-- src/platforms/linux/GpsPort.header.h | 18 ++++ src/platforms/linux/GpsPort.impl.h | 117 +++++++++++++++++++++++++ src/platforms/linux/platform.h | 6 +- src/platforms/linux/serial.cpp | 124 --------------------------- src/platforms/linux/serial.h | 15 ---- 9 files changed, 143 insertions(+), 181 deletions(-) delete mode 100644 src/platforms/linux/GpsPort.cpp create mode 100644 src/platforms/linux/GpsPort.header.h create mode 100644 src/platforms/linux/GpsPort.impl.h delete mode 100644 src/platforms/linux/serial.cpp delete mode 100644 src/platforms/linux/serial.h diff --git a/src/GPSfix.h b/src/GPSfix.h index d645b63..742e5fd 100644 --- a/src/GPSfix.h +++ b/src/GPSfix.h @@ -22,15 +22,15 @@ #include "GPSfix_cfg.h" #if defined( GPS_FIX_DATE ) | defined( GPS_FIX_TIME ) - #include "NeoTime.header.h" + #include "NeoTime.h" #endif #ifdef GPS_FIX_LOCATION_DMS - #include "DMS.header.h" + #include "DMS.h" #endif #ifdef GPS_FIX_LOCATION - #include "Location.header.h" + #include "Location.h" #endif /** diff --git a/src/Platform.h b/src/Platform.h index d00a59c..ec80c8e 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -4,8 +4,6 @@ #ifdef ARDUINO #include -#elif defined LINUX - #include #else #include #include diff --git a/src/platforms/linux/GpsPort.cpp b/src/platforms/linux/GpsPort.cpp deleted file mode 100644 index 8fb47ff..0000000 --- a/src/platforms/linux/GpsPort.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "GpsPort.header.h" - -GpsPort::GpsPort(const char* usbDev) { - _device = ::init(usbDev); -} - -bool GpsPort::available() { - return ::data_available(_device); -} - -char GpsPort::read() { - return ::read(_device); -} - -void GpsPort::print(char c) { - char s[2]; - s[0] = c; - s[1] = '\0'; - ::write(_device, s); -} diff --git a/src/platforms/linux/GpsPort.h b/src/platforms/linux/GpsPort.h index f601040..540638d 100644 --- a/src/platforms/linux/GpsPort.h +++ b/src/platforms/linux/GpsPort.h @@ -1,14 +1,4 @@ #pragma once -#include "serial.h" - -class GpsPort { -private: - serial_dev_t _device; - -public: - GpsPort(const char*); - bool available(); - char read(); - void print(char); -}; +#include "GpsPort.header.h" +#include "GpsPort.impl.h" diff --git a/src/platforms/linux/GpsPort.header.h b/src/platforms/linux/GpsPort.header.h new file mode 100644 index 0000000..bce76d8 --- /dev/null +++ b/src/platforms/linux/GpsPort.header.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +class GpsPort { +private: + int _device; + +public: + GpsPort(const char* usbDev = "/dev/ttyUSB0", const char* speed = "9600"); + bool available(); + char read(); + void print(char); + +private: + int set_interface_attribs(int fd, int speed); +}; + diff --git a/src/platforms/linux/GpsPort.impl.h b/src/platforms/linux/GpsPort.impl.h new file mode 100644 index 0000000..0c3002d --- /dev/null +++ b/src/platforms/linux/GpsPort.impl.h @@ -0,0 +1,117 @@ +#pragma once + +#include "GpsPort.header.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +GpsPort::GpsPort(const char* usbDev, const char* speedTxt) +{ + if (usbDev == nullptr) { + usbDev = "/dev/ttyUSB0"; + } + + int fd = open(usbDev, O_RDWR | O_NOCTTY | O_SYNC); + if (fd < 0) { + printf("Error opening %s: %s\n", usbDev, strerror(errno)); + _device = -1; + } + + int speed; + switch(atoi(speedTxt == nullptr ? "9600" : speedTxt)) { + case 38400: + speed = B38400; + break; + case 19200: + speed = B19200; + break; + default: + case 9600: + speed = B9600; + break; + } + /*baudrate 9600, 8 bits, no parity, 1 stop bit */ + set_interface_attribs(fd, speed); + + _device = fd; +} + +bool GpsPort::available() +{ + fd_set rfds; + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + + FD_ZERO( &rfds ); + FD_SET( _device, &rfds ); + + int retval = select( 1, &rfds, NULL, NULL, &tv ); + if (retval == -1) { + printf("Error select: %s\n", strerror(errno)); + } + return retval > 0; +} + +char GpsPort::read() +{ + char c; + int rdlen = ::read( _device, &c, 1 ); + if (rdlen > 0) { + return c; + } else if (rdlen < 0) { + printf("Error from read: %s\n", strerror(errno)); + } + return '\0'; +} + +void GpsPort::print(char c) +{ + /* simple output */ + int wlen = ::write(_device, &c, 1); + if (wlen != 1) { + printf("Error from write: %d, %d\n", wlen, errno); + } + tcdrain(_device); /* delay for output */ +} + +int GpsPort::set_interface_attribs(int fd, int speed) +{ + struct termios tty; + + if (tcgetattr(fd, &tty) < 0) { + printf("Error from tcgetattr: %s\n", strerror(errno)); + return -1; + } + + cfsetospeed(&tty, (speed_t)speed); + cfsetispeed(&tty, (speed_t)speed); + + tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */ + tty.c_cflag &= ~CSIZE; + tty.c_cflag |= CS8; /* 8-bit characters */ + tty.c_cflag &= ~PARENB; /* no parity bit */ + tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */ + tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */ + + /* setup for non-canonical mode */ + tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + tty.c_oflag &= ~OPOST; + + /* fetch bytes as they become available */ + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 1; + + if (tcsetattr(fd, TCSANOW, &tty) != 0) { + printf("Error from tcsetattr: %s\n", strerror(errno)); + return -1; + } + return 0; +} diff --git a/src/platforms/linux/platform.h b/src/platforms/linux/platform.h index 8971833..87bdbf8 100644 --- a/src/platforms/linux/platform.h +++ b/src/platforms/linux/platform.h @@ -4,10 +4,10 @@ #include #include - #define NEO_GPS_PRINT std::iostream + #define NEO_GPS_PRINT decltype(std::cout) #ifdef USE_FLOAT - void printFloat( std::iostream & io, float f, uint8_t decPlaces ) { + void printFloat( NEO_GPS_PRINT & io, float f, uint8_t decPlaces ) { std::streamsize ss = std::cout.precision(); io << std::setprecision(decPlaces) << std::fixed << f << std::setprecision(ss); } @@ -15,7 +15,7 @@ #endif #ifndef NEO_GPS_STREAM - #include "GpsPort.h" + #include "GpsPort.header.h" #define NEO_GPS_STREAM GpsPort #endif diff --git a/src/platforms/linux/serial.cpp b/src/platforms/linux/serial.cpp deleted file mode 100644 index 773cf1b..0000000 --- a/src/platforms/linux/serial.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * This code is heavily based on - * https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c - */ - -#include "serial.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -static int set_interface_attribs(int fd, int speed) -{ - struct termios tty; - - if (tcgetattr(fd, &tty) < 0) { - printf("Error from tcgetattr: %s\n", strerror(errno)); - return -1; - } - - cfsetospeed(&tty, (speed_t)speed); - cfsetispeed(&tty, (speed_t)speed); - - tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */ - tty.c_cflag &= ~CSIZE; - tty.c_cflag |= CS8; /* 8-bit characters */ - tty.c_cflag &= ~PARENB; /* no parity bit */ - tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */ - tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */ - - /* setup for non-canonical mode */ - tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); - tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - tty.c_oflag &= ~OPOST; - - /* fetch bytes as they become available */ - tty.c_cc[VMIN] = 1; - tty.c_cc[VTIME] = 1; - - if (tcsetattr(fd, TCSANOW, &tty) != 0) { - printf("Error from tcsetattr: %s\n", strerror(errno)); - return -1; - } - return 0; -} - -static void set_mincount(int fd, int mcount) -{ - struct termios tty; - - if (tcgetattr(fd, &tty) < 0) { - printf("Error tcgetattr: %s\n", strerror(errno)); - return; - } - - tty.c_cc[VMIN] = mcount ? 1 : 0; - tty.c_cc[VTIME] = 5; /* half second timer */ - - if (tcsetattr(fd, TCSANOW, &tty) < 0) - printf("Error tcsetattr: %s\n", strerror(errno)); -} - -bool data_available(serial_dev_t fd) -{ - fd_set rfds; - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 0; - - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - - int retval = select(1, &rfds, NULL, NULL, &tv); - if (retval == -1) { - printf("Error select: %s\n", strerror(errno)); - } - return retval > 0; -} - -char read(serial_dev_t fd) -{ - char c; - int rdlen = read(fd, &c, 1); - if (rdlen > 0) { - return c; - } else if (rdlen < 0) { - printf("Error from read: %s\n", strerror(errno)); - } - return '\0'; -} - -void write(serial_dev_t fd, const char* out) -{ - int len = strlen(out); - /* simple output */ - int wlen = write(fd, out, len); - if (wlen != len) { - printf("Error from write: %d, %d\n", wlen, errno); - } - tcdrain(fd); /* delay for output */ -} - -serial_dev_t init(const char *portname) -{ - if (portname == nullptr) { - portname = "/dev/ttyUSB0"; - } - - int fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); - if (fd < 0) { - printf("Error opening %s: %s\n", portname, strerror(errno)); - return -1; - } - /*baudrate 9600, 8 bits, no parity, 1 stop bit */ - set_interface_attribs(fd, B9600); - //set_mincount(fd, 0); /* set to pure timed read */ - - return fd; -} diff --git a/src/platforms/linux/serial.h b/src/platforms/linux/serial.h deleted file mode 100644 index 8b2423e..0000000 --- a/src/platforms/linux/serial.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -typedef int serial_dev_t; - -// Open portname (if nullptr /dev/ttyUSB0). -serial_dev_t init(const char *portname); - -// Write to previously initialized port. -void write(serial_dev_t, const char* out); - -// Reads one character from previously initialized port. -char read(serial_dev_t); - -// Returns true if read would not block on initialized port. -bool data_available(serial_dev_t); From b09636482b94b93c12a613af5664f64fb3e5a0aa Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Fri, 1 Sep 2017 09:24:38 +0200 Subject: [PATCH 16/38] feat: linux code --- examples/linux/NMEA.cpp | 154 ++++++++++++++++++ tests/FakeGPS/FakeContent.h | 3 + tests/FakeGPS/FakeGPS.h | 4 + tests/FakeGPS/FakeGPS.header.h | 17 ++ tests/FakeGPS/FakeGPS.impl.h | 38 +++++ .../FakeContent.internet_sample.h | 17 ++ tests/FakeGPS/platform.h | 32 ++++ tests/NMEA/NMEA.cpp | 154 ++++++++++++++++++ tests/NMEA/a.out | Bin 0 -> 47672 bytes tests/NMEA/build.dummy.txt | 1 + tests/NMEA/build.txt | 1 + 11 files changed, 421 insertions(+) create mode 100644 examples/linux/NMEA.cpp create mode 100644 tests/FakeGPS/FakeContent.h create mode 100644 tests/FakeGPS/FakeGPS.h create mode 100644 tests/FakeGPS/FakeGPS.header.h create mode 100644 tests/FakeGPS/FakeGPS.impl.h create mode 100644 tests/FakeGPS/fake_contents/FakeContent.internet_sample.h create mode 100644 tests/FakeGPS/platform.h create mode 100644 tests/NMEA/NMEA.cpp create mode 100755 tests/NMEA/a.out create mode 100644 tests/NMEA/build.dummy.txt create mode 100644 tests/NMEA/build.txt diff --git a/examples/linux/NMEA.cpp b/examples/linux/NMEA.cpp new file mode 100644 index 0000000..e8d7f44 --- /dev/null +++ b/examples/linux/NMEA.cpp @@ -0,0 +1,154 @@ +//====================================================================== +// Description: This program uses the fix-oriented methods available() and +// read() to handle complete fix structures. +// +// When the last character of the LAST_SENTENCE_IN_INTERVAL (see NMEAGPS_cfg.h) +// is decoded, a completed fix structure becomes available and is returned +// from read(). The new fix is saved the 'fix_data' structure, and can be used +// anywhere, at any time. +// +// If no messages are enabled in NMEAGPS_cfg.h, or +// no 'gps_fix' members are enabled in GPSfix_cfg.h, no information will be +// parsed, copied or printed. +// +// Prerequisites: +// 1) Your GPS device has been correctly powered. +// 2) Your GPS device is correctly connected using a serial adapter. +// By default /dev/ttyUSB0 is used. +// 3) You know the default baud rate of your GPS device. +// By default 9600 is assumed. If this doesn't work change it in serial.cpp +// 4) LAST_SENTENCE_IN_INTERVAL is defined to be the sentence that is +// sent *last* in each update interval (usually once per second). +// The default is NMEAGPS::NMEA_RMC (see NMEAGPS_cfg.h). Other +// programs may need to use the sentence identified by NMEAorder.ino. +// 5) NMEAGPS_RECOGNIZE_ALL is defined in NMEAGPS_cfg.h +// +//====================================================================== + +//------------------------------------------------------------ +// For the NeoGPS example programs, "Streamers" is common set +// of printing and formatting routines for GPS data, in a +// Comma-Separated Values text format (aka CSV). The CSV +// data will be printed to the "debug output device". +// If you don't need these formatters, simply delete this section. + +// platform.h must be included before NMEAGPS.h +#include + +#include +#include + +#include + +#include + +//------------------------------------------------------------ +// This object parses received characters +// into the gps.fix() data structure + +static NMEAGPS gps; + +//------------------------------------------------------------ +// Define a set of GPS fix information. It will +// hold on to the various pieces as they are received from +// an RMC sentence. It can be used anywhere in your sketch. + +static gps_fix fix_data; + +//---------------------------------------------------------------- +// This function gets called about once per second, during the GPS +// quiet time. It's the best place to do anything that might take +// a while: print a bunch of things, write to SD, send an SMS, etc. +// +// By doing the "hard" work during the quiet time, the CPU can get back to +// reading the GPS chars as they come in, so that no chars are lost. + +static auto & DEBUG_PORT = std::cout; + +static void doSomeWork() +{ + // Print all the things! + + trace_all( DEBUG_PORT, gps, fix_data ); + +} // doSomeWork + +//------------------------------------ +// This is the main GPS parsing loop. + +static void GPSloop(GpsPort gps_port) +{ + while (gps.available( gps_port )) { + fix_data = gps.read(); + doSomeWork(); + } + +} // GPSloop + +//-------------------------- + +GpsPort setup(const char * usbDev, const char * speed) +{ + // Start the normal trace output + DEBUG_PORT << "NMEA: started\n"; + DEBUG_PORT << " fix object size = "; + DEBUG_PORT << (uint32_t)sizeof(gps.fix()); + DEBUG_PORT << "\n gps object size = "; + DEBUG_PORT << (uint32_t)sizeof(gps); + DEBUG_PORT << "\nLooking for GPS device on "; + DEBUG_PORT << ( usbDev == nullptr ? "default" : usbDev ); + DEBUG_PORT << " with speed "; + DEBUG_PORT << ( speed == nullptr ? "default" : speed ); + + #ifndef NMEAGPS_RECOGNIZE_ALL + #error You must define NMEAGPS_RECOGNIZE_ALL in NMEAGPS_cfg.h! + #endif + + #ifdef NMEAGPS_INTERRUPT_PROCESSING + #error You must *NOT* define NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h! + #endif + + #if !defined( NMEAGPS_PARSE_GGA ) & !defined( NMEAGPS_PARSE_GLL ) & \ + !defined( NMEAGPS_PARSE_GSA ) & !defined( NMEAGPS_PARSE_GSV ) & \ + !defined( NMEAGPS_PARSE_RMC ) & !defined( NMEAGPS_PARSE_VTG ) & \ + !defined( NMEAGPS_PARSE_ZDA ) & !defined( NMEAGPS_PARSE_GST ) + + DEBUG_PORT << ( F("\nWARNING: No NMEA sentences are enabled: no fix data will be displayed.\n") ); + + #else + if (gps.merging == NMEAGPS::NO_MERGING) { + DEBUG_PORT << F("\nWARNING: displaying data from "); + DEBUG_PORT << gps.string_for( LAST_SENTENCE_IN_INTERVAL ); + DEBUG_PORT << F(" sentences ONLY, and only if "); + DEBUG_PORT << gps.string_for( LAST_SENTENCE_IN_INTERVAL ); + DEBUG_PORT << F(" is enabled.\n" + " Other sentences may be parsed, but their data will not be displayed."); + DEBUG_PORT << "\n"; + } + #endif + + DEBUG_PORT << "\nGPS quiet time is assumed to begin after a "; + DEBUG_PORT << gps.string_for( LAST_SENTENCE_IN_INTERVAL ); + DEBUG_PORT << " sentence is received.\n" + " You should confirm this with NMEAorder.ino\n"; + DEBUG_PORT << "\n"; + + GpsPort gps_port = GpsPort(usbDev, speed); + + trace_header( DEBUG_PORT ); + + return gps_port; +} + +//-------------------------- + +int main(int argc, char *argv[]) { + auto dev = argc >= 2 ? argv[1] : nullptr; + auto speed = argc >=3 ? argv[2] : nullptr; + + auto gps_port = setup(dev, speed); + for (;;) { + GPSloop(gps_port); + } + return 0; +} diff --git a/tests/FakeGPS/FakeContent.h b/tests/FakeGPS/FakeContent.h new file mode 100644 index 0000000..c45b427 --- /dev/null +++ b/tests/FakeGPS/FakeContent.h @@ -0,0 +1,3 @@ +#pragma once + +#include "fake_contents/FakeContent.internet_sample.h" diff --git a/tests/FakeGPS/FakeGPS.h b/tests/FakeGPS/FakeGPS.h new file mode 100644 index 0000000..ca64792 --- /dev/null +++ b/tests/FakeGPS/FakeGPS.h @@ -0,0 +1,4 @@ +#pragma once + +#include "FakeGPS.header.h" +#include "FakeGPS.impl.h" diff --git a/tests/FakeGPS/FakeGPS.header.h b/tests/FakeGPS/FakeGPS.header.h new file mode 100644 index 0000000..37ac311 --- /dev/null +++ b/tests/FakeGPS/FakeGPS.header.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +class FakeGPS { +private: + const char* _fakeContent; + bool _repeat; + std::time_t _next_char_ts; + +public: + FakeGPS(const char* fakeOutput, bool repeat); + bool available(); + char read(); + void print(char); +}; + diff --git a/tests/FakeGPS/FakeGPS.impl.h b/tests/FakeGPS/FakeGPS.impl.h new file mode 100644 index 0000000..563e5f5 --- /dev/null +++ b/tests/FakeGPS/FakeGPS.impl.h @@ -0,0 +1,38 @@ +#pragma once + +#include "FakeGPS.header.h" + +#include +#include + + +FakeGPS::FakeGPS(const char* fakeContent, bool repeat) + : _fakeContent(fakeContent), _repeat(repeat), _next_char_ts(0) {} + +bool FakeGPS::available() { + return _next_char_ts > 0 && _next_char_ts <= std::time( 0 ); +} + + +char FakeGPS::read() { + static int runner = 0; + static int len = strlen(_fakeContent); + + char c = _fakeContent[runner]; + runner = (runner + 1) % len; + + if (c == '\n') { + if (!_repeat && runner == 0) { + _next_char_ts = -1; + } else { + _next_char_ts = std::time( 0 ) + 1; + } + } + + return c; +} + +void FakeGPS::print(char c) { + (void) c; + return; +} diff --git a/tests/FakeGPS/fake_contents/FakeContent.internet_sample.h b/tests/FakeGPS/fake_contents/FakeContent.internet_sample.h new file mode 100644 index 0000000..3075b58 --- /dev/null +++ b/tests/FakeGPS/fake_contents/FakeContent.internet_sample.h @@ -0,0 +1,17 @@ +#pragma once + +namespace fake_gps_content { + + static const char * INTERNET_SAMPLE = + "$GPRMC,162254.00,A,3723.02837,N,12159.39853,W,0.820,188.36,110706,,,A*74\r\n" + "$GPVTG,188.36,T,,M,0.820,N,1.519,K,A*3F\r\n" + "$GPGGA,162254.00,3723.02837,N,12159.39853,W,1,03,2.36,525.6,M,-25.6,M,,*65\r\n" + "$GPGSA,A,2,25,01,22,,,,,,,,,,2.56,2.36,1.00*02\r\n" + "$GPGSV,4,1,14,25,15,175,30,14,80,041,,19,38,259,14,01,52,223,18*76\r\n" + "$GPGSV,4,2,14,18,16,079,,11,19,312,,14,80,041,,21,04,135,25*7D\r\n" + "$GPGSV,4,3,14,15,27,134,18,03,25,222,,22,51,057,16,09,07,036,*79\r\n" + "$GPGSV,4,4,14,07,01,181,,15,25,135,*76\r\n" + "$GPGLL,3723.02837,N,12159.39853,W,162254.00,A,A*7C\r\n" + "$GPZDA,162254.00,11,07,2006,00,00*63\r\n"; + +} diff --git a/tests/FakeGPS/platform.h b/tests/FakeGPS/platform.h new file mode 100644 index 0000000..eeffc27 --- /dev/null +++ b/tests/FakeGPS/platform.h @@ -0,0 +1,32 @@ +#pragma once + +#ifndef NEO_GPS_PRINT + #include + #include + + #define NEO_GPS_PRINT decltype(std::cout) + + #ifdef USE_FLOAT + void printFloat( NEO_GPS_PRINT & io, float f, uint8_t decPlaces ) { + std::streamsize ss = std::cout.precision(); + io << std::setprecision(decPlaces) << std::fixed << f << std::setprecision(ss); + } + #endif +#endif + +#ifndef NEO_GPS_STREAM + #include "FakeGPS.header.h" + #define NEO_GPS_STREAM GpsPort +#endif + +#ifndef NEO_GPS_SYSTEM + #define NEO_GPS_SYSTEM System + + class System { + public: + static void lock() {} + static void unlock() {} + }; +#endif + + diff --git a/tests/NMEA/NMEA.cpp b/tests/NMEA/NMEA.cpp new file mode 100644 index 0000000..e8d7f44 --- /dev/null +++ b/tests/NMEA/NMEA.cpp @@ -0,0 +1,154 @@ +//====================================================================== +// Description: This program uses the fix-oriented methods available() and +// read() to handle complete fix structures. +// +// When the last character of the LAST_SENTENCE_IN_INTERVAL (see NMEAGPS_cfg.h) +// is decoded, a completed fix structure becomes available and is returned +// from read(). The new fix is saved the 'fix_data' structure, and can be used +// anywhere, at any time. +// +// If no messages are enabled in NMEAGPS_cfg.h, or +// no 'gps_fix' members are enabled in GPSfix_cfg.h, no information will be +// parsed, copied or printed. +// +// Prerequisites: +// 1) Your GPS device has been correctly powered. +// 2) Your GPS device is correctly connected using a serial adapter. +// By default /dev/ttyUSB0 is used. +// 3) You know the default baud rate of your GPS device. +// By default 9600 is assumed. If this doesn't work change it in serial.cpp +// 4) LAST_SENTENCE_IN_INTERVAL is defined to be the sentence that is +// sent *last* in each update interval (usually once per second). +// The default is NMEAGPS::NMEA_RMC (see NMEAGPS_cfg.h). Other +// programs may need to use the sentence identified by NMEAorder.ino. +// 5) NMEAGPS_RECOGNIZE_ALL is defined in NMEAGPS_cfg.h +// +//====================================================================== + +//------------------------------------------------------------ +// For the NeoGPS example programs, "Streamers" is common set +// of printing and formatting routines for GPS data, in a +// Comma-Separated Values text format (aka CSV). The CSV +// data will be printed to the "debug output device". +// If you don't need these formatters, simply delete this section. + +// platform.h must be included before NMEAGPS.h +#include + +#include +#include + +#include + +#include + +//------------------------------------------------------------ +// This object parses received characters +// into the gps.fix() data structure + +static NMEAGPS gps; + +//------------------------------------------------------------ +// Define a set of GPS fix information. It will +// hold on to the various pieces as they are received from +// an RMC sentence. It can be used anywhere in your sketch. + +static gps_fix fix_data; + +//---------------------------------------------------------------- +// This function gets called about once per second, during the GPS +// quiet time. It's the best place to do anything that might take +// a while: print a bunch of things, write to SD, send an SMS, etc. +// +// By doing the "hard" work during the quiet time, the CPU can get back to +// reading the GPS chars as they come in, so that no chars are lost. + +static auto & DEBUG_PORT = std::cout; + +static void doSomeWork() +{ + // Print all the things! + + trace_all( DEBUG_PORT, gps, fix_data ); + +} // doSomeWork + +//------------------------------------ +// This is the main GPS parsing loop. + +static void GPSloop(GpsPort gps_port) +{ + while (gps.available( gps_port )) { + fix_data = gps.read(); + doSomeWork(); + } + +} // GPSloop + +//-------------------------- + +GpsPort setup(const char * usbDev, const char * speed) +{ + // Start the normal trace output + DEBUG_PORT << "NMEA: started\n"; + DEBUG_PORT << " fix object size = "; + DEBUG_PORT << (uint32_t)sizeof(gps.fix()); + DEBUG_PORT << "\n gps object size = "; + DEBUG_PORT << (uint32_t)sizeof(gps); + DEBUG_PORT << "\nLooking for GPS device on "; + DEBUG_PORT << ( usbDev == nullptr ? "default" : usbDev ); + DEBUG_PORT << " with speed "; + DEBUG_PORT << ( speed == nullptr ? "default" : speed ); + + #ifndef NMEAGPS_RECOGNIZE_ALL + #error You must define NMEAGPS_RECOGNIZE_ALL in NMEAGPS_cfg.h! + #endif + + #ifdef NMEAGPS_INTERRUPT_PROCESSING + #error You must *NOT* define NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h! + #endif + + #if !defined( NMEAGPS_PARSE_GGA ) & !defined( NMEAGPS_PARSE_GLL ) & \ + !defined( NMEAGPS_PARSE_GSA ) & !defined( NMEAGPS_PARSE_GSV ) & \ + !defined( NMEAGPS_PARSE_RMC ) & !defined( NMEAGPS_PARSE_VTG ) & \ + !defined( NMEAGPS_PARSE_ZDA ) & !defined( NMEAGPS_PARSE_GST ) + + DEBUG_PORT << ( F("\nWARNING: No NMEA sentences are enabled: no fix data will be displayed.\n") ); + + #else + if (gps.merging == NMEAGPS::NO_MERGING) { + DEBUG_PORT << F("\nWARNING: displaying data from "); + DEBUG_PORT << gps.string_for( LAST_SENTENCE_IN_INTERVAL ); + DEBUG_PORT << F(" sentences ONLY, and only if "); + DEBUG_PORT << gps.string_for( LAST_SENTENCE_IN_INTERVAL ); + DEBUG_PORT << F(" is enabled.\n" + " Other sentences may be parsed, but their data will not be displayed."); + DEBUG_PORT << "\n"; + } + #endif + + DEBUG_PORT << "\nGPS quiet time is assumed to begin after a "; + DEBUG_PORT << gps.string_for( LAST_SENTENCE_IN_INTERVAL ); + DEBUG_PORT << " sentence is received.\n" + " You should confirm this with NMEAorder.ino\n"; + DEBUG_PORT << "\n"; + + GpsPort gps_port = GpsPort(usbDev, speed); + + trace_header( DEBUG_PORT ); + + return gps_port; +} + +//-------------------------- + +int main(int argc, char *argv[]) { + auto dev = argc >= 2 ? argv[1] : nullptr; + auto speed = argc >=3 ? argv[2] : nullptr; + + auto gps_port = setup(dev, speed); + for (;;) { + GPSloop(gps_port); + } + return 0; +} diff --git a/tests/NMEA/a.out b/tests/NMEA/a.out new file mode 100755 index 0000000000000000000000000000000000000000..921c18571efab5b49edf384f25134ed0d2e5e9fe GIT binary patch literal 47672 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 G)c!xg+phlr literal 0 HcmV?d00001 diff --git a/tests/NMEA/build.dummy.txt b/tests/NMEA/build.dummy.txt new file mode 100644 index 0000000..5d1560e --- /dev/null +++ b/tests/NMEA/build.dummy.txt @@ -0,0 +1 @@ +g++ -flto -g -Wall ../../../src/DMS.cpp ../../../src/GPSTime.cpp ../../../src/Location.cpp ../../../src/NeoTime.cpp ../../../src/NMEAGPS.cpp ../GpsPort.dummy.cpp ../Print.cpp NMEA.cpp ../serial.cpp -I ../ -I ../../../src diff --git a/tests/NMEA/build.txt b/tests/NMEA/build.txt new file mode 100644 index 0000000..aebc237 --- /dev/null +++ b/tests/NMEA/build.txt @@ -0,0 +1 @@ +g++ -flto -Wall ../../../src/DMS.cpp ../../../src/GPSTime.cpp ../../../src/Location.cpp ../../../src/NeoTime.cpp ../../../src/NMEAGPS.cpp ../GpsPort.cpp ../Print.cpp NMEA.cpp ../serial.cpp -I ../ -I ../../../src From 71fa71309e2042dac7433dc5c8c1446e7f7f3b73 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Tue, 19 Sep 2017 11:11:27 +0200 Subject: [PATCH 17/38] feat: add deprecated when using default impl --- src/DMS.header.h | 4 +- src/NMEAGPS.header.h | 8 +- src/NMEAGPSprivate.h | 4 +- src/NeoTime.header.h | 2 +- src/Streamers.header.h | 7 +- src/platforms/Print.h | 8 ++ src/platforms/Stream.h | 8 ++ src/platforms/System.h | 8 ++ .../FakeGPS/{FakeContent.h => FakeContents.h} | 0 tests/FakeGPS/FakeGPS.h | 1 + tests/FakeGPS/FakeGPS.impl.h | 5 +- tests/FakeGPS/platform.h | 5 +- tests/NMEA/NMEA.cpp | 73 ++----------------- 13 files changed, 52 insertions(+), 81 deletions(-) rename tests/FakeGPS/{FakeContent.h => FakeContents.h} (100%) diff --git a/src/DMS.header.h b/src/DMS.header.h index 5a996c6..0f24b63 100644 --- a/src/DMS.header.h +++ b/src/DMS.header.h @@ -46,10 +46,10 @@ class DMS_t void From( int32_t deg_1E7 ); // Print DMS as the funky NMEA DDDMM.mmmm format - void printDDDMMmmmm( NEO_GPS_PRINT & outs ) const; + void printDDDMMmmmm( NEO_GPS_PRINT & outs ) const NEO_GPS_PRINT_DEFAULT_IMPL_WARN; } NEOGPS_PACKED; -extern NEO_GPS_PRINT & operator << ( NEO_GPS_PRINT & outs, const DMS_t & ); +NEO_GPS_PRINT & operator << ( NEO_GPS_PRINT & outs, const DMS_t & ) NEO_GPS_PRINT_DEFAULT_IMPL_WARN; #endif diff --git a/src/NMEAGPS.header.h b/src/NMEAGPS.header.h index 1daa73f..b76055c 100644 --- a/src/NMEAGPS.header.h +++ b/src/NMEAGPS.header.h @@ -107,7 +107,7 @@ class NMEAGPS // are available to be "read" from the fix buffer. The GPS port // object is passed in so a char can be read if port.available(). - uint8_t available( NEO_GPS_STREAM & port ) + uint8_t available( NEO_GPS_STREAM & port ) NEO_GPS_STREAM_DEFAULT_IMPL_WARN { if (processing_style == PS_POLLING) while (port.available()) @@ -320,14 +320,14 @@ class NMEAGPS //....................................................................... // Request the specified NMEA sentence. Not all devices will respond. - static void poll( NEO_GPS_STREAM *device, nmea_msg_t msg ); + static void poll( NEO_GPS_STREAM *device, nmea_msg_t msg ) NEO_GPS_STREAM_DEFAULT_IMPL_WARN; //....................................................................... // Send a message to the GPS device. // The '$' is optional, and the '*' and CS will be added automatically. - static void send( NEO_GPS_STREAM *device, const char *msg ); - static void send_P( NEO_GPS_STREAM *device, const __FlashStringHelper *msg ); + static void send( NEO_GPS_STREAM *device, const char *msg ) NEO_GPS_STREAM_DEFAULT_IMPL_WARN; + static void send_P( NEO_GPS_STREAM *device, const __FlashStringHelper *msg ) NEO_GPS_STREAM_DEFAULT_IMPL_WARN; #include "NMEAGPSprivate.h" diff --git a/src/NMEAGPSprivate.h b/src/NMEAGPSprivate.h index 1449487..d6abe33 100644 --- a/src/NMEAGPSprivate.h +++ b/src/NMEAGPSprivate.h @@ -89,13 +89,13 @@ // Control access to this object. This preserves atomicity when // the processing style is interrupt-driven. - void lock() const + void lock() const NEO_GPS_SYSTEM_DEFAULT_IMPL_WARN { if (processing_style == PS_INTERRUPT) NEO_GPS_SYSTEM::lock(); } - void unlock() const + void unlock() const NEO_GPS_SYSTEM_DEFAULT_IMPL_WARN { if (processing_style == PS_INTERRUPT) NEO_GPS_SYSTEM::unlock(); diff --git a/src/NeoTime.header.h b/src/NeoTime.header.h index 911d45e..0d59603 100644 --- a/src/NeoTime.header.h +++ b/src/NeoTime.header.h @@ -299,6 +299,6 @@ struct time_t { * @param[in] t time structure. * @return iostream. */ -NEO_GPS_PRINT & operator <<( NEO_GPS_PRINT & outs, const NeoGPS::time_t &t ); +NEO_GPS_PRINT & operator <<( NEO_GPS_PRINT & outs, const NeoGPS::time_t &t ) NEO_GPS_PRINT_DEFAULT_IMPL_WARN; #endif diff --git a/src/Streamers.header.h b/src/Streamers.header.h index e82690f..43144a4 100644 --- a/src/Streamers.header.h +++ b/src/Streamers.header.h @@ -31,9 +31,10 @@ * @param[in] fix gps_fix instance. * @return The outs object. */ -NEO_GPS_PRINT & operator <<( NEO_GPS_PRINT &outs, const gps_fix &fix ); +NEO_GPS_PRINT & operator <<( NEO_GPS_PRINT & outs, const gps_fix &fix ) NEO_GPS_PRINT_DEFAULT_IMPL_WARN; -extern void trace_header( NEO_GPS_PRINT & outs ); -extern void trace_all( NEO_GPS_PRINT & outs, const NMEAGPS &gps, const gps_fix &fix ); +void trace_header( NEO_GPS_PRINT & outs ) NEO_GPS_PRINT_DEFAULT_IMPL_WARN; + +void trace_all( NEO_GPS_PRINT & outs, const NMEAGPS &gps, const gps_fix &fix ) NEO_GPS_PRINT_DEFAULT_IMPL_WARN; #include diff --git a/src/platforms/Print.h b/src/platforms/Print.h index a4c6a1b..cdb711b 100644 --- a/src/platforms/Print.h +++ b/src/platforms/Print.h @@ -4,6 +4,10 @@ #ifndef NEO_GPS_PRINT #define NEO_GPS_PRINT NeoGPS::Print + #ifdef __GNUC__ + #define NEO_GPS_PRINT_DEFAULT_IMPL_WARN \ + __attribute__((deprecated("You are using a function which uses NEO_GPS_PRINT with the default implementation, which does nothing!"))) + #endif /** * This file implements a non working dummy implemenation for Print @@ -26,3 +30,7 @@ namespace NeoGPS { } #endif + +#ifndef NEO_GPS_PRINT_DEFAULT_IMPL_WARN + #define NEO_GPS_PRINT_DEFAULT_IMPL_WARN +#endif diff --git a/src/platforms/Stream.h b/src/platforms/Stream.h index 11872a7..4dff4c9 100644 --- a/src/platforms/Stream.h +++ b/src/platforms/Stream.h @@ -2,6 +2,10 @@ #ifndef NEO_GPS_STREAM #define NEO_GPS_STREAM NeoGPS::Stream + #ifdef __GNUC__ + #define NEO_GPS_STREAM_DEFAULT_IMPL_WARN \ + __attribute__((deprecated("You are using a function which uses NEO_GPS_STREAM with the default implementation, which does nothing!"))) + #endif /** * This file implements a non working dummy implementation for Stream. @@ -16,3 +20,7 @@ namespace NeoGPS { }; } #endif + +#ifndef NEO_GPS_STREAM_DEFAULT_IMPL_WARN + #define NEO_GPS_STREAM_DEFAULT_IMPL_WARN +#endif diff --git a/src/platforms/System.h b/src/platforms/System.h index 58495d2..dd935bf 100644 --- a/src/platforms/System.h +++ b/src/platforms/System.h @@ -2,6 +2,10 @@ #ifndef NEO_GPS_SYSTEM #define NEO_GPS_SYSTEM NeoGPS::System + #ifdef __GNUC__ + #define NEO_GPS_SYSTEM_DEFAULT_IMPL_WARN \ + __attribute__((deprecated("You are using a function which uses NEO_GPS_SYSTEM with the default implementation, which does nothing!"))) + #endif /** * This file implements a non working dummy implementation for interrupts and noInterrupts. @@ -15,3 +19,7 @@ namespace NeoGPS { }; } #endif + +#ifndef NEO_GPS_SYSTEM_DEFAULT_IMPL_WARN + #define NEO_GPS_SYSTEM_DEFAULT_IMPL_WARN +#endif diff --git a/tests/FakeGPS/FakeContent.h b/tests/FakeGPS/FakeContents.h similarity index 100% rename from tests/FakeGPS/FakeContent.h rename to tests/FakeGPS/FakeContents.h diff --git a/tests/FakeGPS/FakeGPS.h b/tests/FakeGPS/FakeGPS.h index ca64792..02da3e4 100644 --- a/tests/FakeGPS/FakeGPS.h +++ b/tests/FakeGPS/FakeGPS.h @@ -1,4 +1,5 @@ #pragma once +#include "FakeContents.h" #include "FakeGPS.header.h" #include "FakeGPS.impl.h" diff --git a/tests/FakeGPS/FakeGPS.impl.h b/tests/FakeGPS/FakeGPS.impl.h index 563e5f5..5b60e4b 100644 --- a/tests/FakeGPS/FakeGPS.impl.h +++ b/tests/FakeGPS/FakeGPS.impl.h @@ -10,7 +10,9 @@ FakeGPS::FakeGPS(const char* fakeContent, bool repeat) : _fakeContent(fakeContent), _repeat(repeat), _next_char_ts(0) {} bool FakeGPS::available() { - return _next_char_ts > 0 && _next_char_ts <= std::time( 0 ); + //std::cout << "_next_char_ts: " << _next_char_ts << " std::time( 0 ): " << std::time( 0 ) << std::endl; + //std::cout << "available: " << (_next_char_ts >= 0 && _next_char_ts <= std::time( 0 )) << std::endl; + return _next_char_ts >= 0 && _next_char_ts <= std::time( 0 ); } @@ -29,6 +31,7 @@ char FakeGPS::read() { } } + //std::cout << c; return c; } diff --git a/tests/FakeGPS/platform.h b/tests/FakeGPS/platform.h index eeffc27..826c661 100644 --- a/tests/FakeGPS/platform.h +++ b/tests/FakeGPS/platform.h @@ -1,5 +1,5 @@ #pragma once - +/* #ifndef NEO_GPS_PRINT #include #include @@ -13,10 +13,11 @@ } #endif #endif +*/ #ifndef NEO_GPS_STREAM #include "FakeGPS.header.h" - #define NEO_GPS_STREAM GpsPort + #define NEO_GPS_STREAM FakeGPS #endif #ifndef NEO_GPS_SYSTEM diff --git a/tests/NMEA/NMEA.cpp b/tests/NMEA/NMEA.cpp index e8d7f44..30cd61c 100644 --- a/tests/NMEA/NMEA.cpp +++ b/tests/NMEA/NMEA.cpp @@ -33,9 +33,8 @@ // If you don't need these formatters, simply delete this section. // platform.h must be included before NMEAGPS.h -#include - -#include +#include +#include #include #include @@ -76,9 +75,9 @@ static void doSomeWork() //------------------------------------ // This is the main GPS parsing loop. -static void GPSloop(GpsPort gps_port) +static void GPSloop(FakeGPS & fakeGPS) { - while (gps.available( gps_port )) { + while (gps.available( fakeGPS )) { fix_data = gps.read(); doSomeWork(); } @@ -87,68 +86,10 @@ static void GPSloop(GpsPort gps_port) //-------------------------- -GpsPort setup(const char * usbDev, const char * speed) -{ - // Start the normal trace output - DEBUG_PORT << "NMEA: started\n"; - DEBUG_PORT << " fix object size = "; - DEBUG_PORT << (uint32_t)sizeof(gps.fix()); - DEBUG_PORT << "\n gps object size = "; - DEBUG_PORT << (uint32_t)sizeof(gps); - DEBUG_PORT << "\nLooking for GPS device on "; - DEBUG_PORT << ( usbDev == nullptr ? "default" : usbDev ); - DEBUG_PORT << " with speed "; - DEBUG_PORT << ( speed == nullptr ? "default" : speed ); - - #ifndef NMEAGPS_RECOGNIZE_ALL - #error You must define NMEAGPS_RECOGNIZE_ALL in NMEAGPS_cfg.h! - #endif - - #ifdef NMEAGPS_INTERRUPT_PROCESSING - #error You must *NOT* define NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h! - #endif - - #if !defined( NMEAGPS_PARSE_GGA ) & !defined( NMEAGPS_PARSE_GLL ) & \ - !defined( NMEAGPS_PARSE_GSA ) & !defined( NMEAGPS_PARSE_GSV ) & \ - !defined( NMEAGPS_PARSE_RMC ) & !defined( NMEAGPS_PARSE_VTG ) & \ - !defined( NMEAGPS_PARSE_ZDA ) & !defined( NMEAGPS_PARSE_GST ) - - DEBUG_PORT << ( F("\nWARNING: No NMEA sentences are enabled: no fix data will be displayed.\n") ); - - #else - if (gps.merging == NMEAGPS::NO_MERGING) { - DEBUG_PORT << F("\nWARNING: displaying data from "); - DEBUG_PORT << gps.string_for( LAST_SENTENCE_IN_INTERVAL ); - DEBUG_PORT << F(" sentences ONLY, and only if "); - DEBUG_PORT << gps.string_for( LAST_SENTENCE_IN_INTERVAL ); - DEBUG_PORT << F(" is enabled.\n" - " Other sentences may be parsed, but their data will not be displayed."); - DEBUG_PORT << "\n"; - } - #endif - - DEBUG_PORT << "\nGPS quiet time is assumed to begin after a "; - DEBUG_PORT << gps.string_for( LAST_SENTENCE_IN_INTERVAL ); - DEBUG_PORT << " sentence is received.\n" - " You should confirm this with NMEAorder.ino\n"; - DEBUG_PORT << "\n"; - - GpsPort gps_port = GpsPort(usbDev, speed); - - trace_header( DEBUG_PORT ); - - return gps_port; -} - -//-------------------------- - -int main(int argc, char *argv[]) { - auto dev = argc >= 2 ? argv[1] : nullptr; - auto speed = argc >=3 ? argv[2] : nullptr; - - auto gps_port = setup(dev, speed); +int main() { + auto fakeGPS = FakeGPS(fake_gps_content::INTERNET_SAMPLE, true); for (;;) { - GPSloop(gps_port); + GPSloop(fakeGPS); } return 0; } From 5c2dd1121f61ea320fd753c554ea640181104fb2 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Tue, 19 Sep 2017 11:37:00 +0200 Subject: [PATCH 18/38] feat: add ctype for isdigit. switch to ms in fakegps --- src/NMEAGPS.header.h | 1 + src/NMEAGPS.impl.h | 2 +- tests/FakeGPS/FakeGPS.header.h | 2 +- tests/FakeGPS/FakeGPS.impl.h | 24 ++++++++++++++++-------- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/NMEAGPS.header.h b/src/NMEAGPS.header.h index b76055c..29f9c68 100644 --- a/src/NMEAGPS.header.h +++ b/src/NMEAGPS.header.h @@ -22,6 +22,7 @@ #include "GPSfix.h" #include "NMEAGPS_cfg.h" +#include //------------------------------------------------------ // diff --git a/src/NMEAGPS.impl.h b/src/NMEAGPS.impl.h index e6f423c..35123d5 100644 --- a/src/NMEAGPS.impl.h +++ b/src/NMEAGPS.impl.h @@ -1498,7 +1498,7 @@ bool NMEAGPS::parseDDDMM done = true; - } else if (validateChars() && !( chr >= '0' && chr <= '9' )) { + } else if (validateChars() && !isdigit(chr)) { sentenceInvalid(); } else if (!decimal) { diff --git a/tests/FakeGPS/FakeGPS.header.h b/tests/FakeGPS/FakeGPS.header.h index 37ac311..7403f4f 100644 --- a/tests/FakeGPS/FakeGPS.header.h +++ b/tests/FakeGPS/FakeGPS.header.h @@ -6,7 +6,7 @@ class FakeGPS { private: const char* _fakeContent; bool _repeat; - std::time_t _next_char_ts; + struct timeval _next_char_tv; public: FakeGPS(const char* fakeOutput, bool repeat); diff --git a/tests/FakeGPS/FakeGPS.impl.h b/tests/FakeGPS/FakeGPS.impl.h index 5b60e4b..c86c789 100644 --- a/tests/FakeGPS/FakeGPS.impl.h +++ b/tests/FakeGPS/FakeGPS.impl.h @@ -2,17 +2,22 @@ #include "FakeGPS.header.h" -#include #include +#include FakeGPS::FakeGPS(const char* fakeContent, bool repeat) - : _fakeContent(fakeContent), _repeat(repeat), _next_char_ts(0) {} + : _fakeContent(fakeContent), _repeat(repeat) { + _next_char_tv.tv_sec = 1; // 0 is our stop condition + _next_char_tv.tv_usec = 0; + } bool FakeGPS::available() { - //std::cout << "_next_char_ts: " << _next_char_ts << " std::time( 0 ): " << std::time( 0 ) << std::endl; - //std::cout << "available: " << (_next_char_ts >= 0 && _next_char_ts <= std::time( 0 )) << std::endl; - return _next_char_ts >= 0 && _next_char_ts <= std::time( 0 ); + struct timeval now; + gettimeofday(&now, NULL); + return _next_char_tv.tv_sec > 0 && + _next_char_tv.tv_sec <= now.tv_sec && + _next_char_tv.tv_usec <= now.tv_usec; } @@ -25,13 +30,16 @@ char FakeGPS::read() { if (c == '\n') { if (!_repeat && runner == 0) { - _next_char_ts = -1; + _next_char_tv.tv_sec = 0; } else { - _next_char_ts = std::time( 0 ) + 1; + _next_char_tv.tv_usec += 100000; + if (_next_char_tv.tv_usec > 1000000) { + _next_char_tv.tv_usec -= 1000000; + ++_next_char_tv.tv_sec; + } } } - //std::cout << c; return c; } From aff5dd9bf0709e58f72a542cb68ca5a9fe40be56 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Tue, 19 Sep 2017 11:43:43 +0200 Subject: [PATCH 19/38] fix: use correct initial time for next tv in fakegps --- tests/FakeGPS/FakeGPS.impl.h | 9 +++++---- tests/FakeGPS/platform.h | 3 +-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/FakeGPS/FakeGPS.impl.h b/tests/FakeGPS/FakeGPS.impl.h index c86c789..6957e3c 100644 --- a/tests/FakeGPS/FakeGPS.impl.h +++ b/tests/FakeGPS/FakeGPS.impl.h @@ -8,16 +8,16 @@ FakeGPS::FakeGPS(const char* fakeContent, bool repeat) : _fakeContent(fakeContent), _repeat(repeat) { - _next_char_tv.tv_sec = 1; // 0 is our stop condition - _next_char_tv.tv_usec = 0; + gettimeofday(&_next_char_tv, NULL); } bool FakeGPS::available() { struct timeval now; gettimeofday(&now, NULL); return _next_char_tv.tv_sec > 0 && - _next_char_tv.tv_sec <= now.tv_sec && - _next_char_tv.tv_usec <= now.tv_usec; + (_next_char_tv.tv_sec < now.tv_sec || + (_next_char_tv.tv_sec == now.tv_sec && + _next_char_tv.tv_usec <= now.tv_usec)); } @@ -33,6 +33,7 @@ char FakeGPS::read() { _next_char_tv.tv_sec = 0; } else { _next_char_tv.tv_usec += 100000; + if (_next_char_tv.tv_usec > 1000000) { _next_char_tv.tv_usec -= 1000000; ++_next_char_tv.tv_sec; diff --git a/tests/FakeGPS/platform.h b/tests/FakeGPS/platform.h index 826c661..60ebd71 100644 --- a/tests/FakeGPS/platform.h +++ b/tests/FakeGPS/platform.h @@ -1,5 +1,5 @@ #pragma once -/* + #ifndef NEO_GPS_PRINT #include #include @@ -13,7 +13,6 @@ } #endif #endif -*/ #ifndef NEO_GPS_STREAM #include "FakeGPS.header.h" From b8082fce9e53cb3a587206555307ef367e89c0c8 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Tue, 19 Sep 2017 22:39:46 +0200 Subject: [PATCH 20/38] fix: revert NMEAGPS_cfg.h to upstream --- src/NMEAGPS_cfg.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/NMEAGPS_cfg.h b/src/NMEAGPS_cfg.h index 9fe8429..c20bdef 100644 --- a/src/NMEAGPS_cfg.h +++ b/src/NMEAGPS_cfg.h @@ -31,13 +31,13 @@ // 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_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 +//#define NMEAGPS_PARSE_VTG +//#define NMEAGPS_PARSE_ZDA //------------------------------------------------------ // Select which sentence is sent *last* by your GPS device @@ -206,8 +206,8 @@ // optionally, all the info for each satellite. // -#define NMEAGPS_PARSE_SATELLITES -#define NMEAGPS_PARSE_SATELLITE_INFO +//#define NMEAGPS_PARSE_SATELLITES +//#define NMEAGPS_PARSE_SATELLITE_INFO #ifdef NMEAGPS_PARSE_SATELLITES #define NMEAGPS_MAX_SATELLITES (20) @@ -335,4 +335,4 @@ #error You cannot enable both TIMESTAMP_FROM_INTERVAL and PPS in NMEAGPS_cfg.h! #endif -#endif +#endif \ No newline at end of file From 5facb6c2d0e3a7b68a282bb207ddd1c2136a6cb2 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Tue, 19 Sep 2017 22:40:20 +0200 Subject: [PATCH 21/38] fix: cast uint_t to int before printing (<<) std::cout treats uint_t like chars --- src/NeoTime.impl.h | 10 +++++----- src/Streamers.header.h | 2 -- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/NeoTime.impl.h b/src/NeoTime.impl.h index f428f85..396c116 100644 --- a/src/NeoTime.impl.h +++ b/src/NeoTime.impl.h @@ -30,19 +30,19 @@ NEO_GPS_PRINT & operator<<( NEO_GPS_PRINT& outs, const NeoGPS::time_t& t ) outs << t.full_year( t.year ); outs << '-'; if (t.month < 10) outs << '0'; - outs << t.month; + outs << (int) t.month; outs << '-'; if (t.date < 10) outs << '0'; - outs << t.date; + outs << (int) t.date; outs << ' '; if (t.hours < 10) outs << '0'; - outs << t.hours; + outs << (int) t.hours; outs << ':'; if (t.minutes < 10) outs << '0'; - outs << t.minutes; + outs << (int) t.minutes; outs << ':'; if (t.seconds < 10) outs << '0'; - outs << t.seconds; + outs << (int) t.seconds; return outs; } diff --git a/src/Streamers.header.h b/src/Streamers.header.h index 43144a4..69bba31 100644 --- a/src/Streamers.header.h +++ b/src/Streamers.header.h @@ -36,5 +36,3 @@ NEO_GPS_PRINT & operator <<( NEO_GPS_PRINT & outs, const gps_fix &fix ) NEO_GPS_ void trace_header( NEO_GPS_PRINT & outs ) NEO_GPS_PRINT_DEFAULT_IMPL_WARN; void trace_all( NEO_GPS_PRINT & outs, const NMEAGPS &gps, const gps_fix &fix ) NEO_GPS_PRINT_DEFAULT_IMPL_WARN; - -#include From d6ae9adc59a5d396c4ba5a11296d65a92a775340 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Tue, 19 Sep 2017 22:41:21 +0200 Subject: [PATCH 22/38] feat: integrate latest changes from NMEA.ino into tests/NMEA.cpp --- tests/NMEA/NMEA.cpp | 51 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/tests/NMEA/NMEA.cpp b/tests/NMEA/NMEA.cpp index 30cd61c..45347e7 100644 --- a/tests/NMEA/NMEA.cpp +++ b/tests/NMEA/NMEA.cpp @@ -4,7 +4,7 @@ // // When the last character of the LAST_SENTENCE_IN_INTERVAL (see NMEAGPS_cfg.h) // is decoded, a completed fix structure becomes available and is returned -// from read(). The new fix is saved the 'fix_data' structure, and can be used +// from read(). The new fix is saved the 'fix' structure, and can be used // anywhere, at any time. // // If no messages are enabled in NMEAGPS_cfg.h, or @@ -52,7 +52,7 @@ static NMEAGPS gps; // hold on to the various pieces as they are received from // an RMC sentence. It can be used anywhere in your sketch. -static gps_fix fix_data; +static gps_fix fix; //---------------------------------------------------------------- // This function gets called about once per second, during the GPS @@ -68,7 +68,7 @@ static void doSomeWork() { // Print all the things! - trace_all( DEBUG_PORT, gps, fix_data ); + trace_all( DEBUG_PORT, gps, fix ); } // doSomeWork @@ -78,7 +78,7 @@ static void doSomeWork() static void GPSloop(FakeGPS & fakeGPS) { while (gps.available( fakeGPS )) { - fix_data = gps.read(); + fix = gps.read(); doSomeWork(); } @@ -86,7 +86,50 @@ static void GPSloop(FakeGPS & fakeGPS) //-------------------------- +void outputHeader() +{ + DEBUG_PORT << "NMEA.cpp: started" << std::endl; + DEBUG_PORT << " fix object size = " << sizeof(gps.fix()) << std::endl; + DEBUG_PORT << " gps object size = " << sizeof(gps) << std::endl; + + #ifndef NMEAGPS_RECOGNIZE_ALL + #error You must define NMEAGPS_RECOGNIZE_ALL in NMEAGPS_cfg.h! + #endif + + #ifdef NMEAGPS_INTERRUPT_PROCESSING + #error You must *NOT* define NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h! + #endif + + #if !defined( NMEAGPS_PARSE_GGA ) && !defined( NMEAGPS_PARSE_GLL ) && \ + !defined( NMEAGPS_PARSE_GSA ) && !defined( NMEAGPS_PARSE_GSV ) && \ + !defined( NMEAGPS_PARSE_RMC ) && !defined( NMEAGPS_PARSE_VTG ) && \ + !defined( NMEAGPS_PARSE_ZDA ) && !defined( NMEAGPS_PARSE_GST ) + + DEBUG_PORT << std::endl << "WARNING: No NMEA sentences are enabled: no fix data will be displayed."; + + #else + if (gps.merging == NMEAGPS::NO_MERGING) { + DEBUG_PORT << std::endl; + DEBUG_PORT << "WARNING: displaying data from " << gps.string_for( LAST_SENTENCE_IN_INTERVAL ) + << " sentences ONLY, and only if " << gps.string_for( LAST_SENTENCE_IN_INTERVAL ) + << " is enabled." << std::endl; + DEBUG_PORT << " Other sentences may be parsed, but their data will not be displayed."; + } + #endif + + DEBUG_PORT << std::endl << "GPS quiet time is assumed to begin after a " + << gps.string_for( LAST_SENTENCE_IN_INTERVAL ) + << " sentence is received." << std::endl; + DEBUG_PORT << " You should confirm this with NMEAorder.cpp" << std::endl << std::endl; + + trace_header( DEBUG_PORT ); +} + +//-------------------------- + + int main() { + outputHeader(); auto fakeGPS = FakeGPS(fake_gps_content::INTERNET_SAMPLE, true); for (;;) { GPSloop(fakeGPS); From 18c848825b25cba645dff4fbcd0caf3cdaf04f72 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Tue, 19 Sep 2017 22:43:14 +0200 Subject: [PATCH 23/38] fix: remove a.out --- tests/NMEA/a.out | Bin 47672 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 tests/NMEA/a.out diff --git a/tests/NMEA/a.out b/tests/NMEA/a.out deleted file mode 100755 index 921c18571efab5b49edf384f25134ed0d2e5e9fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47672 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 G)c!xg+phlr From 92d1ed7a9780c4b5ef39d70939e8aff72e3280f0 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Wed, 20 Sep 2017 20:07:30 +0200 Subject: [PATCH 24/38] feat: add + in front of all number prints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit if number is uint8_t std::cout will print the character (usually uint8_t is typedef'd to unsigned char. adding a + in front of the number tells << to print the number: outs << number → outs << +number --- src/DMS.impl.h | 12 +++++----- src/GPSTime.header.h | 2 +- src/NeoTime.impl.h | 12 +++++----- src/Streamers.impl.h | 46 +++++++++++++++++++-------------------- src/platforms/Print.h | 2 +- src/platforms/Stream.h | 2 +- src/platforms/System.h | 2 +- src/ublox/ubxGPS.header.h | 4 ++-- src/ublox/ubxGPS.impl.h | 24 ++++++++++---------- tests/NMEA/NMEA.cpp | 26 +++++++++------------- 10 files changed, 63 insertions(+), 69 deletions(-) diff --git a/src/DMS.impl.h b/src/DMS.impl.h index 8b53729..880b012 100644 --- a/src/DMS.impl.h +++ b/src/DMS.impl.h @@ -72,21 +72,21 @@ NEO_GPS_PRINT & operator << ( NEO_GPS_PRINT & outs, const DMS_t & dms ) { if (dms.degrees < 10) outs << '0'; - outs << dms.degrees; + outs << +dms.degrees; outs << ' '; if (dms.minutes < 10) outs << '0'; - outs << dms.minutes; + outs << +dms.minutes; outs << F("\' "); if (dms.seconds_whole < 10) outs << '0'; - outs << dms.seconds_whole; + outs << +dms.seconds_whole; outs << '.'; if (dms.seconds_frac < 100) outs << '0'; if (dms.seconds_frac < 10) outs << '0'; - outs << dms.seconds_frac; + outs << +dms.seconds_frac; outs << F("\" "); return outs; @@ -101,7 +101,7 @@ void DMS_t::printDDDMMmmmm( NEO_GPS_PRINT & outs ) const if (minutes < 10) outs << '0'; - outs << minutes; + outs << +minutes; outs << '.'; // Calculate the fractional minutes from the seconds, @@ -119,5 +119,5 @@ void DMS_t::printDDDMMmmmm( NEO_GPS_PRINT & outs ) const outs << '0'; if (mmmm < 10) outs << '0'; - outs << mmmm; + outs << +mmmm; } diff --git a/src/GPSTime.header.h b/src/GPSTime.header.h index ee771ed..1f544a4 100644 --- a/src/GPSTime.header.h +++ b/src/GPSTime.header.h @@ -73,7 +73,7 @@ class GPSTime static bool from_TOWms ( uint32_t time_of_week_ms, NeoGPS::time_t &dt, uint16_t &ms ) { -//trace << PSTR("from_TOWms(") << time_of_week_ms << PSTR("), sow = ") << start_of_week() << PSTR(", leap = ") << leap_seconds << endl; +//trace << PSTR("from_TOWms(") << +time_of_week_ms << PSTR("), sow = ") << start_of_week() << PSTR(", leap = ") << +leap_seconds << endl; bool ok = (start_of_week() != 0) && (leap_seconds != 0); if (ok) { NeoGPS::clock_t tow_s = time_of_week_ms/1000UL; diff --git a/src/NeoTime.impl.h b/src/NeoTime.impl.h index 396c116..408e187 100644 --- a/src/NeoTime.impl.h +++ b/src/NeoTime.impl.h @@ -27,22 +27,22 @@ NEO_GPS_PRINT & operator<<( NEO_GPS_PRINT& outs, const NeoGPS::time_t& t ) { - outs << t.full_year( t.year ); + outs << +t.full_year( t.year ); outs << '-'; if (t.month < 10) outs << '0'; - outs << (int) t.month; + outs << +t.month; outs << '-'; if (t.date < 10) outs << '0'; - outs << (int) t.date; + outs << +t.date; outs << ' '; if (t.hours < 10) outs << '0'; - outs << (int) t.hours; + outs << +t.hours; outs << ':'; if (t.minutes < 10) outs << '0'; - outs << (int) t.minutes; + outs << +t.minutes; outs << ':'; if (t.seconds < 10) outs << '0'; - outs << (int) t.seconds; + outs << +t.seconds; return outs; } diff --git a/src/Streamers.impl.h b/src/Streamers.impl.h index b33d54b..a3445e4 100644 --- a/src/Streamers.impl.h +++ b/src/Streamers.impl.h @@ -111,23 +111,23 @@ const char gps_fix_header[] __PROGMEM = { if (dms.degrees < 10) outs << '0'; - outs << dms.degrees << ' '; + outs << +dms.degrees << ' '; if (dms.minutes < 10) outs << '0'; - outs << dms.minutes; + outs << +dms.minutes; outs << F("\' "); if (dms.seconds_whole < 10) outs << '0'; - outs << dms.seconds_whole; + outs << +dms.seconds_whole; outs << '.'; if (dms.seconds_frac < 100) outs << '0'; if (dms.seconds_frac < 10) outs << '0'; - outs << dms.seconds_frac; + outs << +dms.seconds_frac; outs << F("\" "); } // printDMS @@ -138,7 +138,7 @@ const char gps_fix_header[] __PROGMEM = NEO_GPS_PRINT & operator <<( NEO_GPS_PRINT &outs, const gps_fix &fix ) { if (fix.valid.status) - outs << (uint8_t) fix.status; + outs << (uint) fix.status; outs << ','; #if defined(GPS_FIX_DATE) | defined(GPS_FIX_TIME) @@ -159,7 +159,7 @@ NEO_GPS_PRINT & operator <<( NEO_GPS_PRINT &outs, const gps_fix &fix ) outs << '0'; if (ms < 10) outs << '0'; - outs << ms; + outs << +ms; } outs << ','; @@ -167,7 +167,7 @@ NEO_GPS_PRINT & operator <<( NEO_GPS_PRINT &outs, const gps_fix &fix ) // Date/Time not enabled, just output the interval number static uint32_t sequence = 0L; - outs << sequence++ << ','; + outs << +sequence++ << ','; #endif @@ -253,7 +253,7 @@ NEO_GPS_PRINT & operator <<( NEO_GPS_PRINT &outs, const gps_fix &fix ) #ifdef GPS_FIX_LOCATION if (fix.valid.location) - outs << fix.latitudeL() << ',' << fix.longitudeL(); + outs << +fix.latitudeL() << ',' << +fix.longitudeL(); else outs << ','; outs << ','; @@ -272,55 +272,55 @@ NEO_GPS_PRINT & operator <<( NEO_GPS_PRINT &outs, const gps_fix &fix ) #endif #ifdef GPS_FIX_HEADING if (fix.valid.heading) - outs << fix.heading_cd(); + outs << +fix.heading_cd(); outs << ','; #endif #ifdef GPS_FIX_SPEED if (fix.valid.speed) - outs << fix.speed_mkn(); + outs << +fix.speed_mkn(); outs << ','; #endif #ifdef GPS_FIX_ALTITUDE if (fix.valid.altitude) - outs << fix.altitude_cm(); + outs << +fix.altitude_cm(); outs << ','; #endif #ifdef GPS_FIX_HDOP if (fix.valid.hdop) - outs << fix.hdop; + outs << +fix.hdop; outs << ','; #endif #ifdef GPS_FIX_VDOP if (fix.valid.vdop) - outs << fix.vdop; + outs << +fix.vdop; outs << ','; #endif #ifdef GPS_FIX_PDOP if (fix.valid.pdop) - outs << fix.pdop; + outs << +fix.pdop; outs << ','; #endif #ifdef GPS_FIX_LAT_ERR if (fix.valid.lat_err) - outs << fix.lat_err_cm; + outs << +fix.lat_err_cm; outs << ','; #endif #ifdef GPS_FIX_LON_ERR if (fix.valid.lon_err) - outs << fix.lon_err_cm; + outs << +fix.lon_err_cm; outs << ','; #endif #ifdef GPS_FIX_ALT_ERR if (fix.valid.alt_err) - outs << fix.alt_err_cm; + outs << +fix.alt_err_cm; outs << ','; #endif #ifdef GPS_FIX_GEOID_HEIGHT if (fix.valid.geoidHeight) - outs << fix.geoidHeight_cm(); + outs << +fix.geoidHeight_cm(); outs << ','; #endif @@ -328,7 +328,7 @@ NEO_GPS_PRINT & operator <<( NEO_GPS_PRINT &outs, const gps_fix &fix ) #ifdef GPS_FIX_SATELLITES if (fix.valid.satellites) - outs << fix.satellites; + outs << +fix.satellites; outs << ','; #endif @@ -371,7 +371,7 @@ void trace_all( NEO_GPS_PRINT & outs, const NMEAGPS &gps, const gps_fix &fix ) outs << fix; #if defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL) | defined(NMEAGPS_TIMESTAMP_FROM_PPS) - outs << gps.UTCsecondStart(); + outs << +gps.UTCsecondStart(); outs << ','; #endif @@ -379,14 +379,14 @@ void trace_all( NEO_GPS_PRINT & outs, const NMEAGPS &gps, const gps_fix &fix ) outs << '['; for (uint8_t i=0; i < gps.sat_count; i++) { - outs << gps.satellites[i].id; + outs << +gps.satellites[i].id; #if defined(NMEAGPS_PARSE_SATELLITE_INFO) outs << ' ' << - gps.satellites[i].elevation << '/' << gps.satellites[i].azimuth; + +gps.satellites[i].elevation << '/' << +gps.satellites[i].azimuth; outs << '@'; if (gps.satellites[i].tracked) - outs << gps.satellites[i].snr; + outs << +gps.satellites[i].snr; else outs << '-'; #endif diff --git a/src/platforms/Print.h b/src/platforms/Print.h index cdb711b..1798b6e 100644 --- a/src/platforms/Print.h +++ b/src/platforms/Print.h @@ -6,7 +6,7 @@ #define NEO_GPS_PRINT NeoGPS::Print #ifdef __GNUC__ #define NEO_GPS_PRINT_DEFAULT_IMPL_WARN \ - __attribute__((deprecated("You are using a function which uses NEO_GPS_PRINT with the default implementation, which does nothing!"))) + __attribute__((deprecated("You are using a function which uses NEO_GPS_PRINT without defining the type. Compilation will fail. To fix this #define NEO_GPS_PRINT your_print_type_t before including platform.h"))) #endif /** diff --git a/src/platforms/Stream.h b/src/platforms/Stream.h index 4dff4c9..3a64781 100644 --- a/src/platforms/Stream.h +++ b/src/platforms/Stream.h @@ -4,7 +4,7 @@ #define NEO_GPS_STREAM NeoGPS::Stream #ifdef __GNUC__ #define NEO_GPS_STREAM_DEFAULT_IMPL_WARN \ - __attribute__((deprecated("You are using a function which uses NEO_GPS_STREAM with the default implementation, which does nothing!"))) + __attribute__((deprecated("You are using a function which uses NEO_GPS_STREAM without defining the type. Compilation will fail. To fix this #define NEO_GPS_STREAM your_stream_type_t before including platform.h"))) #endif /** diff --git a/src/platforms/System.h b/src/platforms/System.h index dd935bf..5f78d9f 100644 --- a/src/platforms/System.h +++ b/src/platforms/System.h @@ -4,7 +4,7 @@ #define NEO_GPS_SYSTEM NeoGPS::System #ifdef __GNUC__ #define NEO_GPS_SYSTEM_DEFAULT_IMPL_WARN \ - __attribute__((deprecated("You are using a function which uses NEO_GPS_SYSTEM with the default implementation, which does nothing!"))) + __attribute__((deprecated("You are using a function which uses NEO_GPS_STREAM without defining the type. Compilation will succeed, but the default implementation does not lock / unlock (enable / disable irqs). To fix this #define NEO_GPS_SYSTEM your_system_wrapper_class_t before including platform.h"))) #endif /** diff --git a/src/ublox/ubxGPS.header.h b/src/ublox/ubxGPS.header.h index f052034..5be99b1 100644 --- a/src/ublox/ubxGPS.header.h +++ b/src/ublox/ubxGPS.header.h @@ -309,7 +309,7 @@ class ubloxGPS : public ubloxNMEA if (chrCount == 3) { uint32_t tow = *((uint32_t *) &m_fix.dateTime); - //trace << PSTR("@ ") << tow; + //trace << PSTR("@ ") << +tow; uint16_t ms; if (GPSTime::from_TOWms( tow, m_fix.dateTime, ms )) { @@ -318,7 +318,7 @@ class ubloxGPS : public ubloxNMEA m_fix.valid.date = true; } else m_fix.dateTime.init(); - //trace << PSTR(".") << m_fix.dateTime_cs; + //trace << PSTR(".") << +m_fix.dateTime_cs; } #endif diff --git a/src/ublox/ubxGPS.impl.h b/src/ublox/ubxGPS.impl.h index 00cee4e..c337399 100644 --- a/src/ublox/ubxGPS.impl.h +++ b/src/ublox/ubxGPS.impl.h @@ -364,7 +364,7 @@ void ubloxGPS::write( const msg_t & msg ) sent.msg_class = msg.msg_class; sent.msg_id = msg.msg_id; -//trace << F("::write ") << msg.msg_class << F("/") << msg.msg_id << endl; +//trace << F("::write ") << msg.msg_class << F("/") << (int) msg.msg_id << endl; } //--------------------------------------------------------- @@ -409,7 +409,7 @@ void ubloxGPS::write_P( const msg_t & msg ) bool ubloxGPS::send( const msg_t & msg, msg_t *reply_msg ) { -//trace << F("::send - ") << (uint8_t) msg.msg_class << F(" ") << (uint8_t) msg.msg_id << F(" "); +//trace << F("::send - ") << (int) msg.msg_class << F(" ") << (int) msg.msg_id << F(" "); bool ok = true; write( msg ); @@ -467,7 +467,7 @@ bool ubloxGPS::parseField( char c ) switch (rx().msg_class) { case UBX_NAV: //================================================= -//if (chrCount == 0) Serial << F( " NAV ") << (uint8_t) rx().msg_id; +//if (chrCount == 0) Serial << F( " NAV ") << (int) rx().msg_id; switch (rx().msg_id) { case UBX_NAV_STATUS : return parseNavStatus ( chr ); case UBX_NAV_POSLLH : return parseNavPosLLH ( chr ); @@ -670,12 +670,12 @@ bool ubloxGPS::parseNavPosLLH( uint8_t chr ) if (chrCount == 19) { gps_fix::whole_frac *altp = &m_fix.alt; int32_t height_MSLmm = *((int32_t *)altp); -//trace << F(" alt = ") << height_MSLmm; +//trace << F(" alt = ") << +height_MSLmm; m_fix.alt.whole = height_MSLmm / 1000UL; m_fix.alt.frac = ((uint16_t)(height_MSLmm - (m_fix.alt.whole * 1000UL)))/10; -//trace << F(" = ") << m_fix.alt.whole << F("."); +//trace << F(" = ") << +m_fix.alt.whole << F("."); //if (m_fix.alt.frac < 10) trace << '0'; -//trace << m_fix.alt.frac; +//trace << +m_fix.alt.frac; m_fix.valid.altitude = true; } break; @@ -774,7 +774,7 @@ bool ubloxGPS::parseNavVelNED( uint8_t chr ) m_fix.spd.frac = (nmiph_E19 * 125) >> 16; m_fix.valid.speed = true; -//trace << m_fix.speed_mkn() << F(" nmi/h "); +//trace << +m_fix.speed_mkn() << F(" nmi/h "); } break; #endif @@ -788,14 +788,14 @@ bool ubloxGPS::parseNavVelNED( uint8_t chr ) gps_fix::whole_frac *hdgp = &m_fix.hdg; uint32_t ui = *((uint32_t *)hdgp); //trace << F("hdg "); -//trace << ui; +//trace << +ui; //trace << F("E-5, "); m_fix.hdg.whole = ui / 100000UL; ui -= ((uint32_t)m_fix.hdg.whole) * 100000UL; m_fix.hdg.frac = (ui/1000UL); // hundredths m_fix.valid.heading = true; -//trace << m_fix.heading_cd() << F("E-2 "); +//trace << +m_fix.heading_cd() << F("E-2 "); } break; #endif @@ -829,7 +829,7 @@ bool ubloxGPS::parseNavTimeGPS( uint8_t chr ) *((ublox::nav_timegps_t::valid_t *) &chr); if (!v.leap_seconds) GPSTime::leap_seconds = 0; // oops! -//else trace << F("leap ") << GPSTime::leap_seconds << ' '; +//else trace << F("leap ") << +GPSTime::leap_seconds << ' '; if (GPSTime::leap_seconds != 0) { if (!v.time_of_week) { m_fix.valid.date = @@ -837,7 +837,7 @@ bool ubloxGPS::parseNavTimeGPS( uint8_t chr ) } else if ((GPSTime::start_of_week() == 0) && m_fix.valid.date && m_fix.valid.time) { GPSTime::start_of_week( m_fix.dateTime ); -//trace << m_fix.dateTime << '.' << m_fix.dateTime_cs; +//trace << m_fix.dateTime << '.' << +m_fix.dateTime_cs; } } } @@ -896,7 +896,7 @@ bool ubloxGPS::parseNavTimeUTC( uint8_t chr ) (GPSTime::leap_seconds != 0)) GPSTime::start_of_week( m_fix.dateTime ); #endif -//trace << m_fix.dateTime << F(".") << m_fix.dateTime_cs; +//trace << m_fix.dateTime << F(".") << +m_fix.dateTime_cs; //trace << ' ' << v.UTC << ' ' << v.time_of_week << ' ' << start_of_week(); } break; diff --git a/tests/NMEA/NMEA.cpp b/tests/NMEA/NMEA.cpp index 45347e7..ff92b3f 100644 --- a/tests/NMEA/NMEA.cpp +++ b/tests/NMEA/NMEA.cpp @@ -11,18 +11,6 @@ // no 'gps_fix' members are enabled in GPSfix_cfg.h, no information will be // parsed, copied or printed. // -// Prerequisites: -// 1) Your GPS device has been correctly powered. -// 2) Your GPS device is correctly connected using a serial adapter. -// By default /dev/ttyUSB0 is used. -// 3) You know the default baud rate of your GPS device. -// By default 9600 is assumed. If this doesn't work change it in serial.cpp -// 4) LAST_SENTENCE_IN_INTERVAL is defined to be the sentence that is -// sent *last* in each update interval (usually once per second). -// The default is NMEAGPS::NMEA_RMC (see NMEAGPS_cfg.h). Other -// programs may need to use the sentence identified by NMEAorder.ino. -// 5) NMEAGPS_RECOGNIZE_ALL is defined in NMEAGPS_cfg.h -// //====================================================================== //------------------------------------------------------------ @@ -34,13 +22,19 @@ // platform.h must be included before NMEAGPS.h #include + +// We fake the GPS using FakeGPS. #include + +// platform.h defines delctype(std::cout) as the NEO_GPS_PRINT type. +// We can therefore pass std::cout to all functions which expect a +// NEO_GPS_PRINT object. +#include + #include #include -#include - //------------------------------------------------------------ // This object parses received characters // into the gps.fix() data structure @@ -89,8 +83,8 @@ static void GPSloop(FakeGPS & fakeGPS) void outputHeader() { DEBUG_PORT << "NMEA.cpp: started" << std::endl; - DEBUG_PORT << " fix object size = " << sizeof(gps.fix()) << std::endl; - DEBUG_PORT << " gps object size = " << sizeof(gps) << std::endl; + DEBUG_PORT << " fix object size = " << +sizeof(gps.fix()) << std::endl; + DEBUG_PORT << " gps object size = " << +sizeof(gps) << std::endl; #ifndef NMEAGPS_RECOGNIZE_ALL #error You must define NMEAGPS_RECOGNIZE_ALL in NMEAGPS_cfg.h! From d3f96eb7e8c72f0627d84e1e02c04ed94590ba78 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Wed, 20 Sep 2017 20:12:50 +0200 Subject: [PATCH 25/38] Revert "doc: fix minor documentation mistakes" This reverts commit 8a1ec52b93e62418fa6f265461010055b5000560. --- src/NeoTime.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/NeoTime.h b/src/NeoTime.h index 127910b..a2bce06 100644 --- a/src/NeoTime.h +++ b/src/NeoTime.h @@ -107,7 +107,8 @@ struct time_t { /** * Offset by a number of seconds. - * @param[in] offset in seconds. + * @param[in] seconds to offset. + * @return *this */ void operator +=( clock_t offset ) { *this = offset + operator clock_t(); } @@ -192,7 +193,7 @@ struct time_t { /** * Determine the day of the week for the specified day number - * @param[in] dayno number as counted from January 1 of the epoch year. + * @param[in] day number as counted from January 1 of the epoch year. * @return weekday number 1..7, as for the /day/ member. */ static uint8_t weekday_for(uint16_t dayno) From 43fb3e35ba4578eacb4c2ef3e9ed282426346948 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Wed, 20 Sep 2017 20:14:16 +0200 Subject: [PATCH 26/38] Revert "Revert "doc: fix minor documentation mistakes"" This reverts commit d3f96eb7e8c72f0627d84e1e02c04ed94590ba78. --- src/NeoTime.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NeoTime.h b/src/NeoTime.h index a2bce06..127910b 100644 --- a/src/NeoTime.h +++ b/src/NeoTime.h @@ -107,8 +107,7 @@ struct time_t { /** * Offset by a number of seconds. - * @param[in] seconds to offset. - * @return *this + * @param[in] offset in seconds. */ void operator +=( clock_t offset ) { *this = offset + operator clock_t(); } @@ -193,7 +192,7 @@ struct time_t { /** * Determine the day of the week for the specified day number - * @param[in] day number as counted from January 1 of the epoch year. + * @param[in] dayno number as counted from January 1 of the epoch year. * @return weekday number 1..7, as for the /day/ member. */ static uint8_t weekday_for(uint16_t dayno) From a41ab2015b207e81b94c46a4c58845b0268e17ee Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Wed, 20 Sep 2017 20:14:19 +0200 Subject: [PATCH 27/38] Revert "feat: add some files to gitignore" This reverts commit e9f328f42e353ac6ea5803aa1196853c3fe3df80. --- .gitignore | 5 --- CMakeLists.txt | 116 ------------------------------------------------- 2 files changed, 121 deletions(-) delete mode 100644 CMakeLists.txt diff --git a/.gitignore b/.gitignore index 513291b..96374c4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,3 @@ -.kdev4 -/*.kdev4 -a.out -/build - # Windows image file caches Thumbs.db ehthumbs.db diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 458b7a6..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,116 +0,0 @@ -# This file has been adapted from https://github.com/jacketizer/libnmea/blob/master/CMakeLists.txt -# (MIT License THANKS) - -cmake_minimum_required (VERSION 2.8) -project(NeoGPS CXX) - -option(NEO_GPS_BUILD_STATIC_LIB "Build static NeoGPS" ON) -option(NEO_GPS_BUILD_SHARED_LIB "Build shared NeoGPS" ON) -option(NEO_GPS_BUILD_EXAMPLES "Build examples" ON) -option(NEO_GPS_EXAMPLES_LINK_STATIC "Link examples statically" OFF) - -if (NOT NEO_GPS_BUILD_STATIC_LIB AND NOT NEO_GPS_BUILD_SHARED_LIB) - message(FATAL_ERROR "You must build either shared or static lib, or both") -endif() - -if (NOT NEO_GPS_BUILD_SHARED_LIB) - set(NEO_GPS_EXAMPLES_LINK_STATIC ON) -endif() - -if (NOT NEO_GPS_BUILD_STATIC_LIB) - message("Linking examples/unit tests to shared lib since NEO_GPS_BUILD_STATIC_LIB is turned off") - set(NEO_GPS_EXAMPLES_LINK_STATIC OFF) -endif() - -# Set some nicer output dirs. -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) - -set(NEO_GPS_SRC - src/DMS.cpp - src/GPSTime.cpp - src/Location.cpp - src/NeoTime.cpp - src/NMEAGPS.cpp - src/Streamers.cpp - src/ublox/ubxGPS.cpp - src/ublox/ubxmsg.cpp - src/ublox/ubxNMEA.cpp) - -set(NEO_GPS_HDR - src/CosaCompat.h - src/DMS.h - src/GPSfix_cfg.h - src/GPSfix.h - src/GPSport.h - src/GPSTime.h - src/Location.h - src/NeoGPS_cfg.h - src/NeoTime.h - src/NMEAGPS_cfg.h - src/NMEAGPS.h - src/Platform.h - src/Streamers.h - src/ublox/ubx_cfg.h - src/ublox/ubxGPS.h - src/ublox/ubxmsg.h - src/ublox/ubxNMEA.h) - -source_group("Headers" FILES ${NEO_GPS_HDR}) -source_group("Source" FILES ${NEO_GPS_SRC}) - -if (NEO_GPS_BUILD_STATIC_LIB) - add_library(neogps STATIC ${NEO_GPS_SRC}) - target_link_libraries(neogps dl) - install(TARGETS neogps DESTINATION lib) -endif() - -if (NEO_GPS_BUILD_SHARED_LIB) - if (POLICY CMP0042) - cmake_policy(PUSH) - cmake_policy(SET CMP0042 OLD) - endif() - - add_library(neogps_shared SHARED ${NEO_GPS_SRC}) - target_link_libraries(neogps_shared dl) - - if (UNIX) - set_target_properties(neogps_shared PROPERTIES OUTPUT_NAME neogps) - endif() - - install(TARGETS neogps_shared DESTINATION lib) - - if (POLICY CMP0042) - cmake_policy(POP) - endif() -endif() - -# And copy headers to build dir. -foreach (HDR ${PARSERS_HDRS}) - get_filename_component(HDR_NAME ${HDR} NAME_WE) - message("${HDR}") - configure_file(${HDR} ${PROJECT_BINARY_DIR}/include/neogps/${HDR_NAME}.h COPYONLY) -endforeach() - -include_directories("${PROJECT_BINARY_DIR}/include/") - -if (NEO_GPS_BUILD_EXAMPLES) - # Find all example sources. - file(GLOB EXAMPLE_SRCS - RELATIVE "${PROJECT_SOURCE_DIR}" - "${PROJECT_SOURCE_DIR}/examples/*/*.cpp") - - foreach (EXAMPLE_SRC ${EXAMPLE_SRCS}) - get_filename_component(EXAMPLE_NAME ${EXAMPLE_SRC} NAME_WE) - - add_executable(${EXAMPLE_NAME} ${EXAMPLE_SRC}) - - if (NEO_GPS_EXAMPLES_LINK_STATIC) - target_link_libraries(${EXAMPLE_NAME} neogps) - else() - target_link_libraries(${EXAMPLE_NAME} neogps_shared) - endif() - endforeach() -endif() - From 20971babe572be0884255c26631bebf7e7f7a447 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Wed, 20 Sep 2017 20:14:20 +0200 Subject: [PATCH 28/38] Revert "feat: NeoGPS finally outputs something" This reverts commit a8b7fbe6f24600eaa214267acb88f7aae48a5fd3. --- examples/linux/GpsPort.cpp | 5 ++- examples/linux/GpsPort.dummy.cpp | 51 ----------------------------- examples/linux/NMEA/NMEA.cpp | 2 +- examples/linux/NMEA/build.dummy.txt | 1 - examples/linux/serial.cpp | 2 +- 5 files changed, 6 insertions(+), 55 deletions(-) delete mode 100644 examples/linux/GpsPort.dummy.cpp delete mode 100644 examples/linux/NMEA/build.dummy.txt diff --git a/examples/linux/GpsPort.cpp b/examples/linux/GpsPort.cpp index f3c1ab0..41d7cc1 100644 --- a/examples/linux/GpsPort.cpp +++ b/examples/linux/GpsPort.cpp @@ -5,7 +5,10 @@ GpsPort::GpsPort(const char* usbDev) { } bool GpsPort::available() { - return ::data_available(_device); + return true; + //bool available = ::data_available(_device); + //std::cout << "Availabe: " << available << std::endl; + //return available; } char GpsPort::read() { diff --git a/examples/linux/GpsPort.dummy.cpp b/examples/linux/GpsPort.dummy.cpp deleted file mode 100644 index d70d116..0000000 --- a/examples/linux/GpsPort.dummy.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "GpsPort.h" -#include -#include - -GpsPort::GpsPort(const char* usbDev) { - (void) usbDev; - _device = 0; -} - -bool GpsPort::available() { - if (_device == 0) { - return true; - } - _device = 1; - return false; -} - -static const char * NMEA_STRING = - "$GPRMC,162254.00,A,3723.02837,N,12159.39853,W,0.820,188.36,110706,,,A*74\r\n" - "$GPVTG,188.36,T,,M,0.820,N,1.519,K,A*3F\r\n" - "$GPGGA,162254.00,3723.02837,N,12159.39853,W,1,03,2.36,525.6,M,-25.6,M,,*65\r\n" - "$GPGSA,A,2,25,01,22,,,,,,,,,,2.56,2.36,1.00*02\r\n" - "$GPGSV,4,1,14,25,15,175,30,14,80,041,,19,38,259,14,01,52,223,18*76\r\n" - "$GPGSV,4,2,14,18,16,079,,11,19,312,,14,80,041,,21,04,135,25*7D\r\n" - "$GPGSV,4,3,14,15,27,134,18,03,25,222,,22,51,057,16,09,07,036,*79\r\n" - "$GPGSV,4,4,14,07,01,181,,15,25,135,*76\r\n" - "$GPGLL,3723.02837,N,12159.39853,W,162254.00,A,A*7C\r\n" - "$GPZDA,162254.00,11,07,2006,00,00*63\r\n"; - -char GpsPort::read() { - static int runner = 0; - static int len = strlen(NMEA_STRING); - char c = NMEA_STRING[runner]; - if (c == '$') { - sleep(1); - } - runner = (runner + 1) % len; - - char nextC = NMEA_STRING[runner]; - if (nextC == '$') { - // Signal available to say false; - _device = 1; - } - - return c; -} - -void GpsPort::print(char c) { - (void) c; - return; -} diff --git a/examples/linux/NMEA/NMEA.cpp b/examples/linux/NMEA/NMEA.cpp index c0b1373..dfb2cae 100644 --- a/examples/linux/NMEA/NMEA.cpp +++ b/examples/linux/NMEA/NMEA.cpp @@ -92,7 +92,7 @@ GpsPort setup(char *usbDev) DEBUG_PORT.print( "\n gps object size = " ); DEBUG_PORT.print( (uint32_t)sizeof(gps) ); DEBUG_PORT.print( "\nLooking for GPS device on " ); - DEBUG_PORT.print( usbDev == nullptr ? "default" : usbDev ); + DEBUG_PORT.print( usbDev ); #ifndef NMEAGPS_RECOGNIZE_ALL #error You must define NMEAGPS_RECOGNIZE_ALL in NMEAGPS_cfg.h! diff --git a/examples/linux/NMEA/build.dummy.txt b/examples/linux/NMEA/build.dummy.txt deleted file mode 100644 index 5d1560e..0000000 --- a/examples/linux/NMEA/build.dummy.txt +++ /dev/null @@ -1 +0,0 @@ -g++ -flto -g -Wall ../../../src/DMS.cpp ../../../src/GPSTime.cpp ../../../src/Location.cpp ../../../src/NeoTime.cpp ../../../src/NMEAGPS.cpp ../GpsPort.dummy.cpp ../Print.cpp NMEA.cpp ../serial.cpp -I ../ -I ../../../src diff --git a/examples/linux/serial.cpp b/examples/linux/serial.cpp index 773cf1b..2e423fc 100644 --- a/examples/linux/serial.cpp +++ b/examples/linux/serial.cpp @@ -75,7 +75,7 @@ bool data_available(serial_dev_t fd) FD_ZERO(&rfds); FD_SET(fd, &rfds); - int retval = select(1, &rfds, NULL, NULL, &tv); + int retval = select(1, &rfds, NULL, NULL, &tv) > 0; if (retval == -1) { printf("Error select: %s\n", strerror(errno)); } From 745ad6ebd071b903fac7d264754c8b286258f77a Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Wed, 20 Sep 2017 20:14:21 +0200 Subject: [PATCH 29/38] Revert "feat: minor tweaks to get linux version to compile" This reverts commit 9058e0142bba7273e413e7a04312a1ce95a6da68. --- src/NeoTime.cpp | 2 +- src/Platform.h | 5 ++--- src/platforms/Print.h | 1 - src/platforms/Stream.h | 1 + 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/NeoTime.cpp b/src/NeoTime.cpp index 81c33b9..d842bf9 100644 --- a/src/NeoTime.cpp +++ b/src/NeoTime.cpp @@ -33,7 +33,7 @@ bool time_t::parse(str_P s) strcpy_P(buf, s); char* sp = &buf[0]; #else - char* sp = (char *)&s[0]; + char* sp = &s[0]; #endif uint16_t value = strtoul(sp, &sp, 10); diff --git a/src/Platform.h b/src/Platform.h index 38de3c1..510e320 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -1,7 +1,5 @@ #pragma once -#include "CosaCompat.h" - /** * This file contains platform related definitions and imports. **/ @@ -18,12 +16,13 @@ #include "platforms/System.h" #include - //#define __PROGMEM + #define __PROGMEM #define PROGMEM #define pgm_read_byte(x) (*(x)) #define __FlashStringHelper char #define F(x) (x) + #define str_P char * #include diff --git a/src/platforms/Print.h b/src/platforms/Print.h index d9a2ece..1236c5e 100644 --- a/src/platforms/Print.h +++ b/src/platforms/Print.h @@ -9,7 +9,6 @@ class Print { void print(uint8_t) const; void print(uint16_t) const; void print(uint32_t) const; - void print(int) const; void print(const char *) const; void write(char) const; }; diff --git a/src/platforms/Stream.h b/src/platforms/Stream.h index 81c1d85..79484db 100644 --- a/src/platforms/Stream.h +++ b/src/platforms/Stream.h @@ -1,5 +1,6 @@ #pragma once +#include // If there is not already an implementation for your platform, // implement these functions. class Stream { From 518e2182374b56aaf88d1938a4dbca054bbdb096 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Wed, 20 Sep 2017 20:14:22 +0200 Subject: [PATCH 30/38] Revert "feat: add (hopefully) working linux serial example." This reverts commit cfe09772d167fdf67785e25b47ef3ecf3d44dcd9. --- examples/linux/GpsPort.cpp | 23 ------ examples/linux/GpsPort.h | 13 ---- examples/linux/NMEA/NMEA.cpp | 128 ++++++++++++++++++++++++---------- examples/linux/NMEA/build.txt | 1 - examples/linux/Print.cpp | 16 ----- examples/linux/System.cpp | 4 -- examples/linux/serial.cpp | 21 +++--- examples/linux/serial.h | 15 ---- 8 files changed, 102 insertions(+), 119 deletions(-) delete mode 100644 examples/linux/GpsPort.cpp delete mode 100644 examples/linux/GpsPort.h delete mode 100644 examples/linux/NMEA/build.txt delete mode 100644 examples/linux/Print.cpp delete mode 100644 examples/linux/System.cpp delete mode 100644 examples/linux/serial.h diff --git a/examples/linux/GpsPort.cpp b/examples/linux/GpsPort.cpp deleted file mode 100644 index 41d7cc1..0000000 --- a/examples/linux/GpsPort.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "GpsPort.h" - -GpsPort::GpsPort(const char* usbDev) { - _device = ::init(usbDev); -} - -bool GpsPort::available() { - return true; - //bool available = ::data_available(_device); - //std::cout << "Availabe: " << available << std::endl; - //return available; -} - -char GpsPort::read() { - return ::read(_device); -} - -void GpsPort::print(char c) { - char s[2]; - s[0] = c; - s[1] = '\0'; - ::write(_device, s); -} diff --git a/examples/linux/GpsPort.h b/examples/linux/GpsPort.h deleted file mode 100644 index 88596ea..0000000 --- a/examples/linux/GpsPort.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "serial.h" - -class GpsPort { -private: - serial_dev_t _device; - -public: - GpsPort(const char*); - bool available(); - char read(); - void print(char); -}; diff --git a/examples/linux/NMEA/NMEA.cpp b/examples/linux/NMEA/NMEA.cpp index dfb2cae..c90b3f4 100644 --- a/examples/linux/NMEA/NMEA.cpp +++ b/examples/linux/NMEA/NMEA.cpp @@ -1,8 +1,9 @@ -#include +#include #include -#include //====================================================================== +// Program: NMEA.ino +// // Description: This program uses the fix-oriented methods available() and // read() to handle complete fix structures. // @@ -17,18 +18,54 @@ // // Prerequisites: // 1) Your GPS device has been correctly powered. -// 2) Your GPS device is correctly connected using a serial adapter. -// By default /dev/ttyUSB0 is used. +// Be careful when connecting 3.3V devices. +// 2) Your GPS device is correctly connected to an Arduino serial port. +// See GPSport.h for the default connections. // 3) You know the default baud rate of your GPS device. -// By default 9600 is assumed. If this doesn't work change it in serial.cpp +// If 9600 does not work, use NMEAdiagnostic.ino to +// scan for the correct baud rate. // 4) LAST_SENTENCE_IN_INTERVAL is defined to be the sentence that is // sent *last* in each update interval (usually once per second). // The default is NMEAGPS::NMEA_RMC (see NMEAGPS_cfg.h). Other // programs may need to use the sentence identified by NMEAorder.ino. // 5) NMEAGPS_RECOGNIZE_ALL is defined in NMEAGPS_cfg.h // +// 'Serial' is for debug output to the Serial Monitor window. +// //====================================================================== +//------------------------------------------------------------------------- +// The GPSport.h include file tries to choose a default serial port +// for the GPS device. If you know which serial port you want to use, +// delete this section and declare it here: +// +// HardwareSerial & gps_port = Serial2; // an alias +// or +// AltSoftSerial gps_port; // depends on Arduino - pins 8 & 9 on UNO +// or +// NeoSWSerial gps_port( rxpin, txpin ); // to GPS TX, RX +// or +// Search and replace all occurrences of "gps_port" with your port's name. +// +// See Installation instructions for additional information. + +#ifdef ARDUINO + #if defined( UBRR1H ) | defined( ID_USART0 ) + // Default is to use Serial1 when available. You could also + // use NeoHWSerial, especially if you want to handle GPS characters + // in an Interrupt Service Routine. + //#include + #else + // Only one serial port is available, uncomment one of the following: + //#include + //#include + #include + //#include /* NOT RECOMMENDED */ + #endif +#endif + +#include "GPSport.h" + //------------------------------------------------------------ // For the NeoGPS example programs, "Streamers" is common set // of printing and formatting routines for GPS data, in a @@ -38,6 +75,26 @@ #include "Streamers.h" +//------------------------------------------------------------ +// When NeoHWSerial is used, none of the built-in HardwareSerial +// variables can be used: Serial, Serial1, Serial2 and Serial3 +// *cannot* be used. Instead, you must use the corresponding +// NeoSerial, NeoSerial1, NeoSerial2 or NeoSerial3. This define +// is used to substitute the appropriate Serial variable in +// all debug prints below. + +#ifndef DEBUG_PORT + #ifdef NeoHWSerial_h + #define DEBUG_PORT NeoSerial + #else + #define DEBUG_PORT Serial + #endif +#endif + +#ifndef USING_GPS_PORT + #define USING_GPS_PORT "unknown port" +#endif + //------------------------------------------------------------ // This object parses received characters // into the gps.fix() data structure @@ -59,8 +116,6 @@ static gps_fix fix_data; // By doing the "hard" work during the quiet time, the CPU can get back to // reading the GPS chars as they come in, so that no chars are lost. -static Print DEBUG_PORT; - static void doSomeWork() { // Print all the things! @@ -72,7 +127,7 @@ static void doSomeWork() //------------------------------------ // This is the main GPS parsing loop. -static void GPSloop(GpsPort gps_port) +static void GPSloop() { while (gps.available( gps_port )) { fix_data = gps.read(); @@ -83,16 +138,19 @@ static void GPSloop(GpsPort gps_port) //-------------------------- -GpsPort setup(char *usbDev) +void setup() { // Start the normal trace output - DEBUG_PORT.print( "NMEA: started\n" ); - DEBUG_PORT.print( " fix object size = " ); - DEBUG_PORT.print( (uint32_t)sizeof(gps.fix()) ); - DEBUG_PORT.print( "\n gps object size = " ); - DEBUG_PORT.print( (uint32_t)sizeof(gps) ); - DEBUG_PORT.print( "\nLooking for GPS device on " ); - DEBUG_PORT.print( usbDev ); + DEBUG_PORT.begin(9600); + while (!DEBUG_PORT) + ; + + DEBUG_PORT.print( F("NMEA.INO: started\n") ); + DEBUG_PORT.print( F(" fix object size = ") ); + DEBUG_PORT.println( sizeof(gps.fix()) ); + DEBUG_PORT.print( F(" gps object size = ") ); + DEBUG_PORT.println( sizeof(gps) ); + DEBUG_PORT.println( F("Looking for GPS device on " USING_GPS_PORT) ); #ifndef NMEAGPS_RECOGNIZE_ALL #error You must define NMEAGPS_RECOGNIZE_ALL in NMEAGPS_cfg.h! @@ -111,35 +169,31 @@ GpsPort setup(char *usbDev) #else if (gps.merging == NMEAGPS::NO_MERGING) { - DEBUG_PORT.print( F("\nWARNING: displaying data from ") ); - DEBUG_PORT.print( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); - DEBUG_PORT.print( F(" sentences ONLY, and only if ") ); - DEBUG_PORT.print( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); - DEBUG_PORT.print( F(" is enabled.\n" + DEBUG_PORT.print ( F("\nWARNING: displaying data from ") ); + DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); + DEBUG_PORT.print ( F(" sentences ONLY, and only if ") ); + DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); + DEBUG_PORT.println( F(" is enabled.\n" " Other sentences may be parsed, but their data will not be displayed.") ); - DEBUG_PORT.print( "\n" ); } #endif - DEBUG_PORT.print( "\nGPS quiet time is assumed to begin after a "); - DEBUG_PORT.print( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); - DEBUG_PORT.print( " sentence is received.\n" - " You should confirm this with NMEAorder.ino\n" ); - DEBUG_PORT.print( "\n" ); - - GpsPort gps_port = GpsPort(usbDev); + DEBUG_PORT.print ( F("\nGPS quiet time is assumed to begin after a ") ); + DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); + DEBUG_PORT.println( F(" sentence is received.\n" + " You should confirm this with NMEAorder.ino\n") ); trace_header( DEBUG_PORT ); - - return gps_port; + + DEBUG_PORT.flush(); + + // Start the UART for the GPS device + gps_port.begin( 9600 ); } //-------------------------- -int main(int argc, char *argv[]) { - auto gps_port = setup(argc > 1 ? argv[1] : nullptr); - for (;;) { - GPSloop(gps_port); - } - return 0; +void loop() +{ + GPSloop(); } diff --git a/examples/linux/NMEA/build.txt b/examples/linux/NMEA/build.txt deleted file mode 100644 index aebc237..0000000 --- a/examples/linux/NMEA/build.txt +++ /dev/null @@ -1 +0,0 @@ -g++ -flto -Wall ../../../src/DMS.cpp ../../../src/GPSTime.cpp ../../../src/Location.cpp ../../../src/NeoTime.cpp ../../../src/NMEAGPS.cpp ../GpsPort.cpp ../Print.cpp NMEA.cpp ../serial.cpp -I ../ -I ../../../src diff --git a/examples/linux/Print.cpp b/examples/linux/Print.cpp deleted file mode 100644 index 887f67e..0000000 --- a/examples/linux/Print.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include - -#include - -template -static void _print(T x) { - std::cout << x; -} - -void Print::print(char c) const { _print(c); } -void Print::print(uint8_t n) const { _print(n); } -void Print::print(uint16_t n) const { _print(n); } -void Print::print(uint32_t n) const { _print(n); } -void Print::print(int n) const { _print(n); } -void Print::print(const char *s) const { _print(s); } -void Print::write(char c) const { _print(c); } diff --git a/examples/linux/System.cpp b/examples/linux/System.cpp deleted file mode 100644 index 0c8c874..0000000 --- a/examples/linux/System.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include - -void interrupts() {} -void noInterrupts() {} diff --git a/examples/linux/serial.cpp b/examples/linux/serial.cpp index 2e423fc..ddcf1e2 100644 --- a/examples/linux/serial.cpp +++ b/examples/linux/serial.cpp @@ -49,7 +49,7 @@ static int set_interface_attribs(int fd, int speed) return 0; } -static void set_mincount(int fd, int mcount) +void set_mincount(int fd, int mcount) { struct termios tty; @@ -65,14 +65,16 @@ static void set_mincount(int fd, int mcount) printf("Error tcsetattr: %s\n", strerror(errno)); } -bool data_available(serial_dev_t fd) +static int fd; + +bool data_available() { fd_set rfds; struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; - FD_ZERO(&rfds); + FD_ZERO(rfds); FD_SET(fd, &rfds); int retval = select(1, &rfds, NULL, NULL, &tv) > 0; @@ -82,19 +84,19 @@ bool data_available(serial_dev_t fd) return retval > 0; } -char read(serial_dev_t fd) +char read() { char c; int rdlen = read(fd, &c, 1); if (rdlen > 0) { - return c; + printf("Read: %c\n", c); } else if (rdlen < 0) { printf("Error from read: %s\n", strerror(errno)); } return '\0'; } -void write(serial_dev_t fd, const char* out) +void write(const char* out) { int len = strlen(out); /* simple output */ @@ -105,13 +107,13 @@ void write(serial_dev_t fd, const char* out) tcdrain(fd); /* delay for output */ } -serial_dev_t init(const char *portname) +void init(const char *portname) { if (portname == nullptr) { portname = "/dev/ttyUSB0"; } - int fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); + fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); if (fd < 0) { printf("Error opening %s: %s\n", portname, strerror(errno)); return -1; @@ -119,6 +121,5 @@ serial_dev_t init(const char *portname) /*baudrate 9600, 8 bits, no parity, 1 stop bit */ set_interface_attribs(fd, B9600); //set_mincount(fd, 0); /* set to pure timed read */ - - return fd; + } diff --git a/examples/linux/serial.h b/examples/linux/serial.h deleted file mode 100644 index 8b2423e..0000000 --- a/examples/linux/serial.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -typedef int serial_dev_t; - -// Open portname (if nullptr /dev/ttyUSB0). -serial_dev_t init(const char *portname); - -// Write to previously initialized port. -void write(serial_dev_t, const char* out); - -// Reads one character from previously initialized port. -char read(serial_dev_t); - -// Returns true if read would not block on initialized port. -bool data_available(serial_dev_t); From 7ff96cb842c6beb0d6ee285cb931f23a27361854 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Wed, 20 Sep 2017 20:14:22 +0200 Subject: [PATCH 31/38] Revert "feat: continue work for a linux example" This reverts commit c71471606ca29bb4f7458072df5da05386a1ccd9. --- examples/linux/NMEA/NMEA.cpp | 199 ----------------------------------- examples/linux/serial.cpp | 125 ---------------------- 2 files changed, 324 deletions(-) delete mode 100644 examples/linux/NMEA/NMEA.cpp delete mode 100644 examples/linux/serial.cpp diff --git a/examples/linux/NMEA/NMEA.cpp b/examples/linux/NMEA/NMEA.cpp deleted file mode 100644 index c90b3f4..0000000 --- a/examples/linux/NMEA/NMEA.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include -#include - -//====================================================================== -// Program: NMEA.ino -// -// Description: This program uses the fix-oriented methods available() and -// read() to handle complete fix structures. -// -// When the last character of the LAST_SENTENCE_IN_INTERVAL (see NMEAGPS_cfg.h) -// is decoded, a completed fix structure becomes available and is returned -// from read(). The new fix is saved the 'fix_data' structure, and can be used -// anywhere, at any time. -// -// If no messages are enabled in NMEAGPS_cfg.h, or -// no 'gps_fix' members are enabled in GPSfix_cfg.h, no information will be -// parsed, copied or printed. -// -// Prerequisites: -// 1) Your GPS device has been correctly powered. -// Be careful when connecting 3.3V devices. -// 2) Your GPS device is correctly connected to an Arduino serial port. -// See GPSport.h for the default connections. -// 3) You know the default baud rate of your GPS device. -// If 9600 does not work, use NMEAdiagnostic.ino to -// scan for the correct baud rate. -// 4) LAST_SENTENCE_IN_INTERVAL is defined to be the sentence that is -// sent *last* in each update interval (usually once per second). -// The default is NMEAGPS::NMEA_RMC (see NMEAGPS_cfg.h). Other -// programs may need to use the sentence identified by NMEAorder.ino. -// 5) NMEAGPS_RECOGNIZE_ALL is defined in NMEAGPS_cfg.h -// -// 'Serial' is for debug output to the Serial Monitor window. -// -//====================================================================== - -//------------------------------------------------------------------------- -// The GPSport.h include file tries to choose a default serial port -// for the GPS device. If you know which serial port you want to use, -// delete this section and declare it here: -// -// HardwareSerial & gps_port = Serial2; // an alias -// or -// AltSoftSerial gps_port; // depends on Arduino - pins 8 & 9 on UNO -// or -// NeoSWSerial gps_port( rxpin, txpin ); // to GPS TX, RX -// or -// Search and replace all occurrences of "gps_port" with your port's name. -// -// See Installation instructions for additional information. - -#ifdef ARDUINO - #if defined( UBRR1H ) | defined( ID_USART0 ) - // Default is to use Serial1 when available. You could also - // use NeoHWSerial, especially if you want to handle GPS characters - // in an Interrupt Service Routine. - //#include - #else - // Only one serial port is available, uncomment one of the following: - //#include - //#include - #include - //#include /* NOT RECOMMENDED */ - #endif -#endif - -#include "GPSport.h" - -//------------------------------------------------------------ -// For the NeoGPS example programs, "Streamers" is common set -// of printing and formatting routines for GPS data, in a -// Comma-Separated Values text format (aka CSV). The CSV -// data will be printed to the "debug output device". -// If you don't need these formatters, simply delete this section. - -#include "Streamers.h" - -//------------------------------------------------------------ -// When NeoHWSerial is used, none of the built-in HardwareSerial -// variables can be used: Serial, Serial1, Serial2 and Serial3 -// *cannot* be used. Instead, you must use the corresponding -// NeoSerial, NeoSerial1, NeoSerial2 or NeoSerial3. This define -// is used to substitute the appropriate Serial variable in -// all debug prints below. - -#ifndef DEBUG_PORT - #ifdef NeoHWSerial_h - #define DEBUG_PORT NeoSerial - #else - #define DEBUG_PORT Serial - #endif -#endif - -#ifndef USING_GPS_PORT - #define USING_GPS_PORT "unknown port" -#endif - -//------------------------------------------------------------ -// This object parses received characters -// into the gps.fix() data structure - -static NMEAGPS gps; - -//------------------------------------------------------------ -// Define a set of GPS fix information. It will -// hold on to the various pieces as they are received from -// an RMC sentence. It can be used anywhere in your sketch. - -static gps_fix fix_data; - -//---------------------------------------------------------------- -// This function gets called about once per second, during the GPS -// quiet time. It's the best place to do anything that might take -// a while: print a bunch of things, write to SD, send an SMS, etc. -// -// By doing the "hard" work during the quiet time, the CPU can get back to -// reading the GPS chars as they come in, so that no chars are lost. - -static void doSomeWork() -{ - // Print all the things! - - trace_all( DEBUG_PORT, gps, fix_data ); - -} // doSomeWork - -//------------------------------------ -// This is the main GPS parsing loop. - -static void GPSloop() -{ - while (gps.available( gps_port )) { - fix_data = gps.read(); - doSomeWork(); - } - -} // GPSloop - -//-------------------------- - -void setup() -{ - // Start the normal trace output - DEBUG_PORT.begin(9600); - while (!DEBUG_PORT) - ; - - DEBUG_PORT.print( F("NMEA.INO: started\n") ); - DEBUG_PORT.print( F(" fix object size = ") ); - DEBUG_PORT.println( sizeof(gps.fix()) ); - DEBUG_PORT.print( F(" gps object size = ") ); - DEBUG_PORT.println( sizeof(gps) ); - DEBUG_PORT.println( F("Looking for GPS device on " USING_GPS_PORT) ); - - #ifndef NMEAGPS_RECOGNIZE_ALL - #error You must define NMEAGPS_RECOGNIZE_ALL in NMEAGPS_cfg.h! - #endif - - #ifdef NMEAGPS_INTERRUPT_PROCESSING - #error You must *NOT* define NMEAGPS_INTERRUPT_PROCESSING in NMEAGPS_cfg.h! - #endif - - #if !defined( NMEAGPS_PARSE_GGA ) & !defined( NMEAGPS_PARSE_GLL ) & \ - !defined( NMEAGPS_PARSE_GSA ) & !defined( NMEAGPS_PARSE_GSV ) & \ - !defined( NMEAGPS_PARSE_RMC ) & !defined( NMEAGPS_PARSE_VTG ) & \ - !defined( NMEAGPS_PARSE_ZDA ) & !defined( NMEAGPS_PARSE_GST ) - - DEBUG_PORT.println( F("\nWARNING: No NMEA sentences are enabled: no fix data will be displayed.") ); - - #else - if (gps.merging == NMEAGPS::NO_MERGING) { - DEBUG_PORT.print ( F("\nWARNING: displaying data from ") ); - DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); - DEBUG_PORT.print ( F(" sentences ONLY, and only if ") ); - DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); - DEBUG_PORT.println( F(" is enabled.\n" - " Other sentences may be parsed, but their data will not be displayed.") ); - } - #endif - - DEBUG_PORT.print ( F("\nGPS quiet time is assumed to begin after a ") ); - DEBUG_PORT.print ( gps.string_for( LAST_SENTENCE_IN_INTERVAL ) ); - DEBUG_PORT.println( F(" sentence is received.\n" - " You should confirm this with NMEAorder.ino\n") ); - - trace_header( DEBUG_PORT ); - - DEBUG_PORT.flush(); - - // Start the UART for the GPS device - gps_port.begin( 9600 ); -} - -//-------------------------- - -void loop() -{ - GPSloop(); -} diff --git a/examples/linux/serial.cpp b/examples/linux/serial.cpp deleted file mode 100644 index ddcf1e2..0000000 --- a/examples/linux/serial.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - * This code is heavily based on - * https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c - */ - -#include "serial.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -static int set_interface_attribs(int fd, int speed) -{ - struct termios tty; - - if (tcgetattr(fd, &tty) < 0) { - printf("Error from tcgetattr: %s\n", strerror(errno)); - return -1; - } - - cfsetospeed(&tty, (speed_t)speed); - cfsetispeed(&tty, (speed_t)speed); - - tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */ - tty.c_cflag &= ~CSIZE; - tty.c_cflag |= CS8; /* 8-bit characters */ - tty.c_cflag &= ~PARENB; /* no parity bit */ - tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */ - tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */ - - /* setup for non-canonical mode */ - tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); - tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - tty.c_oflag &= ~OPOST; - - /* fetch bytes as they become available */ - tty.c_cc[VMIN] = 1; - tty.c_cc[VTIME] = 1; - - if (tcsetattr(fd, TCSANOW, &tty) != 0) { - printf("Error from tcsetattr: %s\n", strerror(errno)); - return -1; - } - return 0; -} - -void set_mincount(int fd, int mcount) -{ - struct termios tty; - - if (tcgetattr(fd, &tty) < 0) { - printf("Error tcgetattr: %s\n", strerror(errno)); - return; - } - - tty.c_cc[VMIN] = mcount ? 1 : 0; - tty.c_cc[VTIME] = 5; /* half second timer */ - - if (tcsetattr(fd, TCSANOW, &tty) < 0) - printf("Error tcsetattr: %s\n", strerror(errno)); -} - -static int fd; - -bool data_available() -{ - fd_set rfds; - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 0; - - FD_ZERO(rfds); - FD_SET(fd, &rfds); - - int retval = select(1, &rfds, NULL, NULL, &tv) > 0; - if (retval == -1) { - printf("Error select: %s\n", strerror(errno)); - } - return retval > 0; -} - -char read() -{ - char c; - int rdlen = read(fd, &c, 1); - if (rdlen > 0) { - printf("Read: %c\n", c); - } else if (rdlen < 0) { - printf("Error from read: %s\n", strerror(errno)); - } - return '\0'; -} - -void write(const char* out) -{ - int len = strlen(out); - /* simple output */ - int wlen = write(fd, out, len); - if (wlen != len) { - printf("Error from write: %d, %d\n", wlen, errno); - } - tcdrain(fd); /* delay for output */ -} - -void init(const char *portname) -{ - if (portname == nullptr) { - portname = "/dev/ttyUSB0"; - } - - fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); - if (fd < 0) { - printf("Error opening %s: %s\n", portname, strerror(errno)); - return -1; - } - /*baudrate 9600, 8 bits, no parity, 1 stop bit */ - set_interface_attribs(fd, B9600); - //set_mincount(fd, 0); /* set to pure timed read */ - -} From 0722cf9d51d29982ee1ad3d07d9ac39171f27d26 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Wed, 20 Sep 2017 20:14:23 +0200 Subject: [PATCH 32/38] Revert "feat: continue converting to template functions" This reverts commit 44153e68e94bb251359b01c06aaf6ae4d5361c2c. --- src/DMS.cpp | 56 ++++++ src/DMS.h | 60 +----- src/NeoTime.cpp | 23 +++ src/NeoTime.h | 25 +-- src/Streamers.cpp | 404 ++++++++++++++++++++++++++++++++++++++++ src/Streamers.h | 421 ++---------------------------------------- src/platforms/Print.h | 2 - 7 files changed, 499 insertions(+), 492 deletions(-) create mode 100644 src/Streamers.cpp diff --git a/src/DMS.cpp b/src/DMS.cpp index eadc898..82f0e96 100644 --- a/src/DMS.cpp +++ b/src/DMS.cpp @@ -62,3 +62,59 @@ void DMS_t::From( int32_t deg_1E7 ) } } // From + +//---------------------------------------------------------------- + +Print & operator << ( Print & outs, const DMS_t & dms ) +{ + if (dms.degrees < 10) + outs.write( '0' ); + outs.print( dms.degrees ); + outs.write( ' ' ); + if (dms.minutes < 10) + outs.write( '0' ); + outs.print( dms.minutes ); + outs.print( F("\' ") ); + if (dms.seconds_whole < 10) + outs.write( '0' ); + outs.print( dms.seconds_whole ); + outs.write( '.' ); + if (dms.seconds_frac < 100) + outs.write( '0' ); + if (dms.seconds_frac < 10) + outs.write( '0' ); + outs.print( dms.seconds_frac ); + outs.print( F("\" ") ); + + return outs; + +} // operator << + +//---------------------------------------------------------------- + +void DMS_t::printDDDMMmmmm( Print & outs ) const +{ + outs.print( degrees ); + + if (minutes < 10) + outs.print( '0' ); + outs.print( minutes ); + outs.print( '.' ); + + // Calculate the fractional minutes from the seconds, + // *without* using floating-point numbers. + + uint16_t mmmm = seconds_whole * 166; // same as 10000/60, less .66666... + mmmm += (seconds_whole * 2 + seconds_frac/2 ) / 3; // ... plus the remaining .66666 + // ... plus the seconds_frac, scaled by 10000/(60*1000) = 1/6, which + // is implemented above as 1/2 * 1/3 + + // print leading zeroes, if necessary + if (mmmm < 1000) + outs.print( '0' ); + if (mmmm < 100) + outs.print( '0' ); + if (mmmm < 10) + outs.print( '0' ); + outs.print( mmmm ); +} diff --git a/src/DMS.h b/src/DMS.h index e458b11..b1cee52 100644 --- a/src/DMS.h +++ b/src/DMS.h @@ -49,68 +49,10 @@ class DMS_t void From( int32_t deg_1E7 ); // Print DMS as the funky NMEA DDDMM.mmmm format - template void printDDDMMmmmm( Print & outs ) const; } NEOGPS_PACKED; -//---------------------------------------------------------------- - -template -Print & operator << ( Print & outs, const DMS_t & dms ) -{ - if (dms.degrees < 10) - outs.write( '0' ); - outs.print( dms.degrees ); - outs.write( ' ' ); - if (dms.minutes < 10) - outs.write( '0' ); - outs.print( dms.minutes ); - outs.print( F("\' ") ); - if (dms.seconds_whole < 10) - outs.write( '0' ); - outs.print( dms.seconds_whole ); - outs.write( '.' ); - if (dms.seconds_frac < 100) - outs.write( '0' ); - if (dms.seconds_frac < 10) - outs.write( '0' ); - outs.print( dms.seconds_frac ); - outs.print( F("\" ") ); - - return outs; - -} // operator << - -//---------------------------------------------------------------- - -template -void DMS_t::printDDDMMmmmm( Print & outs ) const -{ - outs.print( degrees ); - - if (minutes < 10) - outs.print( '0' ); - outs.print( minutes ); - outs.print( '.' ); - - // Calculate the fractional minutes from the seconds, - // *without* using floating-point numbers. - - uint16_t mmmm = seconds_whole * 166; // same as 10000/60, less .66666... - mmmm += (seconds_whole * 2 + seconds_frac/2 ) / 3; // ... plus the remaining .66666 - // ... plus the seconds_frac, scaled by 10000/(60*1000) = 1/6, which - // is implemented above as 1/2 * 1/3 - - // print leading zeroes, if necessary - if (mmmm < 1000) - outs.print( '0' ); - if (mmmm < 100) - outs.print( '0' ); - if (mmmm < 10) - outs.print( '0' ); - outs.print( mmmm ); -} - +extern Print & operator << ( Print & outs, const DMS_t & ); #endif diff --git a/src/NeoTime.cpp b/src/NeoTime.cpp index d842bf9..b84226f 100644 --- a/src/NeoTime.cpp +++ b/src/NeoTime.cpp @@ -23,6 +23,29 @@ // For strtoul declaration #include + +Print & operator<<( Print& outs, const NeoGPS::time_t& t ) +{ + outs.print( t.full_year( t.year ) ); + outs.write( '-' ); + if (t.month < 10) outs.write( '0' ); + outs.print( t.month ); + outs.write( '-' ); + if (t.date < 10) outs.write( '0' ); + outs.print( t.date ); + outs.write( ' ' ); + if (t.hours < 10) outs.write( '0' ); + outs.print( t.hours ); + outs.write( ':' ); + if (t.minutes < 10) outs.write( '0' ); + outs.print( t.minutes ); + outs.write( ':' ); + if (t.seconds < 10) outs.write( '0' ); + outs.print( t.seconds ); + + return outs; +} + using NeoGPS::time_t; bool time_t::parse(str_P s) diff --git a/src/NeoTime.h b/src/NeoTime.h index 127910b..b0fd35f 100644 --- a/src/NeoTime.h +++ b/src/NeoTime.h @@ -297,33 +297,14 @@ struct time_t { }; // namespace NeoGPS +class Print; + /** * Print the date/time to the given stream with the format "YYYY-MM-DD HH:MM:SS". * @param[in] outs output stream. * @param[in] t time structure. * @return iostream. */ -template -Print & operator <<( Print & outs, const NeoGPS::time_t &t ) -{ - outs.print( t.full_year( t.year ) ); - outs.write( '-' ); - if (t.month < 10) outs.write( '0' ); - outs.print( t.month ); - outs.write( '-' ); - if (t.date < 10) outs.write( '0' ); - outs.print( t.date ); - outs.write( ' ' ); - if (t.hours < 10) outs.write( '0' ); - outs.print( t.hours ); - outs.write( ':' ); - if (t.minutes < 10) outs.write( '0' ); - outs.print( t.minutes ); - outs.write( ':' ); - if (t.seconds < 10) outs.write( '0' ); - outs.print( t.seconds ); - - return outs; -} +Print & operator <<( Print & outs, const NeoGPS::time_t &t ); #endif diff --git a/src/Streamers.cpp b/src/Streamers.cpp new file mode 100644 index 0000000..1e3a112 --- /dev/null +++ b/src/Streamers.cpp @@ -0,0 +1,404 @@ +#include "Streamers.h" +#include "NMEAGPS.h" + +//#define USE_FLOAT + +Print& operator <<( Print &outs, const bool b ) + { outs.print( b ? 't' : 'f' ); return outs; } + +Print& operator <<( Print &outs, const char c ) { outs.print(c); return outs; } + +Print& operator <<( Print &outs, const uint16_t v ) { outs.print(v); return outs; } + +Print& operator <<( Print &outs, const uint32_t v ) { outs.print(v); return outs; } + +Print& operator <<( Print &outs, const int32_t v ) { outs.print(v); return outs; } + +Print& operator <<( Print &outs, const uint8_t v ) { outs.print(v); return outs; } + +Print& operator <<( Print &outs, const __FlashStringHelper *s ) +{ outs.print(s); return outs; } + +//------------------------------------------ + +const char gps_fix_header[] __PROGMEM = + "Status," + + #if defined(GPS_FIX_DATE) | defined(GPS_FIX_TIME) + + "UTC " + + #if defined(GPS_FIX_DATE) + "Date" + #endif + #if defined(GPS_FIX_DATE) & defined(GPS_FIX_TIME) + "/" + #endif + #if defined(GPS_FIX_TIME) + "Time" + #endif + + #else + "s" + #endif + + "," + + #ifdef GPS_FIX_LOCATION + "Lat,Lon," + #endif + + #ifdef GPS_FIX_LOCATION_DMS + "DMS," + #endif + + #if defined(GPS_FIX_HEADING) + "Hdg," + #endif + + #if defined(GPS_FIX_SPEED) + "Spd," + #endif + + #if defined(GPS_FIX_ALTITUDE) + "Alt," + #endif + + #if defined(GPS_FIX_HDOP) + "HDOP," + #endif + + #if defined(GPS_FIX_VDOP) + "VDOP," + #endif + + #if defined(GPS_FIX_PDOP) + "PDOP," + #endif + + #if defined(GPS_FIX_LAT_ERR) + "Lat err," + #endif + + #if defined(GPS_FIX_LON_ERR) + "Lon err," + #endif + + #if defined(GPS_FIX_ALT_ERR) + "Alt err," + #endif + + #if defined(GPS_FIX_GEOID_HEIGHT) + "Geoid Ht," + #endif + + #if defined(GPS_FIX_SATELLITES) + "Sats," + #endif + + ; + +//............... + +#ifdef GPS_FIX_LOCATION_DMS + + static void printDMS( Print & outs, const DMS_t & dms ) + { + if (dms.degrees < 10) + outs.write( '0' ); + outs.print( dms.degrees ); + outs.write( ' ' ); + + if (dms.minutes < 10) + outs.write( '0' ); + outs.print( dms.minutes ); + outs.print( F("\' ") ); + + if (dms.seconds_whole < 10) + outs.write( '0' ); + outs.print( dms.seconds_whole ); + outs.write( '.' ); + + if (dms.seconds_frac < 100) + outs.write( '0' ); + if (dms.seconds_frac < 10) + outs.write( '0' ); + outs.print( dms.seconds_frac ); + outs.print( F("\" ") ); + + } // printDMS + +#endif +//............... + +Print & operator <<( Print &outs, const gps_fix &fix ) +{ + if (fix.valid.status) + outs << (uint8_t) fix.status; + outs << ','; + + #if defined(GPS_FIX_DATE) | defined(GPS_FIX_TIME) + bool someTime = false; + + #if defined(GPS_FIX_DATE) + someTime |= fix.valid.date; + #endif + + #if defined(GPS_FIX_TIME) + someTime |= fix.valid.time; + #endif + + if (someTime) { + outs << fix.dateTime << '.'; + uint16_t ms = fix.dateTime_ms(); + if (ms < 100) + outs << '0'; + if (ms < 10) + outs << '0'; + outs << ms; + } + outs << ','; + + #else + + // Date/Time not enabled, just output the interval number + static uint32_t sequence = 0L; + outs << sequence++ << ','; + + #endif + + #ifdef USE_FLOAT + #ifdef GPS_FIX_LOCATION + if (fix.valid.location) { + outs.print( fix.latitude(), 6 ); + outs << ','; + outs.print( fix.longitude(), 6 ); + } else + outs << ','; + outs << ','; + #endif + #ifdef GPS_FIX_LOCATION_DMS + if (fix.valid.location) { + printDMS( outs, fix.latitudeDMS ); + outs.print( fix.latitudeDMS.NS() ); + outs.write( ' ' ); + if (fix.longitudeDMS.degrees < 100) + outs.write( '0' ); + printDMS( outs, fix.longitudeDMS ); + outs.print( fix.longitudeDMS.EW() ); + } + outs << ','; + #endif + #ifdef GPS_FIX_HEADING + if (fix.valid.heading) + outs.print( fix.heading(), 2 ); + outs << ','; + #endif + #ifdef GPS_FIX_SPEED + if (fix.valid.speed) + outs.print( fix.speed(), 3 ); // knots + outs << ','; + #endif + #ifdef GPS_FIX_ALTITUDE + if (fix.valid.altitude) + outs.print( fix.altitude(), 2 ); + outs << ','; + #endif + + #ifdef GPS_FIX_HDOP + if (fix.valid.hdop) + outs.print( (fix.hdop * 0.001), 3 ); + outs << ','; + #endif + #ifdef GPS_FIX_VDOP + if (fix.valid.vdop) + outs.print( (fix.vdop * 0.001), 3 ); + outs << ','; + #endif + #ifdef GPS_FIX_PDOP + if (fix.valid.pdop) + outs.print( (fix.pdop * 0.001), 3 ); + outs << ','; + #endif + + #ifdef GPS_FIX_LAT_ERR + if (fix.valid.lat_err) + outs.print( fix.lat_err(), 2 ); + outs << ','; + #endif + #ifdef GPS_FIX_LON_ERR + if (fix.valid.lon_err) + outs.print( fix.lon_err(), 2 ); + outs << ','; + #endif + #ifdef GPS_FIX_ALT_ERR + if (fix.valid.alt_err) + outs.print( fix.alt_err(), 2 ); + outs << ','; + #endif + + #ifdef GPS_FIX_GEOID_HEIGHT + if (fix.valid.geoidHeight) + outs.print( fix.geoidHeight(), 2 ); + outs << ','; + #endif + + #else + + // not USE_FLOAT ---------------------- + + #ifdef GPS_FIX_LOCATION + if (fix.valid.location) + outs << fix.latitudeL() << ',' << fix.longitudeL(); + else + outs << ','; + outs << ','; + #endif + #ifdef GPS_FIX_LOCATION_DMS + if (fix.valid.location) { + printDMS( outs, fix.latitudeDMS ); + outs.print( fix.latitudeDMS.NS() ); + outs.write( ' ' ); + if (fix.longitudeDMS.degrees < 100) + outs.write( '0' ); + printDMS( outs, fix.longitudeDMS ); + outs.print( fix.longitudeDMS.EW() ); + } + outs << ','; + #endif + #ifdef GPS_FIX_HEADING + if (fix.valid.heading) + outs << fix.heading_cd(); + outs << ','; + #endif + #ifdef GPS_FIX_SPEED + if (fix.valid.speed) + outs << fix.speed_mkn(); + outs << ','; + #endif + #ifdef GPS_FIX_ALTITUDE + if (fix.valid.altitude) + outs << fix.altitude_cm(); + outs << ','; + #endif + + #ifdef GPS_FIX_HDOP + if (fix.valid.hdop) + outs << fix.hdop; + outs << ','; + #endif + #ifdef GPS_FIX_VDOP + if (fix.valid.vdop) + outs << fix.vdop; + outs << ','; + #endif + #ifdef GPS_FIX_PDOP + if (fix.valid.pdop) + outs << fix.pdop; + outs << ','; + #endif + + #ifdef GPS_FIX_LAT_ERR + if (fix.valid.lat_err) + outs << fix.lat_err_cm; + outs << ','; + #endif + #ifdef GPS_FIX_LON_ERR + if (fix.valid.lon_err) + outs << fix.lon_err_cm; + outs << ','; + #endif + #ifdef GPS_FIX_ALT_ERR + if (fix.valid.alt_err) + outs << fix.alt_err_cm; + outs << ','; + #endif + + #ifdef GPS_FIX_GEOID_HEIGHT + if (fix.valid.geoidHeight) + outs << fix.geoidHeight_cm(); + outs << ','; + #endif + + #endif + + #ifdef GPS_FIX_SATELLITES + if (fix.valid.satellites) + outs << fix.satellites; + outs << ','; + #endif + + return outs; +} + +//----------------------------- + +static const char NMEAGPS_header[] __PROGMEM = + #if defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL) | defined(NMEAGPS_TIMESTAMP_FROM_PPS) + "micros()," + #endif + + #if defined(NMEAGPS_PARSE_SATELLITES) + "[sat" + #if defined(NMEAGPS_PARSE_SATELLITE_INFO) + " elev/az @ SNR" + #endif + "]," + #endif + + #ifdef NMEAGPS_STATS + "Rx ok,Rx err,Rx chars," + #endif + + ""; + +void trace_header( Print & outs ) +{ + outs.print( (const __FlashStringHelper *) &gps_fix_header[0] ); + outs.print( (const __FlashStringHelper *) &NMEAGPS_header[0] ); + + outs << '\n'; +} + +//-------------------------- + +void trace_all( Print & outs, const NMEAGPS &gps, const gps_fix &fix ) +{ + outs << fix; + + #if defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL) | defined(NMEAGPS_TIMESTAMP_FROM_PPS) + outs << gps.UTCsecondStart(); + outs << ','; + #endif + + #if defined(NMEAGPS_PARSE_SATELLITES) + outs << '['; + + for (uint8_t i=0; i < gps.sat_count; i++) { + outs << gps.satellites[i].id; + + #if defined(NMEAGPS_PARSE_SATELLITE_INFO) + outs << ' ' << + gps.satellites[i].elevation << '/' << gps.satellites[i].azimuth; + outs << '@'; + if (gps.satellites[i].tracked) + outs << gps.satellites[i].snr; + else + outs << '-'; + #endif + + outs << ','; + } + + outs << F("],"); + #endif + + #ifdef NMEAGPS_STATS + outs << gps.statistics.ok << ',' + << gps.statistics.errors << ',' + << gps.statistics.chars << ','; + #endif + + outs << '\n'; + +} // trace_all diff --git a/src/Streamers.h b/src/Streamers.h index 870d0e3..f0a2e68 100644 --- a/src/Streamers.h +++ b/src/Streamers.h @@ -3,32 +3,15 @@ #include "Platform.h" -#include "GPSfix.h" -#include "NMEAGPS.h" - -template -Print& operator <<( Print &outs, const bool b ) - { outs.print( b ? 't' : 'f' ); return outs; } - -template -Print& operator <<( Print &outs, const char c ) { outs.print(c); return outs; } - -template -Print& operator <<( Print &outs, const uint16_t v ) { outs.print(v); return outs; } - -template -Print& operator <<( Print &outs, const uint32_t v ) { outs.print(v); return outs; } - -template -Print& operator <<( Print &outs, const int32_t v ) { outs.print(v); return outs; } - -template -Print& operator <<( Print &outs, const uint8_t v ) { outs.print(v); return outs; } - -template -Print& operator <<( Print &outs, const __FlashStringHelper *s ) -{ outs.print(s); return outs; } +extern Print & operator <<( Print & outs, const bool b ); +extern Print & operator <<( Print & outs, const char c ); +extern Print & operator <<( Print & outs, const uint16_t v ); +extern Print & operator <<( Print & outs, const uint32_t v ); +extern Print & operator <<( Print & outs, const int32_t v ); +extern Print & operator <<( Print & outs, const uint8_t v ); +extern Print & operator <<( Print & outs, const __FlashStringHelper *s ); +class gps_fix; /** * Print valid fix data to the given stream with the format @@ -40,391 +23,11 @@ Print& operator <<( Print &outs, const __FlashStringHelper *s ) * @param[in] fix gps_fix instance. * @return iostream. */ +extern Print & operator <<( Print &outs, const gps_fix &fix ); -template -Print & operator <<( Print &outs, const gps_fix &fix ) -{ - if (fix.valid.status) - outs << (uint8_t) fix.status; - outs << ','; - - #if defined(GPS_FIX_DATE) | defined(GPS_FIX_TIME) - bool someTime = false; - - #if defined(GPS_FIX_DATE) - someTime |= fix.valid.date; - #endif - - #if defined(GPS_FIX_TIME) - someTime |= fix.valid.time; - #endif - - if (someTime) { - outs << fix.dateTime << '.'; - uint16_t ms = fix.dateTime_ms(); - if (ms < 100) - outs << '0'; - if (ms < 10) - outs << '0'; - outs << ms; - } - outs << ','; - - #else - - // Date/Time not enabled, just output the interval number - static uint32_t sequence = 0L; - outs << sequence++ << ','; - - #endif - - #ifdef USE_FLOAT - #ifdef GPS_FIX_LOCATION - if (fix.valid.location) { - outs.print( fix.latitude(), 6 ); - outs << ','; - outs.print( fix.longitude(), 6 ); - } else - outs << ','; - outs << ','; - #endif - #ifdef GPS_FIX_LOCATION_DMS - if (fix.valid.location) { - printDMS( outs, fix.latitudeDMS ); - outs.print( fix.latitudeDMS.NS() ); - outs.write( ' ' ); - if (fix.longitudeDMS.degrees < 100) - outs.write( '0' ); - printDMS( outs, fix.longitudeDMS ); - outs.print( fix.longitudeDMS.EW() ); - } - outs << ','; - #endif - #ifdef GPS_FIX_HEADING - if (fix.valid.heading) - outs.print( fix.heading(), 2 ); - outs << ','; - #endif - #ifdef GPS_FIX_SPEED - if (fix.valid.speed) - outs.print( fix.speed(), 3 ); // knots - outs << ','; - #endif - #ifdef GPS_FIX_ALTITUDE - if (fix.valid.altitude) - outs.print( fix.altitude(), 2 ); - outs << ','; - #endif - - #ifdef GPS_FIX_HDOP - if (fix.valid.hdop) - outs.print( (fix.hdop * 0.001), 3 ); - outs << ','; - #endif - #ifdef GPS_FIX_VDOP - if (fix.valid.vdop) - outs.print( (fix.vdop * 0.001), 3 ); - outs << ','; - #endif - #ifdef GPS_FIX_PDOP - if (fix.valid.pdop) - outs.print( (fix.pdop * 0.001), 3 ); - outs << ','; - #endif - - #ifdef GPS_FIX_LAT_ERR - if (fix.valid.lat_err) - outs.print( fix.lat_err(), 2 ); - outs << ','; - #endif - #ifdef GPS_FIX_LON_ERR - if (fix.valid.lon_err) - outs.print( fix.lon_err(), 2 ); - outs << ','; - #endif - #ifdef GPS_FIX_ALT_ERR - if (fix.valid.alt_err) - outs.print( fix.alt_err(), 2 ); - outs << ','; - #endif - - #ifdef GPS_FIX_GEOID_HEIGHT - if (fix.valid.geoidHeight) - outs.print( fix.geoidHeight(), 2 ); - outs << ','; - #endif - - #else - - // not USE_FLOAT ---------------------- - - #ifdef GPS_FIX_LOCATION - if (fix.valid.location) - outs << fix.latitudeL() << ',' << fix.longitudeL(); - else - outs << ','; - outs << ','; - #endif - #ifdef GPS_FIX_LOCATION_DMS - if (fix.valid.location) { - printDMS( outs, fix.latitudeDMS ); - outs.print( fix.latitudeDMS.NS() ); - outs.write( ' ' ); - if (fix.longitudeDMS.degrees < 100) - outs.write( '0' ); - printDMS( outs, fix.longitudeDMS ); - outs.print( fix.longitudeDMS.EW() ); - } - outs << ','; - #endif - #ifdef GPS_FIX_HEADING - if (fix.valid.heading) - outs << fix.heading_cd(); - outs << ','; - #endif - #ifdef GPS_FIX_SPEED - if (fix.valid.speed) - outs << fix.speed_mkn(); - outs << ','; - #endif - #ifdef GPS_FIX_ALTITUDE - if (fix.valid.altitude) - outs << fix.altitude_cm(); - outs << ','; - #endif - - #ifdef GPS_FIX_HDOP - if (fix.valid.hdop) - outs << fix.hdop; - outs << ','; - #endif - #ifdef GPS_FIX_VDOP - if (fix.valid.vdop) - outs << fix.vdop; - outs << ','; - #endif - #ifdef GPS_FIX_PDOP - if (fix.valid.pdop) - outs << fix.pdop; - outs << ','; - #endif - - #ifdef GPS_FIX_LAT_ERR - if (fix.valid.lat_err) - outs << fix.lat_err_cm; - outs << ','; - #endif - #ifdef GPS_FIX_LON_ERR - if (fix.valid.lon_err) - outs << fix.lon_err_cm; - outs << ','; - #endif - #ifdef GPS_FIX_ALT_ERR - if (fix.valid.alt_err) - outs << fix.alt_err_cm; - outs << ','; - #endif - - #ifdef GPS_FIX_GEOID_HEIGHT - if (fix.valid.geoidHeight) - outs << fix.geoidHeight_cm(); - outs << ','; - #endif - - #endif - - #ifdef GPS_FIX_SATELLITES - if (fix.valid.satellites) - outs << fix.satellites; - outs << ','; - #endif - - return outs; -} - -const char gps_fix_header[] __PROGMEM = - "Status," - - #if defined(GPS_FIX_DATE) | defined(GPS_FIX_TIME) - - "UTC " - - #if defined(GPS_FIX_DATE) - "Date" - #endif - #if defined(GPS_FIX_DATE) & defined(GPS_FIX_TIME) - "/" - #endif - #if defined(GPS_FIX_TIME) - "Time" - #endif - - #else - "s" - #endif - - "," - - #ifdef GPS_FIX_LOCATION - "Lat,Lon," - #endif - - #ifdef GPS_FIX_LOCATION_DMS - "DMS," - #endif - - #if defined(GPS_FIX_HEADING) - "Hdg," - #endif - - #if defined(GPS_FIX_SPEED) - "Spd," - #endif - - #if defined(GPS_FIX_ALTITUDE) - "Alt," - #endif - - #if defined(GPS_FIX_HDOP) - "HDOP," - #endif - - #if defined(GPS_FIX_VDOP) - "VDOP," - #endif - - #if defined(GPS_FIX_PDOP) - "PDOP," - #endif - - #if defined(GPS_FIX_LAT_ERR) - "Lat err," - #endif - - #if defined(GPS_FIX_LON_ERR) - "Lon err," - #endif - - #if defined(GPS_FIX_ALT_ERR) - "Alt err," - #endif - - #if defined(GPS_FIX_GEOID_HEIGHT) - "Geoid Ht," - #endif - - #if defined(GPS_FIX_SATELLITES) - "Sats," - #endif - - ; - -//............... - -#ifdef GPS_FIX_LOCATION_DMS - - template - static void printDMS( Print & outs, const DMS_t & dms ) - { - if (dms.degrees < 10) - outs.write( '0' ); - outs.print( dms.degrees ); - outs.write( ' ' ); - - if (dms.minutes < 10) - outs.write( '0' ); - outs.print( dms.minutes ); - outs.print( F("\' ") ); - - if (dms.seconds_whole < 10) - outs.write( '0' ); - outs.print( dms.seconds_whole ); - outs.write( '.' ); - - if (dms.seconds_frac < 100) - outs.write( '0' ); - if (dms.seconds_frac < 10) - outs.write( '0' ); - outs.print( dms.seconds_frac ); - outs.print( F("\" ") ); - - } // printDMS - -#endif - -//............... -//----------------------------- - -static const char NMEAGPS_header[] __PROGMEM = - #if defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL) | defined(NMEAGPS_TIMESTAMP_FROM_PPS) - "micros()," - #endif - - #if defined(NMEAGPS_PARSE_SATELLITES) - "[sat" - #if defined(NMEAGPS_PARSE_SATELLITE_INFO) - " elev/az @ SNR" - #endif - "]," - #endif - - #ifdef NMEAGPS_STATS - "Rx ok,Rx err,Rx chars," - #endif - - ""; - -template -void trace_header( Print & outs ) -{ - outs.print( (const __FlashStringHelper *) &gps_fix_header[0] ); - outs.print( (const __FlashStringHelper *) &NMEAGPS_header[0] ); - - outs << '\n'; -} - -//-------------------------- - -template -void trace_all( Print & outs, const NMEAGPS &gps, const gps_fix &fix ) -{ - outs << fix; - - #if defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL) | defined(NMEAGPS_TIMESTAMP_FROM_PPS) - outs << gps.UTCsecondStart(); - outs << ','; - #endif - - #if defined(NMEAGPS_PARSE_SATELLITES) - outs << '['; - - for (uint8_t i=0; i < gps.sat_count; i++) { - outs << gps.satellites[i].id; - - #if defined(NMEAGPS_PARSE_SATELLITE_INFO) - outs << ' ' << - gps.satellites[i].elevation << '/' << gps.satellites[i].azimuth; - outs << '@'; - if (gps.satellites[i].tracked) - outs << gps.satellites[i].snr; - else - outs << '-'; - #endif - - outs << ','; - } - - outs << F("],"); - #endif - - #ifdef NMEAGPS_STATS - outs << gps.statistics.ok << ',' - << gps.statistics.errors << ',' - << gps.statistics.chars << ','; - #endif - - outs << '\n'; +class NMEAGPS; -} // trace_all +extern void trace_header( Print & outs ); +extern void trace_all( Print & outs, const NMEAGPS &gps, const gps_fix &fix ); #endif diff --git a/src/platforms/Print.h b/src/platforms/Print.h index 1236c5e..1b2da9a 100644 --- a/src/platforms/Print.h +++ b/src/platforms/Print.h @@ -1,8 +1,6 @@ #pragma once #include -// If there is not already an implementation for your platform, -// implement these functions. class Print { public: void print(char) const; From 0b2e59f02d455aa78f087ab0ef8bc2d7aee58cbd Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Wed, 20 Sep 2017 20:14:24 +0200 Subject: [PATCH 33/38] Revert "feat: introduce templates for arduino classes" This reverts commit 491cf1d297e5496a8d34ce673dc45287cb4ec6b4. --- src/NMEAGPS.cpp | 159 ++++++++++++++++++++++++++++++++++++++ src/NMEAGPS.h | 168 +---------------------------------------- src/Platform.h | 12 +-- src/platforms/Stream.h | 4 +- 4 files changed, 166 insertions(+), 177 deletions(-) diff --git a/src/NMEAGPS.cpp b/src/NMEAGPS.cpp index 0afc9ca..606ec58 100644 --- a/src/NMEAGPS.cpp +++ b/src/NMEAGPS.cpp @@ -30,6 +30,13 @@ #endif +#ifndef CR + #define CR ((char)13) +#endif +#ifndef LF + #define LF ((char)10) +#endif + //---------------------------------------------------------------- // Parse a single character as HEX and returns byte value. @@ -42,6 +49,15 @@ inline static uint8_t parseHEX(char a) return a - '0'; } +//---------------------------------------------------------------- +// Format lower nybble of value as HEX and returns character. + +static char formatHex( uint8_t val ) +{ + val &= 0x0F; + return (val >= 10) ? ((val - 10) + 'A') : (val + '0'); +} + //---------------------------------------------------------------- inline uint8_t to_binary(uint8_t value) @@ -1571,3 +1587,146 @@ const gps_fix NMEAGPS::read() } // read //---------------------------------------------------------------- + +void NMEAGPS::poll( Stream *device, nmea_msg_t msg ) +{ + // Only the ublox documentation references talker ID "EI". + // Other manufacturer's devices use "II" and "GP" talker IDs for the GPQ sentence. + // However, "GP" is reserved for the GPS device, so it seems inconsistent + // to use that talker ID when requesting something from the GPS device. + + #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gga[] __PROGMEM = "EIGPQ,GGA"; + #endif + #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gll[] __PROGMEM = "EIGPQ,GLL"; + #endif + #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gsa[] __PROGMEM = "EIGPQ,GSA"; + #endif + #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gst[] __PROGMEM = "EIGPQ,GST"; + #endif + #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gsv[] __PROGMEM = "EIGPQ,GSV"; + #endif + #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char rmc[] __PROGMEM = "EIGPQ,RMC"; + #endif + #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char vtg[] __PROGMEM = "EIGPQ,VTG"; + #endif + #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char zda[] __PROGMEM = "EIGPQ,ZDA"; + #endif + + static const char * const poll_msgs[] __PROGMEM = + { + #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) + gga, + #endif + #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) + gll, + #endif + #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) + gsa, + #endif + #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) + gst, + #endif + #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) + gsv, + #endif + #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) + rmc, + #endif + #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) + vtg, + #endif + #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) + zda + #endif + }; + + if ((NMEA_FIRST_MSG <= msg) && (msg <= NMEA_LAST_MSG)) { + #ifdef __AVR__ + const __FlashStringHelper * pollCmd = + (const __FlashStringHelper *) pgm_read_word(&poll_msgs[msg-NMEA_FIRST_MSG]); + #else + const __FlashStringHelper * pollCmd = + (const __FlashStringHelper *) poll_msgs[msg-NMEA_FIRST_MSG]; + #endif + send_P( device, pollCmd ); + } + +} // poll + +//---------------------------------------------------------------- + +static void send_trailer( Stream *device, uint8_t crc ) +{ + device->print('*'); + + char hexDigit = formatHex( crc>>4 ); + device->print( hexDigit ); + + hexDigit = formatHex( crc ); + device->print( hexDigit ); + + device->print( CR ); + device->print( LF ); + +} // send_trailer + +//---------------------------------------------------------------- + +void NMEAGPS::send( Stream *device, const char *msg ) +{ + if (msg && *msg) { + if (*msg == '$') + msg++; + device->print('$'); + uint8_t sent_trailer = 0; + uint8_t crc = 0; + while (*msg) { + if ((*msg == '*') || (sent_trailer > 0)) + sent_trailer++; + else + crc ^= *msg; + device->print( *msg++ ); + } + + if (!sent_trailer) + send_trailer( device, crc ); + } + +} // send + +//---------------------------------------------------------------- + +void NMEAGPS::send_P( Stream *device, const __FlashStringHelper *msg ) +{ + if (msg) { + const char *ptr = (const char *)msg; + char chr = pgm_read_byte(ptr++); + + device->print('$'); + if (chr == '$') + chr = pgm_read_byte(ptr++); + uint8_t sent_trailer = 0; + uint8_t crc = 0; + while (chr) { + if ((chr == '*') || (sent_trailer > 0)) + sent_trailer++; + else + crc ^= chr; + device->print( chr ); + + chr = pgm_read_byte(ptr++); + } + + if (!sent_trailer) + send_trailer( device, crc ); + } + +} // send_P diff --git a/src/NMEAGPS.h b/src/NMEAGPS.h index 65e2339..66e71d1 100644 --- a/src/NMEAGPS.h +++ b/src/NMEAGPS.h @@ -102,7 +102,6 @@ class NMEAGPS // are available to be "read" from the fix buffer. The GPS port // object is passed in so a char can be read if port.available(). - template uint8_t available( Stream & port ) { if (processing_style == PS_POLLING) @@ -229,17 +228,13 @@ class NMEAGPS //....................................................................... // Request the specified NMEA sentence. Not all devices will respond. - template static void poll( Stream *device, nmea_msg_t msg ); //....................................................................... // Send a message to the GPS device. // The '$' is optional, and the '*' and CS will be added automatically. - template static void send( Stream *device, const char *msg ); - - template static void send_P( Stream *device, const __FlashStringHelper *msg ); //....................................................................... @@ -294,7 +289,6 @@ class NMEAGPS // uint32_t elapsedUS = (currentCount - captureCount) * countUS; // gps.UTCsecondStart( micros() - elapsedUS ); // } - #endif //....................................................................... @@ -343,13 +337,13 @@ class NMEAGPS //....................................................................... // Control access to this object. This preserves atomicity when // the processing style is interrupt-driven. - + void lock() const { if (processing_style == PS_INTERRUPT) noInterrupts(); } - + void unlock() const { if (processing_style == PS_INTERRUPT) @@ -671,162 +665,4 @@ class NMEAGPS } NEOGPS_PACKED; - -template -void NMEAGPS::poll( Stream *device, nmea_msg_t msg ) -{ - // Only the ublox documentation references talker ID "EI". - // Other manufacturer's devices use "II" and "GP" talker IDs for the GPQ sentence. - // However, "GP" is reserved for the GPS device, so it seems inconsistent - // to use that talker ID when requesting something from the GPS device. - - #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gga[] __PROGMEM = "EIGPQ,GGA"; - #endif - #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gll[] __PROGMEM = "EIGPQ,GLL"; - #endif - #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gsa[] __PROGMEM = "EIGPQ,GSA"; - #endif - #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gst[] __PROGMEM = "EIGPQ,GST"; - #endif - #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gsv[] __PROGMEM = "EIGPQ,GSV"; - #endif - #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char rmc[] __PROGMEM = "EIGPQ,RMC"; - #endif - #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char vtg[] __PROGMEM = "EIGPQ,VTG"; - #endif - #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char zda[] __PROGMEM = "EIGPQ,ZDA"; - #endif - - static const char * const poll_msgs[] __PROGMEM = - { - #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) - gga, - #endif - #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) - gll, - #endif - #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) - gsa, - #endif - #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) - gst, - #endif - #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) - gsv, - #endif - #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) - rmc, - #endif - #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) - vtg, - #endif - #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) - zda - #endif - }; - - if ((NMEA_FIRST_MSG <= msg) && (msg <= NMEA_LAST_MSG)) { - #ifdef __AVR__ - const __FlashStringHelper * pollCmd = - (const __FlashStringHelper *) pgm_read_word(&poll_msgs[msg-NMEA_FIRST_MSG]); - #else - const __FlashStringHelper * pollCmd = - (const __FlashStringHelper *) poll_msgs[msg-NMEA_FIRST_MSG]; - #endif - send_P( device, pollCmd ); - } - -} // poll - -//---------------------------------------------------------------- -// Format lower nybble of value as HEX and returns character. - -static char formatHex( uint8_t val ) -{ - val &= 0x0F; - return (val >= 10) ? ((val - 10) + 'A') : (val + '0'); -} - -//---------------------------------------------------------------- - -template -static void send_trailer( Stream *device, uint8_t crc ) -{ - - device->print('*'); - - char hexDigit = formatHex( crc>>4 ); - device->print( hexDigit ); - - hexDigit = formatHex( crc ); - device->print( hexDigit ); - - device->print( CR ); - device->print( LF ); - -} // send_trailer - -//---------------------------------------------------------------- - -template -void NMEAGPS::send( Stream *device, const char *msg ) -{ - if (msg && *msg) { - if (*msg == '$') - msg++; - device->print('$'); - uint8_t sent_trailer = 0; - uint8_t crc = 0; - while (*msg) { - if ((*msg == '*') || (sent_trailer > 0)) - sent_trailer++; - else - crc ^= *msg; - device->print( *msg++ ); - } - - if (!sent_trailer) - send_trailer( device, crc ); - } - -} // send - -//---------------------------------------------------------------- - -template -void NMEAGPS::send_P( Stream *device, const __FlashStringHelper *msg ) -{ - if (msg) { - const char *ptr = (const char *)msg; - char chr = pgm_read_byte(ptr++); - - device->print('$'); - if (chr == '$') - chr = pgm_read_byte(ptr++); - uint8_t sent_trailer = 0; - uint8_t crc = 0; - while (chr) { - if ((chr == '*') || (sent_trailer > 0)) - sent_trailer++; - else - crc ^= chr; - device->print( chr ); - - chr = pgm_read_byte(ptr++); - } - - if (!sent_trailer) - send_trailer( device, crc ); - } - -} // send_P - #endif diff --git a/src/Platform.h b/src/Platform.h index 510e320..9631fe3 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -13,10 +13,11 @@ #include #endif #else + #include "platforms/Stream.h" + #include "platforms/Print.h" #include "platforms/System.h" #include - #define __PROGMEM #define PROGMEM #define pgm_read_byte(x) (*(x)) @@ -26,14 +27,7 @@ #include - #define PI 3.14159265358979323846 + const double PI = 3.14159265358979323846; #define TWO_PI PI * 2.0 #endif - -#ifndef CR - #define CR ((char)13) -#endif -#ifndef LF - #define LF ((char)10) -#endif diff --git a/src/platforms/Stream.h b/src/platforms/Stream.h index 79484db..c5d4231 100644 --- a/src/platforms/Stream.h +++ b/src/platforms/Stream.h @@ -6,6 +6,6 @@ class Stream { public: bool available(); - char read(); - void print(char); + uint8_t read(); + void print(uint8_t); }; From f2fbf1f3d226785d09f069424ad590fb6c0a67ad Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Wed, 20 Sep 2017 20:14:25 +0200 Subject: [PATCH 34/38] Revert "feat[Platforms]: adapt DMS.h DMS.cpp Location.h" This reverts commit e9706e3a419554e56ad9f915e9574423326c8374. --- src/DMS.cpp | 6 ++++++ src/DMS.h | 10 ++++++---- src/Location.h | 6 +++++- src/Platform.h | 5 +++-- src/Streamers.h | 4 ++-- src/platforms/Print.h | 10 ++++------ 6 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/DMS.cpp b/src/DMS.cpp index 82f0e96..1a6b2a0 100644 --- a/src/DMS.cpp +++ b/src/DMS.cpp @@ -18,6 +18,10 @@ #include "DMS.h" +#ifdef ARDUINO + #include +#endif + //---------------------------------------------------------------- // Note that no division is used, and shifts are on byte boundaries. Fast! @@ -64,6 +68,7 @@ void DMS_t::From( int32_t deg_1E7 ) } // From //---------------------------------------------------------------- +#ifdef ARDUINO Print & operator << ( Print & outs, const DMS_t & dms ) { @@ -118,3 +123,4 @@ void DMS_t::printDDDMMmmmm( Print & outs ) const outs.print( '0' ); outs.print( mmmm ); } +#endif diff --git a/src/DMS.h b/src/DMS.h index b1cee52..0a23a13 100644 --- a/src/DMS.h +++ b/src/DMS.h @@ -20,10 +20,10 @@ // #include "NeoGPS_cfg.h" -#include "Platform.h" #include - -class Print; +#ifdef ARDUINO + class Print; +#endif enum Hemisphere_t { NORTH_H = 0, SOUTH_H = 1, EAST_H = 0, WEST_H = 1 }; @@ -53,6 +53,8 @@ class DMS_t } NEOGPS_PACKED; -extern Print & operator << ( Print & outs, const DMS_t & ); +#ifdef ARDUINO + extern Print & operator << ( Print & outs, const DMS_t & ); +#endif #endif diff --git a/src/Location.h b/src/Location.h index 4ef3171..747b5fa 100644 --- a/src/Location.h +++ b/src/Location.h @@ -1,7 +1,11 @@ #ifndef NEOGPS_LOCATION_H #define NEOGPS_LOCATION_H -#include "Platform.h" +#ifdef ARDUINO + #include +#else + #include "CosaCompat.h" +#endif #include "NeoGPS_cfg.h" diff --git a/src/Platform.h b/src/Platform.h index 9631fe3..425a768 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -26,8 +26,9 @@ #define str_P char * #include + constexpr double pi() { return std::atan(1)*4; } - const double PI = 3.14159265358979323846; - #define TWO_PI PI * 2.0 + #define PI pi() + #define TWO_PI pi() * 2.0 #endif diff --git a/src/Streamers.h b/src/Streamers.h index f0a2e68..a356302 100644 --- a/src/Streamers.h +++ b/src/Streamers.h @@ -1,7 +1,7 @@ #ifndef STREAMERS_H #define STREAMERS_H -#include "Platform.h" +#include extern Print & operator <<( Print & outs, const bool b ); extern Print & operator <<( Print & outs, const char c ); @@ -30,4 +30,4 @@ class NMEAGPS; extern void trace_header( Print & outs ); extern void trace_all( Print & outs, const NMEAGPS &gps, const gps_fix &fix ); -#endif +#endif \ No newline at end of file diff --git a/src/platforms/Print.h b/src/platforms/Print.h index 1b2da9a..1331b4f 100644 --- a/src/platforms/Print.h +++ b/src/platforms/Print.h @@ -3,10 +3,8 @@ #include class Print { public: - void print(char) const; - void print(uint8_t) const; - void print(uint16_t) const; - void print(uint32_t) const; - void print(const char *) const; - void write(char) const; + void print(uint8_t); + void print(uint16_t); + void print(uint32_t); + void write(char); }; From 0b6257292052ca32fd9472d757111e7bce9f0576 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Wed, 20 Sep 2017 20:14:26 +0200 Subject: [PATCH 35/38] Revert "feat: add str_P to Platform.h" This reverts commit 852821b0698781ed970c8884225226905fd0971e. --- src/NeoTime.cpp | 12 ++++-------- src/Platform.h | 1 - 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/NeoTime.cpp b/src/NeoTime.cpp index b84226f..dbbe5fd 100644 --- a/src/NeoTime.cpp +++ b/src/NeoTime.cpp @@ -50,14 +50,10 @@ using NeoGPS::time_t; bool time_t::parse(str_P s) { - #ifdef AVR - static size_t BUF_MAX = 32; - char buf[BUF_MAX]; - strcpy_P(buf, s); - char* sp = &buf[0]; - #else - char* sp = &s[0]; - #endif + static size_t BUF_MAX = 32; + char buf[BUF_MAX]; + strcpy_P(buf, s); + char* sp = &buf[0]; uint16_t value = strtoul(sp, &sp, 10); if (*sp != '-') return false; diff --git a/src/Platform.h b/src/Platform.h index 425a768..1f89640 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -23,7 +23,6 @@ #define pgm_read_byte(x) (*(x)) #define __FlashStringHelper char #define F(x) (x) - #define str_P char * #include constexpr double pi() { return std::atan(1)*4; } From 7908a3897e4affcb8265c54fa4ba4e78cd42f035 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Wed, 20 Sep 2017 20:14:27 +0200 Subject: [PATCH 36/38] Revert "feat: continue Arduino compat declarations" This reverts commit 31fc16163e3313a022e9e2d5f71efdd18162c98d. --- src/NMEAGPS.cpp | 4 ++-- src/NeoTime.cpp | 46 +++++++++++++++++++++++-------------------- src/NeoTime.h | 25 +++++++++++++---------- src/Platform.h | 4 +--- src/platforms/Port.h | 6 ++++++ src/platforms/Print.h | 10 ---------- 6 files changed, 49 insertions(+), 46 deletions(-) create mode 100644 src/platforms/Port.h delete mode 100644 src/platforms/Print.h diff --git a/src/NMEAGPS.cpp b/src/NMEAGPS.cpp index 606ec58..927ec1f 100644 --- a/src/NMEAGPS.cpp +++ b/src/NMEAGPS.cpp @@ -444,7 +444,7 @@ static const char * const std_nmea[] __PROGMEM = const NMEAGPS::msg_table_t NMEAGPS::nmea_msg_table __PROGMEM = { NMEAGPS::NMEA_FIRST_MSG, - (const msg_table_t *) nullptr, + (const msg_table_t *) 0x00, sizeof(std_nmea)/sizeof(std_nmea[0]), std_nmea }; @@ -659,7 +659,7 @@ const __FlashStringHelper *NMEAGPS::string_for( nmea_msg_t msg ) const continue; #endif - return (const __FlashStringHelper *) nullptr; + return (const __FlashStringHelper *) 0x00; } } // string_for diff --git a/src/NeoTime.cpp b/src/NeoTime.cpp index dbbe5fd..77dd584 100644 --- a/src/NeoTime.cpp +++ b/src/NeoTime.cpp @@ -24,27 +24,31 @@ // For strtoul declaration #include -Print & operator<<( Print& outs, const NeoGPS::time_t& t ) -{ - outs.print( t.full_year( t.year ) ); - outs.write( '-' ); - if (t.month < 10) outs.write( '0' ); - outs.print( t.month ); - outs.write( '-' ); - if (t.date < 10) outs.write( '0' ); - outs.print( t.date ); - outs.write( ' ' ); - if (t.hours < 10) outs.write( '0' ); - outs.print( t.hours ); - outs.write( ':' ); - if (t.minutes < 10) outs.write( '0' ); - outs.print( t.minutes ); - outs.write( ':' ); - if (t.seconds < 10) outs.write( '0' ); - outs.print( t.seconds ); - - return outs; -} +#ifdef ARDUINO + #include + + Print & operator<<( Print& outs, const NeoGPS::time_t& t ) + { + outs.print( t.full_year( t.year ) ); + outs.write( '-' ); + if (t.month < 10) outs.write( '0' ); + outs.print( t.month ); + outs.write( '-' ); + if (t.date < 10) outs.write( '0' ); + outs.print( t.date ); + outs.write( ' ' ); + if (t.hours < 10) outs.write( '0' ); + outs.print( t.hours ); + outs.write( ':' ); + if (t.minutes < 10) outs.write( '0' ); + outs.print( t.minutes ); + outs.write( ':' ); + if (t.seconds < 10) outs.write( '0' ); + outs.print( t.seconds ); + + return outs; + } +#endif using NeoGPS::time_t; diff --git a/src/NeoTime.h b/src/NeoTime.h index b0fd35f..d92422b 100644 --- a/src/NeoTime.h +++ b/src/NeoTime.h @@ -22,9 +22,12 @@ #ifndef TIME_H #define TIME_H -#include "Platform.h" +#ifdef ARDUINO + #include +#endif #include "NeoGPS_cfg.h" +#include "CosaCompat.h" namespace NeoGPS { @@ -297,14 +300,16 @@ struct time_t { }; // namespace NeoGPS -class Print; - -/** - * Print the date/time to the given stream with the format "YYYY-MM-DD HH:MM:SS". - * @param[in] outs output stream. - * @param[in] t time structure. - * @return iostream. - */ -Print & operator <<( Print & outs, const NeoGPS::time_t &t ); +#ifdef ARDUINO + class Print; + + /** + * Print the date/time to the given stream with the format "YYYY-MM-DD HH:MM:SS". + * @param[in] outs output stream. + * @param[in] t time structure. + * @return iostream. + */ + Print & operator <<( Print & outs, const NeoGPS::time_t &t ); +#endif #endif diff --git a/src/Platform.h b/src/Platform.h index 1f89640..47bb9d7 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -5,16 +5,14 @@ **/ #ifdef ARDUINO #include - #include - #include #ifdef __AVR__ #include #endif #else #include "platforms/Stream.h" - #include "platforms/Print.h" + #include "platforms/Port.h" #include "platforms/System.h" #include diff --git a/src/platforms/Port.h b/src/platforms/Port.h new file mode 100644 index 0000000..97663d0 --- /dev/null +++ b/src/platforms/Port.h @@ -0,0 +1,6 @@ +#pragma once + +#include +class Port { +public: +}; diff --git a/src/platforms/Print.h b/src/platforms/Print.h deleted file mode 100644 index 1331b4f..0000000 --- a/src/platforms/Print.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include -class Print { -public: - void print(uint8_t); - void print(uint16_t); - void print(uint32_t); - void write(char); -}; From 2b7d62aa1f97e43dd69df54a8d731c114cea627c Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Wed, 20 Sep 2017 20:14:28 +0200 Subject: [PATCH 37/38] Revert "feat: extract functionality into Arduino compat. libs" This reverts commit 813f8be4da5e5da205fbf4a6c2aa626aa3a0cd40. --- src/CosaCompat.h | 15 +++ src/NMEAGPS.cpp | 283 +++++++++++++++++++++-------------------- src/NMEAGPS.h | 92 ++++++++------ src/Platform.h | 31 ----- src/platforms/Port.h | 6 - src/platforms/Stream.h | 11 -- src/platforms/System.h | 4 - 7 files changed, 212 insertions(+), 230 deletions(-) delete mode 100644 src/Platform.h delete mode 100644 src/platforms/Port.h delete mode 100644 src/platforms/Stream.h delete mode 100644 src/platforms/System.h diff --git a/src/CosaCompat.h b/src/CosaCompat.h index e4f06c5..a2912f3 100644 --- a/src/CosaCompat.h +++ b/src/CosaCompat.h @@ -15,4 +15,19 @@ typedef PGM_P str_P; #define __PROGMEM PROGMEM +#ifndef ARDUINO + #include + #define PROGMEM + + #define pgm_read_byte(x) (*(x)) + #define __FlashStringHelper char + #define F(x) (x) + + #include + constexpr double pi() { return std::atan(1)*4; } + + #define PI pi() + #define TWO_PI pi() * 2 +#endif + #endif diff --git a/src/NMEAGPS.cpp b/src/NMEAGPS.cpp index 927ec1f..aae0c67 100644 --- a/src/NMEAGPS.cpp +++ b/src/NMEAGPS.cpp @@ -18,6 +18,9 @@ #include "NMEAGPS.h" +#ifdef ARDUINO + #include +#endif // Check configurations @@ -1588,145 +1591,147 @@ const gps_fix NMEAGPS::read() //---------------------------------------------------------------- -void NMEAGPS::poll( Stream *device, nmea_msg_t msg ) -{ - // Only the ublox documentation references talker ID "EI". - // Other manufacturer's devices use "II" and "GP" talker IDs for the GPQ sentence. - // However, "GP" is reserved for the GPS device, so it seems inconsistent - // to use that talker ID when requesting something from the GPS device. - - #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gga[] __PROGMEM = "EIGPQ,GGA"; - #endif - #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gll[] __PROGMEM = "EIGPQ,GLL"; - #endif - #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gsa[] __PROGMEM = "EIGPQ,GSA"; - #endif - #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gst[] __PROGMEM = "EIGPQ,GST"; - #endif - #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gsv[] __PROGMEM = "EIGPQ,GSV"; - #endif - #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char rmc[] __PROGMEM = "EIGPQ,RMC"; - #endif - #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char vtg[] __PROGMEM = "EIGPQ,VTG"; - #endif - #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char zda[] __PROGMEM = "EIGPQ,ZDA"; - #endif - - static const char * const poll_msgs[] __PROGMEM = - { - #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) - gga, - #endif - #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) - gll, - #endif - #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) - gsa, - #endif - #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) - gst, - #endif - #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) - gsv, - #endif - #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) - rmc, - #endif - #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) - vtg, - #endif - #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) - zda - #endif - }; - - if ((NMEA_FIRST_MSG <= msg) && (msg <= NMEA_LAST_MSG)) { - #ifdef __AVR__ - const __FlashStringHelper * pollCmd = - (const __FlashStringHelper *) pgm_read_word(&poll_msgs[msg-NMEA_FIRST_MSG]); - #else - const __FlashStringHelper * pollCmd = - (const __FlashStringHelper *) poll_msgs[msg-NMEA_FIRST_MSG]; +#ifdef ARDUINO + void NMEAGPS::poll( Stream *device, nmea_msg_t msg ) + { + // Only the ublox documentation references talker ID "EI". + // Other manufacturer's devices use "II" and "GP" talker IDs for the GPQ sentence. + // However, "GP" is reserved for the GPS device, so it seems inconsistent + // to use that talker ID when requesting something from the GPS device. + + #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gga[] __PROGMEM = "EIGPQ,GGA"; #endif - send_P( device, pollCmd ); - } - -} // poll - -//---------------------------------------------------------------- - -static void send_trailer( Stream *device, uint8_t crc ) -{ - device->print('*'); - - char hexDigit = formatHex( crc>>4 ); - device->print( hexDigit ); - - hexDigit = formatHex( crc ); - device->print( hexDigit ); - - device->print( CR ); - device->print( LF ); - -} // send_trailer - -//---------------------------------------------------------------- - -void NMEAGPS::send( Stream *device, const char *msg ) -{ - if (msg && *msg) { - if (*msg == '$') - msg++; - device->print('$'); - uint8_t sent_trailer = 0; - uint8_t crc = 0; - while (*msg) { - if ((*msg == '*') || (sent_trailer > 0)) - sent_trailer++; - else - crc ^= *msg; - device->print( *msg++ ); + #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gll[] __PROGMEM = "EIGPQ,GLL"; + #endif + #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gsa[] __PROGMEM = "EIGPQ,GSA"; + #endif + #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gst[] __PROGMEM = "EIGPQ,GST"; + #endif + #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gsv[] __PROGMEM = "EIGPQ,GSV"; + #endif + #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char rmc[] __PROGMEM = "EIGPQ,RMC"; + #endif + #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char vtg[] __PROGMEM = "EIGPQ,VTG"; + #endif + #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char zda[] __PROGMEM = "EIGPQ,ZDA"; + #endif + + static const char * const poll_msgs[] __PROGMEM = + { + #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) + gga, + #endif + #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) + gll, + #endif + #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) + gsa, + #endif + #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) + gst, + #endif + #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) + gsv, + #endif + #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) + rmc, + #endif + #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) + vtg, + #endif + #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) + zda + #endif + }; + + if ((NMEA_FIRST_MSG <= msg) && (msg <= NMEA_LAST_MSG)) { + #ifdef __AVR__ + const __FlashStringHelper * pollCmd = + (const __FlashStringHelper *) pgm_read_word(&poll_msgs[msg-NMEA_FIRST_MSG]); + #else + const __FlashStringHelper * pollCmd = + (const __FlashStringHelper *) poll_msgs[msg-NMEA_FIRST_MSG]; + #endif + send_P( device, pollCmd ); } - - if (!sent_trailer) - send_trailer( device, crc ); - } - -} // send - -//---------------------------------------------------------------- - -void NMEAGPS::send_P( Stream *device, const __FlashStringHelper *msg ) -{ - if (msg) { - const char *ptr = (const char *)msg; - char chr = pgm_read_byte(ptr++); - - device->print('$'); - if (chr == '$') - chr = pgm_read_byte(ptr++); - uint8_t sent_trailer = 0; - uint8_t crc = 0; - while (chr) { - if ((chr == '*') || (sent_trailer > 0)) - sent_trailer++; - else - crc ^= chr; - device->print( chr ); - - chr = pgm_read_byte(ptr++); + + } // poll + + //---------------------------------------------------------------- + + static void send_trailer( Stream *device, uint8_t crc ) + { + device->print('*'); + + char hexDigit = formatHex( crc>>4 ); + device->print( hexDigit ); + + hexDigit = formatHex( crc ); + device->print( hexDigit ); + + device->print( CR ); + device->print( LF ); + + } // send_trailer + + //---------------------------------------------------------------- + + void NMEAGPS::send( Stream *device, const char *msg ) + { + if (msg && *msg) { + if (*msg == '$') + msg++; + device->print('$'); + uint8_t sent_trailer = 0; + uint8_t crc = 0; + while (*msg) { + if ((*msg == '*') || (sent_trailer > 0)) + sent_trailer++; + else + crc ^= *msg; + device->print( *msg++ ); + } + + if (!sent_trailer) + send_trailer( device, crc ); } - - if (!sent_trailer) - send_trailer( device, crc ); - } - -} // send_P + + } // send + + //---------------------------------------------------------------- + + void NMEAGPS::send_P( Stream *device, const __FlashStringHelper *msg ) + { + if (msg) { + const char *ptr = (const char *)msg; + char chr = pgm_read_byte(ptr++); + + device->print('$'); + if (chr == '$') + chr = pgm_read_byte(ptr++); + uint8_t sent_trailer = 0; + uint8_t crc = 0; + while (chr) { + if ((chr == '*') || (sent_trailer > 0)) + sent_trailer++; + else + crc ^= chr; + device->print( chr ); + + chr = pgm_read_byte(ptr++); + } + + if (!sent_trailer) + send_trailer( device, crc ); + } + + } // send_P +#endif diff --git a/src/NMEAGPS.h b/src/NMEAGPS.h index 66e71d1..4ef5dd3 100644 --- a/src/NMEAGPS.h +++ b/src/NMEAGPS.h @@ -21,7 +21,12 @@ #include "CosaCompat.h" -#include "Platform.h" +#ifdef ARDUINO + #include + #ifdef __AVR__ + #include + #endif +#endif #include "GPSfix.h" #include "NMEAGPS_cfg.h" @@ -93,22 +98,24 @@ class NMEAGPS CONST_CLASS_DATA nmea_msg_t NMEA_FIRST_MSG = (nmea_msg_t) (NMEA_UNKNOWN+1); CONST_CLASS_DATA nmea_msg_t NMEA_LAST_MSG = (nmea_msg_t) (NMEAMSG_END-1); - //======================================================================= - // FIX-ORIENTED methods: available, read and handle - //======================================================================= - - //....................................................................... - // The available(...) functions return the number of *fixes* that - // are available to be "read" from the fix buffer. The GPS port - // object is passed in so a char can be read if port.available(). - - uint8_t available( Stream & port ) - { - if (processing_style == PS_POLLING) - while (port.available()) - handle( port.read() ); - return _available(); - } + #ifdef ARDUINO + //======================================================================= + // FIX-ORIENTED methods: available, read and handle + //======================================================================= + + //....................................................................... + // The available(...) functions return the number of *fixes* that + // are available to be "read" from the fix buffer. The GPS port + // object is passed in so a char can be read if port.available(). + + uint8_t available( Stream & port ) + { + if (processing_style == PS_POLLING) + while (port.available()) + handle( port.read() ); + return _available(); + } + #endif uint8_t available() const volatile { return _available(); }; @@ -225,17 +232,19 @@ class NMEAGPS } statistics; #endif - //....................................................................... - // Request the specified NMEA sentence. Not all devices will respond. - - static void poll( Stream *device, nmea_msg_t msg ); - - //....................................................................... - // Send a message to the GPS device. - // The '$' is optional, and the '*' and CS will be added automatically. - - static void send( Stream *device, const char *msg ); - static void send_P( Stream *device, const __FlashStringHelper *msg ); + #ifdef ARDUINO + //....................................................................... + // Request the specified NMEA sentence. Not all devices will respond. + + static void poll( Stream *device, nmea_msg_t msg ); + + //....................................................................... + // Send a message to the GPS device. + // The '$' is optional, and the '*' and CS will be added automatically. + + static void send( Stream *device, const char *msg ); + static void send_P( Stream *device, const __FlashStringHelper *msg ); + #endif //....................................................................... // Indicate that the next sentence should initialize the internal data. @@ -338,17 +347,22 @@ class NMEAGPS // Control access to this object. This preserves atomicity when // the processing style is interrupt-driven. - void lock() const - { - if (processing_style == PS_INTERRUPT) - noInterrupts(); - } - - void unlock() const - { - if (processing_style == PS_INTERRUPT) - interrupts(); - } + #ifdef ARDUINO + void lock() const + { + if (processing_style == PS_INTERRUPT) + noInterrupts(); + } + + void unlock() const + { + if (processing_style == PS_INTERRUPT) + interrupts(); + } + #else + void lock() const; + void unlock() const; + #endif protected: // Current fix diff --git a/src/Platform.h b/src/Platform.h deleted file mode 100644 index 47bb9d7..0000000 --- a/src/Platform.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -/** - * This file contains platform related definitions and imports. - **/ -#ifdef ARDUINO - #include - #include - - #ifdef __AVR__ - #include - #endif -#else - #include "platforms/Stream.h" - #include "platforms/Port.h" - #include "platforms/System.h" - - #include - #define PROGMEM - - #define pgm_read_byte(x) (*(x)) - #define __FlashStringHelper char - #define F(x) (x) - - #include - constexpr double pi() { return std::atan(1)*4; } - - #define PI pi() - #define TWO_PI pi() * 2.0 - -#endif diff --git a/src/platforms/Port.h b/src/platforms/Port.h deleted file mode 100644 index 97663d0..0000000 --- a/src/platforms/Port.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include -class Port { -public: -}; diff --git a/src/platforms/Stream.h b/src/platforms/Stream.h deleted file mode 100644 index c5d4231..0000000 --- a/src/platforms/Stream.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include -// If there is not already an implementation for your platform, -// implement these functions. -class Stream { -public: - bool available(); - uint8_t read(); - void print(uint8_t); -}; diff --git a/src/platforms/System.h b/src/platforms/System.h deleted file mode 100644 index e161f77..0000000 --- a/src/platforms/System.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -void interrupts(); -void noInterrupts(); From 7e6a90f3be7ad229ab2703c13ab6e91c101c4d03 Mon Sep 17 00:00:00 2001 From: Christian Loitsch Date: Wed, 20 Sep 2017 20:14:29 +0200 Subject: [PATCH 38/38] Revert "feat: allow compilation without ARDUINO" This reverts commit 39f391181d137b2bf3152fd6036300b5c1809651. --- src/CosaCompat.h | 18 +-- src/DMS.cpp | 8 +- src/DMS.h | 10 +- src/Location.cpp | 2 +- src/Location.h | 8 +- src/NMEAGPS.cpp | 288 +++++++++++++++++++++++------------------------ src/NMEAGPS.h | 101 ++++++++--------- src/NeoGPS_cfg.h | 5 +- src/NeoTime.cpp | 50 ++++---- src/NeoTime.h | 24 ++-- 10 files changed, 230 insertions(+), 284 deletions(-) diff --git a/src/CosaCompat.h b/src/CosaCompat.h index a2912f3..98143df 100644 --- a/src/CosaCompat.h +++ b/src/CosaCompat.h @@ -12,22 +12,6 @@ #endif typedef PGM_P str_P; - #define __PROGMEM PROGMEM -#ifndef ARDUINO - #include - #define PROGMEM - - #define pgm_read_byte(x) (*(x)) - #define __FlashStringHelper char - #define F(x) (x) - - #include - constexpr double pi() { return std::atan(1)*4; } - - #define PI pi() - #define TWO_PI pi() * 2 -#endif - -#endif +#endif \ No newline at end of file diff --git a/src/DMS.cpp b/src/DMS.cpp index 1a6b2a0..bab8621 100644 --- a/src/DMS.cpp +++ b/src/DMS.cpp @@ -18,9 +18,7 @@ #include "DMS.h" -#ifdef ARDUINO - #include -#endif +#include //---------------------------------------------------------------- // Note that no division is used, and shifts are on byte boundaries. Fast! @@ -68,7 +66,6 @@ void DMS_t::From( int32_t deg_1E7 ) } // From //---------------------------------------------------------------- -#ifdef ARDUINO Print & operator << ( Print & outs, const DMS_t & dms ) { @@ -122,5 +119,4 @@ void DMS_t::printDDDMMmmmm( Print & outs ) const if (mmmm < 10) outs.print( '0' ); outs.print( mmmm ); -} -#endif +} \ No newline at end of file diff --git a/src/DMS.h b/src/DMS.h index 0a23a13..3b26efc 100644 --- a/src/DMS.h +++ b/src/DMS.h @@ -21,9 +21,7 @@ #include "NeoGPS_cfg.h" #include -#ifdef ARDUINO - class Print; -#endif +class Print; enum Hemisphere_t { NORTH_H = 0, SOUTH_H = 1, EAST_H = 0, WEST_H = 1 }; @@ -53,8 +51,6 @@ class DMS_t } NEOGPS_PACKED; -#ifdef ARDUINO - extern Print & operator << ( Print & outs, const DMS_t & ); -#endif +extern Print & operator << ( Print & outs, const DMS_t & ); -#endif +#endif \ No newline at end of file diff --git a/src/Location.cpp b/src/Location.cpp index 7b3750a..fed8604 100644 --- a/src/Location.cpp +++ b/src/Location.cpp @@ -117,4 +117,4 @@ void Location_t::OffsetBy( float distR, float bearingR ) _lat = (newLat / (RAD_PER_DEG * LOC_SCALE)); _lon += (dLon / (RAD_PER_DEG * LOC_SCALE)); -} // OffsetBy +} // OffsetBy \ No newline at end of file diff --git a/src/Location.h b/src/Location.h index 747b5fa..65bfc6b 100644 --- a/src/Location.h +++ b/src/Location.h @@ -1,11 +1,7 @@ #ifndef NEOGPS_LOCATION_H #define NEOGPS_LOCATION_H -#ifdef ARDUINO - #include -#else - #include "CosaCompat.h" -#endif +#include #include "NeoGPS_cfg.h" @@ -130,4 +126,4 @@ class Location_t } // NeoGPS -#endif +#endif \ No newline at end of file diff --git a/src/NMEAGPS.cpp b/src/NMEAGPS.cpp index aae0c67..2792c3a 100644 --- a/src/NMEAGPS.cpp +++ b/src/NMEAGPS.cpp @@ -18,9 +18,7 @@ #include "NMEAGPS.h" -#ifdef ARDUINO - #include -#endif +#include // Check configurations @@ -447,7 +445,7 @@ static const char * const std_nmea[] __PROGMEM = const NMEAGPS::msg_table_t NMEAGPS::nmea_msg_table __PROGMEM = { NMEAGPS::NMEA_FIRST_MSG, - (const msg_table_t *) 0x00, + (const msg_table_t *) NULL, sizeof(std_nmea)/sizeof(std_nmea[0]), std_nmea }; @@ -662,7 +660,7 @@ const __FlashStringHelper *NMEAGPS::string_for( nmea_msg_t msg ) const continue; #endif - return (const __FlashStringHelper *) 0x00; + return (const __FlashStringHelper *) NULL; } } // string_for @@ -1591,147 +1589,145 @@ const gps_fix NMEAGPS::read() //---------------------------------------------------------------- -#ifdef ARDUINO - void NMEAGPS::poll( Stream *device, nmea_msg_t msg ) - { - // Only the ublox documentation references talker ID "EI". - // Other manufacturer's devices use "II" and "GP" talker IDs for the GPQ sentence. - // However, "GP" is reserved for the GPS device, so it seems inconsistent - // to use that talker ID when requesting something from the GPS device. - - #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gga[] __PROGMEM = "EIGPQ,GGA"; - #endif - #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gll[] __PROGMEM = "EIGPQ,GLL"; - #endif - #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gsa[] __PROGMEM = "EIGPQ,GSA"; - #endif - #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gst[] __PROGMEM = "EIGPQ,GST"; - #endif - #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char gsv[] __PROGMEM = "EIGPQ,GSV"; - #endif - #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char rmc[] __PROGMEM = "EIGPQ,RMC"; - #endif - #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char vtg[] __PROGMEM = "EIGPQ,VTG"; - #endif - #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) - static const char zda[] __PROGMEM = "EIGPQ,ZDA"; - #endif - - static const char * const poll_msgs[] __PROGMEM = - { - #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) - gga, - #endif - #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) - gll, - #endif - #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) - gsa, - #endif - #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) - gst, - #endif - #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) - gsv, - #endif - #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) - rmc, - #endif - #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) - vtg, - #endif - #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) - zda - #endif - }; - - if ((NMEA_FIRST_MSG <= msg) && (msg <= NMEA_LAST_MSG)) { - #ifdef __AVR__ - const __FlashStringHelper * pollCmd = - (const __FlashStringHelper *) pgm_read_word(&poll_msgs[msg-NMEA_FIRST_MSG]); - #else - const __FlashStringHelper * pollCmd = - (const __FlashStringHelper *) poll_msgs[msg-NMEA_FIRST_MSG]; +void NMEAGPS::poll( Stream *device, nmea_msg_t msg ) +{ + // Only the ublox documentation references talker ID "EI". + // Other manufacturer's devices use "II" and "GP" talker IDs for the GPQ sentence. + // However, "GP" is reserved for the GPS device, so it seems inconsistent + // to use that talker ID when requesting something from the GPS device. + + #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gga[] __PROGMEM = "EIGPQ,GGA"; + #endif + #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gll[] __PROGMEM = "EIGPQ,GLL"; + #endif + #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gsa[] __PROGMEM = "EIGPQ,GSA"; + #endif + #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gst[] __PROGMEM = "EIGPQ,GST"; + #endif + #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char gsv[] __PROGMEM = "EIGPQ,GSV"; + #endif + #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char rmc[] __PROGMEM = "EIGPQ,RMC"; + #endif + #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char vtg[] __PROGMEM = "EIGPQ,VTG"; + #endif + #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) + static const char zda[] __PROGMEM = "EIGPQ,ZDA"; + #endif + + static const char * const poll_msgs[] __PROGMEM = + { + #if defined(NMEAGPS_PARSE_GGA) | defined(NMEAGPS_RECOGNIZE_ALL) + gga, #endif - send_P( device, pollCmd ); - } - - } // poll - - //---------------------------------------------------------------- - - static void send_trailer( Stream *device, uint8_t crc ) - { - device->print('*'); - - char hexDigit = formatHex( crc>>4 ); - device->print( hexDigit ); - - hexDigit = formatHex( crc ); - device->print( hexDigit ); - - device->print( CR ); - device->print( LF ); - - } // send_trailer - - //---------------------------------------------------------------- - - void NMEAGPS::send( Stream *device, const char *msg ) - { - if (msg && *msg) { - if (*msg == '$') - msg++; - device->print('$'); - uint8_t sent_trailer = 0; - uint8_t crc = 0; - while (*msg) { - if ((*msg == '*') || (sent_trailer > 0)) - sent_trailer++; - else - crc ^= *msg; - device->print( *msg++ ); - } - - if (!sent_trailer) - send_trailer( device, crc ); + #if defined(NMEAGPS_PARSE_GLL) | defined(NMEAGPS_RECOGNIZE_ALL) + gll, + #endif + #if defined(NMEAGPS_PARSE_GSA) | defined(NMEAGPS_RECOGNIZE_ALL) + gsa, + #endif + #if defined(NMEAGPS_PARSE_GST) | defined(NMEAGPS_RECOGNIZE_ALL) + gst, + #endif + #if defined(NMEAGPS_PARSE_GSV) | defined(NMEAGPS_RECOGNIZE_ALL) + gsv, + #endif + #if defined(NMEAGPS_PARSE_RMC) | defined(NMEAGPS_RECOGNIZE_ALL) + rmc, + #endif + #if defined(NMEAGPS_PARSE_VTG) | defined(NMEAGPS_RECOGNIZE_ALL) + vtg, + #endif + #if defined(NMEAGPS_PARSE_ZDA) | defined(NMEAGPS_RECOGNIZE_ALL) + zda + #endif + }; + + if ((NMEA_FIRST_MSG <= msg) && (msg <= NMEA_LAST_MSG)) { + #ifdef __AVR__ + const __FlashStringHelper * pollCmd = + (const __FlashStringHelper *) pgm_read_word(&poll_msgs[msg-NMEA_FIRST_MSG]); + #else + const __FlashStringHelper * pollCmd = + (const __FlashStringHelper *) poll_msgs[msg-NMEA_FIRST_MSG]; + #endif + send_P( device, pollCmd ); + } + +} // poll + +//---------------------------------------------------------------- + +static void send_trailer( Stream *device, uint8_t crc ) +{ + device->print('*'); + + char hexDigit = formatHex( crc>>4 ); + device->print( hexDigit ); + + hexDigit = formatHex( crc ); + device->print( hexDigit ); + + device->print( CR ); + device->print( LF ); + +} // send_trailer + +//---------------------------------------------------------------- + +void NMEAGPS::send( Stream *device, const char *msg ) +{ + if (msg && *msg) { + if (*msg == '$') + msg++; + device->print('$'); + uint8_t sent_trailer = 0; + uint8_t crc = 0; + while (*msg) { + if ((*msg == '*') || (sent_trailer > 0)) + sent_trailer++; + else + crc ^= *msg; + device->print( *msg++ ); } - - } // send - - //---------------------------------------------------------------- - - void NMEAGPS::send_P( Stream *device, const __FlashStringHelper *msg ) - { - if (msg) { - const char *ptr = (const char *)msg; - char chr = pgm_read_byte(ptr++); - - device->print('$'); - if (chr == '$') - chr = pgm_read_byte(ptr++); - uint8_t sent_trailer = 0; - uint8_t crc = 0; - while (chr) { - if ((chr == '*') || (sent_trailer > 0)) - sent_trailer++; - else - crc ^= chr; - device->print( chr ); - - chr = pgm_read_byte(ptr++); - } - - if (!sent_trailer) - send_trailer( device, crc ); + + if (!sent_trailer) + send_trailer( device, crc ); + } + +} // send + +//---------------------------------------------------------------- + +void NMEAGPS::send_P( Stream *device, const __FlashStringHelper *msg ) +{ + if (msg) { + const char *ptr = (const char *)msg; + char chr = pgm_read_byte(ptr++); + + device->print('$'); + if (chr == '$') + chr = pgm_read_byte(ptr++); + uint8_t sent_trailer = 0; + uint8_t crc = 0; + while (chr) { + if ((chr == '*') || (sent_trailer > 0)) + sent_trailer++; + else + crc ^= chr; + device->print( chr ); + + chr = pgm_read_byte(ptr++); } - - } // send_P -#endif + + if (!sent_trailer) + send_trailer( device, crc ); + } + +} // send_P diff --git a/src/NMEAGPS.h b/src/NMEAGPS.h index 4ef5dd3..cb56e05 100644 --- a/src/NMEAGPS.h +++ b/src/NMEAGPS.h @@ -21,11 +21,9 @@ #include "CosaCompat.h" -#ifdef ARDUINO - #include - #ifdef __AVR__ - #include - #endif +#include +#ifdef __AVR__ + #include #endif #include "GPSfix.h" @@ -98,25 +96,22 @@ class NMEAGPS CONST_CLASS_DATA nmea_msg_t NMEA_FIRST_MSG = (nmea_msg_t) (NMEA_UNKNOWN+1); CONST_CLASS_DATA nmea_msg_t NMEA_LAST_MSG = (nmea_msg_t) (NMEAMSG_END-1); - #ifdef ARDUINO - //======================================================================= - // FIX-ORIENTED methods: available, read and handle - //======================================================================= - - //....................................................................... - // The available(...) functions return the number of *fixes* that - // are available to be "read" from the fix buffer. The GPS port - // object is passed in so a char can be read if port.available(). - - uint8_t available( Stream & port ) - { - if (processing_style == PS_POLLING) - while (port.available()) - handle( port.read() ); - return _available(); - } - #endif - + //======================================================================= + // FIX-ORIENTED methods: available, read and handle + //======================================================================= + + //....................................................................... + // The available(...) functions return the number of *fixes* that + // are available to be "read" from the fix buffer. The GPS port + // object is passed in so a char can be read if port.available(). + + uint8_t available( Stream & port ) + { + if (processing_style == PS_POLLING) + while (port.available()) + handle( port.read() ); + return _available(); + } uint8_t available() const volatile { return _available(); }; //....................................................................... @@ -171,7 +166,7 @@ class NMEAGPS // Convert a nmea_msg_t to a PROGMEM string. // Useful for printing the sentence type instead of a number. // This can return "UNK" if the message is not a valid number. - + const __FlashStringHelper *string_for( nmea_msg_t msg ) const; //....................................................................... @@ -232,19 +227,17 @@ class NMEAGPS } statistics; #endif - #ifdef ARDUINO - //....................................................................... - // Request the specified NMEA sentence. Not all devices will respond. - - static void poll( Stream *device, nmea_msg_t msg ); - - //....................................................................... - // Send a message to the GPS device. - // The '$' is optional, and the '*' and CS will be added automatically. - - static void send( Stream *device, const char *msg ); - static void send_P( Stream *device, const __FlashStringHelper *msg ); - #endif + //....................................................................... + // Request the specified NMEA sentence. Not all devices will respond. + + static void poll( Stream *device, nmea_msg_t msg ); + + //....................................................................... + // Send a message to the GPS device. + // The '$' is optional, and the '*' and CS will be added automatically. + + static void send( Stream *device, const char *msg ); + static void send_P( Stream *device, const __FlashStringHelper *msg ); //....................................................................... // Indicate that the next sentence should initialize the internal data. @@ -256,9 +249,8 @@ class NMEAGPS //....................................................................... // Correlate the Arduino micros() clock with UTC. - #if defined ARDUINO && \ - (defined(NMEAGPS_TIMESTAMP_FROM_PPS) | \ - defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL)) + #if defined(NMEAGPS_TIMESTAMP_FROM_PPS) | \ + defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL) private: uint32_t _UTCsecondStart; #if defined(NMEAGPS_TIMESTAMP_FROM_INTERVAL) & \ @@ -347,22 +339,17 @@ class NMEAGPS // Control access to this object. This preserves atomicity when // the processing style is interrupt-driven. - #ifdef ARDUINO - void lock() const - { - if (processing_style == PS_INTERRUPT) - noInterrupts(); - } - - void unlock() const - { - if (processing_style == PS_INTERRUPT) - interrupts(); - } - #else - void lock() const; - void unlock() const; - #endif + void lock() const + { + if (processing_style == PS_INTERRUPT) + noInterrupts(); + } + + void unlock() const + { + if (processing_style == PS_INTERRUPT) + interrupts(); + } protected: // Current fix diff --git a/src/NeoGPS_cfg.h b/src/NeoGPS_cfg.h index d17cbce..b325f06 100644 --- a/src/NeoGPS_cfg.h +++ b/src/NeoGPS_cfg.h @@ -72,10 +72,7 @@ * */ -#if defined ARDUINO && \ - ((ARDUINO < 10606) | \ - ((10700 <= ARDUINO) & (ARDUINO <= 10799)) | \ - ((107000 <= ARDUINO) & (ARDUINO <= 107999))) +#if (ARDUINO < 10606) | ((10700 <= ARDUINO) & (ARDUINO <= 10799)) | ((107000 <= ARDUINO) & (ARDUINO <= 107999)) #define CONST_CLASS_DATA static const diff --git a/src/NeoTime.cpp b/src/NeoTime.cpp index 77dd584..d2d336b 100644 --- a/src/NeoTime.cpp +++ b/src/NeoTime.cpp @@ -24,31 +24,29 @@ // For strtoul declaration #include -#ifdef ARDUINO - #include - - Print & operator<<( Print& outs, const NeoGPS::time_t& t ) - { - outs.print( t.full_year( t.year ) ); - outs.write( '-' ); - if (t.month < 10) outs.write( '0' ); - outs.print( t.month ); - outs.write( '-' ); - if (t.date < 10) outs.write( '0' ); - outs.print( t.date ); - outs.write( ' ' ); - if (t.hours < 10) outs.write( '0' ); - outs.print( t.hours ); - outs.write( ':' ); - if (t.minutes < 10) outs.write( '0' ); - outs.print( t.minutes ); - outs.write( ':' ); - if (t.seconds < 10) outs.write( '0' ); - outs.print( t.seconds ); - - return outs; - } -#endif +#include + +Print & operator<<( Print& outs, const NeoGPS::time_t& t ) +{ + outs.print( t.full_year( t.year ) ); + outs.write( '-' ); + if (t.month < 10) outs.write( '0' ); + outs.print( t.month ); + outs.write( '-' ); + if (t.date < 10) outs.write( '0' ); + outs.print( t.date ); + outs.write( ' ' ); + if (t.hours < 10) outs.write( '0' ); + outs.print( t.hours ); + outs.write( ':' ); + if (t.minutes < 10) outs.write( '0' ); + outs.print( t.minutes ); + outs.write( ':' ); + if (t.seconds < 10) outs.write( '0' ); + outs.print( t.seconds ); + + return outs; +} using NeoGPS::time_t; @@ -211,4 +209,4 @@ uint16_t time_t::day_of_year() const epoch_weekday( compile_weekday ); pivot_year ( this_year.year ); } -#endif +#endif \ No newline at end of file diff --git a/src/NeoTime.h b/src/NeoTime.h index d92422b..67f792f 100644 --- a/src/NeoTime.h +++ b/src/NeoTime.h @@ -22,9 +22,7 @@ #ifndef TIME_H #define TIME_H -#ifdef ARDUINO - #include -#endif +#include #include "NeoGPS_cfg.h" #include "CosaCompat.h" @@ -300,16 +298,14 @@ struct time_t { }; // namespace NeoGPS -#ifdef ARDUINO - class Print; - - /** - * Print the date/time to the given stream with the format "YYYY-MM-DD HH:MM:SS". - * @param[in] outs output stream. - * @param[in] t time structure. - * @return iostream. - */ - Print & operator <<( Print & outs, const NeoGPS::time_t &t ); -#endif +class Print; + +/** + * Print the date/time to the given stream with the format "YYYY-MM-DD HH:MM:SS". + * @param[in] outs output stream. + * @param[in] t time structure. + * @return iostream. + */ +Print & operator <<( Print & outs, const NeoGPS::time_t &t ); #endif