From b721a33d7b14c9f994eaa1932a71d578dc1d8147 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 24 Nov 2020 06:44:58 +0100 Subject: [PATCH 1/5] Split message string once more to allow parsing of magnetic variation east/west indicator as a token --- src/nmea/GxRMC.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/nmea/GxRMC.cpp b/src/nmea/GxRMC.cpp index ab4fc8d..57e710d 100644 --- a/src/nmea/GxRMC.cpp +++ b/src/nmea/GxRMC.cpp @@ -39,6 +39,12 @@ void GxRMC::parse(char const * gprmc, RmcData & data) { ParserState state = ParserState::MessadeId; + /* Replace the '*' sign denoting the start of the checksum + * with a ',' in order to be able to tokenize all elements + * including the one before the checksum. + */ + *strchr((char *)gprmc, '*') = ','; + for (char * token = strsep((char **)&gprmc, ","); token != nullptr; token = strsep((char **)&gprmc, ",")) From 93f385e5e9eb04ef6760e0299f1004b784f59796 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 24 Nov 2020 06:46:02 +0100 Subject: [PATCH 2/5] Eliminating jump to checksum as all RMC outputs are containing empty fields, even if they don't contain the data --- src/nmea/GxRMC.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/nmea/GxRMC.cpp b/src/nmea/GxRMC.cpp index 57e710d..c6b1bd5 100644 --- a/src/nmea/GxRMC.cpp +++ b/src/nmea/GxRMC.cpp @@ -49,15 +49,6 @@ void GxRMC::parse(char const * gprmc, RmcData & data) token != nullptr; token = strsep((char **)&gprmc, ",")) { - /* All GPS receivers should at least implement the the fields: UTC Position Fix, - * Status, Latitude, Longitude, Speed over ground, Track Angle. All other fields - * are optional. Therefore we are checking in the following if statement if the - * current token is a checksum token. If that's the case we are directly jumping - * to ParserState::Checksum. - */ - if (util::isChecksumToken(token)) - state = ParserState::Checksum; - ParserState next_state = state; switch(state) From e7d9bdabb9d5a6957a3e971380abb4be1c70de38 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 24 Nov 2020 06:46:56 +0100 Subject: [PATCH 3/5] Renaming parameter gprmc to gxrmc to reflect that next to GPS also Galileo, GLONASS and GNSS messages are supported --- src/nmea/GxRMC.cpp | 8 ++++---- src/nmea/GxRMC.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/nmea/GxRMC.cpp b/src/nmea/GxRMC.cpp index c6b1bd5..53a6441 100644 --- a/src/nmea/GxRMC.cpp +++ b/src/nmea/GxRMC.cpp @@ -35,7 +35,7 @@ constexpr float kts_to_m_per_s(float const v) { return (v / 1.9438444924574f); } * PUBLIC MEMBER FUNCTIONS **************************************************************************************/ -void GxRMC::parse(char const * gprmc, RmcData & data) +void GxRMC::parse(char const * gxrmc, RmcData & data) { ParserState state = ParserState::MessadeId; @@ -43,11 +43,11 @@ void GxRMC::parse(char const * gprmc, RmcData & data) * with a ',' in order to be able to tokenize all elements * including the one before the checksum. */ - *strchr((char *)gprmc, '*') = ','; + *strchr((char *)gxrmc, '*') = ','; - for (char * token = strsep((char **)&gprmc, ","); + for (char * token = strsep((char **)&gxrmc, ","); token != nullptr; - token = strsep((char **)&gprmc, ",")) + token = strsep((char **)&gxrmc, ",")) { ParserState next_state = state; diff --git a/src/nmea/GxRMC.h b/src/nmea/GxRMC.h index 9363e72..5024168 100644 --- a/src/nmea/GxRMC.h +++ b/src/nmea/GxRMC.h @@ -32,7 +32,7 @@ class GxRMC public: - static void parse(char const * gprmc, RmcData & data); + static void parse(char const * gxrmc, RmcData & data); private: From f9f3adad47777d2384ce2aeee76357884628967c Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 24 Nov 2020 06:49:44 +0100 Subject: [PATCH 4/5] Changing parameter signature from 'const char *' tp 'char *' as the buffer is in fact modified within the call. This also does away with tedious casting --- extras/test/src/test_GxGGA.cpp | 20 ++++++++++---------- src/nmea/GxGGA.cpp | 8 ++++---- src/nmea/GxGGA.h | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/extras/test/src/test_GxGGA.cpp b/extras/test/src/test_GxGGA.cpp index b29517e..1fea5f1 100644 --- a/extras/test/src/test_GxGGA.cpp +++ b/extras/test/src/test_GxGGA.cpp @@ -32,7 +32,7 @@ SCENARIO("Extracting satellite system from valid GxGGA message", "[GxGGA-01]") WHEN("GPS") { std::string const GPGGA = "$GPGGA,111908.952,4838.0060,N,01301.5895,E,1,05,2.4,454.7,M,46.6,M,0.0,0000*7A\r\n"; - nmea::GxGGA::parse(GPGGA.c_str(), data); + nmea::GxGGA::parse(const_cast(GPGGA.c_str()), data); REQUIRE(data.source == nmea::GgaSource::GPS); } } @@ -40,7 +40,7 @@ SCENARIO("Extracting satellite system from valid GxGGA message", "[GxGGA-01]") TEST_CASE("Extracting position time from valid GxGGA message", "[GxGGA-02]") { std::string const GPGGA = "$GPGGA,111908.952,4838.0060,N,01301.5895,E,1,05,2.4,454.7,M,46.6,M,0.0,0000*7A\r\n"; - nmea::GxGGA::parse(GPGGA.c_str(), data); + nmea::GxGGA::parse(const_cast(GPGGA.c_str()), data); REQUIRE(data.time_utc.hour == 11); REQUIRE(data.time_utc.minute == 19); REQUIRE(data.time_utc.second == 8); @@ -50,7 +50,7 @@ TEST_CASE("Extracting position time from valid GxGGA message", "[GxGGA-02]") SCENARIO("Extracting latitude/longiture from valid GPGGA message", "[GxGGA-03]") { std::string const GPGGA = "$GPGGA,111908.952,4838.0060,N,01301.5895,E,1,05,2.4,454.7,M,46.6,M,0.0,0000*7A\r\n"; - nmea::GxGGA::parse(GPGGA.c_str(), data); + nmea::GxGGA::parse(const_cast(GPGGA.c_str()), data); REQUIRE(data.latitude == Approx(48.633433)); REQUIRE(data.longitude == Approx(13.026492)); } @@ -60,7 +60,7 @@ TEST_CASE("Extracting fix quality angle from valid GxGGA message", "[GxGGA-04]") WHEN("GPS Fix") { std::string const GPGGA = "$GPGGA,111908.952,4838.0060,N,01301.5895,E,1,05,2.4,454.7,M,46.6,M,0.0,0000*7A\r\n"; - nmea::GxGGA::parse(GPGGA.c_str(), data); + nmea::GxGGA::parse(const_cast(GPGGA.c_str()), data); REQUIRE(data.fix_quality == nmea::FixQuality::GPS_Fix); } } @@ -68,41 +68,41 @@ TEST_CASE("Extracting fix quality angle from valid GxGGA message", "[GxGGA-04]") SCENARIO("Extracting number of satellites from valid GPGGA message", "[GxGGA-05]") { std::string const GPGGA = "$GPGGA,111908.952,4838.0060,N,01301.5895,E,1,05,2.4,454.7,M,46.6,M,0.0,0000*7A\r\n"; - nmea::GxGGA::parse(GPGGA.c_str(), data); + nmea::GxGGA::parse(const_cast(GPGGA.c_str()), data); REQUIRE(data.num_satellites == 5); } SCENARIO("Extracting horizontal dilution of precision from valid GPGGA message", "[GxGGA-06]") { std::string const GPGGA = "$GPGGA,111908.952,4838.0060,N,01301.5895,E,1,05,2.4,454.7,M,46.6,M,0.0,0000*7A\r\n"; - nmea::GxGGA::parse(GPGGA.c_str(), data); + nmea::GxGGA::parse(const_cast(GPGGA.c_str()), data); REQUIRE(data.hdop == Approx(2.4)); } SCENARIO("Extracting altitude from valid GPGGA message", "[GxGGA-07]") { std::string const GPGGA = "$GPGGA,111908.952,4838.0060,N,01301.5895,E,1,05,2.4,454.7,M,46.6,M,0.0,0000*7A\r\n"; - nmea::GxGGA::parse(GPGGA.c_str(), data); + nmea::GxGGA::parse(const_cast(GPGGA.c_str()), data); REQUIRE(data.altitude == Approx(454.7)); } SCENARIO("Extracting geoidal separation from valid GPGGA message", "[GxGGA-08]") { std::string const GPGGA = "$GPGGA,111908.952,4838.0060,N,01301.5895,E,1,05,2.4,454.7,M,46.6,M,0.0,0000*7A\r\n"; - nmea::GxGGA::parse(GPGGA.c_str(), data); + nmea::GxGGA::parse(const_cast(GPGGA.c_str()), data); REQUIRE(data.geoidal_separation == Approx(46.6)); } SCENARIO("Extracting time since last DGPS update from valid GPGGA message", "[GxGGA-09]") { std::string const GPGGA = "$GPGGA,111908.952,4838.0060,N,01301.5895,E,1,05,2.4,454.7,M,46.6,M,0.0,0000*7A\r\n"; - nmea::GxGGA::parse(GPGGA.c_str(), data); + nmea::GxGGA::parse(const_cast(GPGGA.c_str()), data); REQUIRE(data.dgps_age == Approx(0.0)); } SCENARIO("Extracting DGPS station id from valid GPGGA message", "[GxGGA-10]") { std::string const GPGGA = "$GPGGA,111908.952,4838.0060,N,01301.5895,E,1,05,2.4,454.7,M,46.6,M,0.0,0000*7A\r\n"; - nmea::GxGGA::parse(GPGGA.c_str(), data); + nmea::GxGGA::parse(const_cast(GPGGA.c_str()), data); REQUIRE(strncmp(data.dgps_id, "0000", 4) == 0); } diff --git a/src/nmea/GxGGA.cpp b/src/nmea/GxGGA.cpp index 1bd2491..0f2eed3 100644 --- a/src/nmea/GxGGA.cpp +++ b/src/nmea/GxGGA.cpp @@ -28,7 +28,7 @@ namespace nmea * PUBLIC MEMBER FUNCTIONS **************************************************************************************/ -void GxGGA::parse(char const * gxgga, GgaData & data) +void GxGGA::parse(char * gxgga, GgaData & data) { ParserState state = ParserState::MessadeId; @@ -36,11 +36,11 @@ void GxGGA::parse(char const * gxgga, GgaData & data) * with a ',' in order to be able to tokenize all elements * including the one before the checksum. */ - *strchr((char *)gxgga, '*') = ','; + *strchr(gxgga, '*') = ','; - for (char * token = strsep((char **)&gxgga, ","); + for (char * token = strsep(&gxgga, ","); token != nullptr; - token = strsep((char **)&gxgga, ",")) + token = strsep(&gxgga, ",")) { ParserState next_state = state; diff --git a/src/nmea/GxGGA.h b/src/nmea/GxGGA.h index 98d4e08..f68110b 100644 --- a/src/nmea/GxGGA.h +++ b/src/nmea/GxGGA.h @@ -32,7 +32,7 @@ class GxGGA public: - static void parse(char const * gxgga, GgaData & data); + static void parse(char * gxgga, GgaData & data); private: From fae211953faaa0166d36ece35bfac48ee1b2ceb8 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Tue, 24 Nov 2020 06:51:02 +0100 Subject: [PATCH 5/5] Changing parameter signature from 'const char *' tp 'char *' as the buffer is in fact modified within the call. This also does away with tedious casting --- extras/test/src/test_GxRMC.cpp | 26 +++++++++++++------------- src/nmea/GxRMC.cpp | 8 ++++---- src/nmea/GxRMC.h | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/extras/test/src/test_GxRMC.cpp b/extras/test/src/test_GxRMC.cpp index aa8608a..46cecd3 100644 --- a/extras/test/src/test_GxRMC.cpp +++ b/extras/test/src/test_GxRMC.cpp @@ -33,7 +33,7 @@ SCENARIO("Extracting latitude/longiture from valid GPRMC message", "[GxRMC-01]") { std::string const GPRMC = "$GPRMC,062101.714,A,5001.869,N,01912.114,E,955535.7,116.2,290520,000.0,W*45\r\n"; - nmea::GxRMC::parse(GPRMC.c_str(), data); + nmea::GxRMC::parse(const_cast(GPRMC.c_str()), data); REQUIRE(data.latitude == Approx(50.03114442)); REQUIRE(data.longitude == Approx(19.20189679)); @@ -43,7 +43,7 @@ SCENARIO("Extracting latitude/longiture from valid GPRMC message", "[GxRMC-01]") { std::string const GPRMC = "$GPRMC,122311.239,A,4056.748,N,11212.614,W,,,290620,000.0,W*63\r\n"; - nmea::GxRMC::parse(GPRMC.c_str(), data); + nmea::GxRMC::parse(const_cast(GPRMC.c_str()), data); REQUIRE(data.latitude == Approx(40.9458060446613)); REQUIRE(data.longitude == Approx(-112.210235595703)); @@ -53,7 +53,7 @@ SCENARIO("Extracting latitude/longiture from valid GPRMC message", "[GxRMC-01]") { std::string const GPRMC = "$GPRMC,122311.239,A,2727.069,S,05859.190,W,,,290620,000.0,W*76\r\n"; - nmea::GxRMC::parse(GPRMC.c_str(), data); + nmea::GxRMC::parse(const_cast(GPRMC.c_str()), data); REQUIRE(data.latitude == Approx(-27.4511422937699)); REQUIRE(data.longitude == Approx(-58.986502289772)); @@ -63,7 +63,7 @@ SCENARIO("Extracting latitude/longiture from valid GPRMC message", "[GxRMC-01]") { std::string const GPRMC = "$GPRMC,122311.239,A,0610.522,S,10649.632,E,,,290620,000.0,W*6D\r\n"; - nmea::GxRMC::parse(GPRMC.c_str(), data); + nmea::GxRMC::parse(const_cast(GPRMC.c_str()), data); REQUIRE(data.latitude == Approx(-6.17536097471491)); REQUIRE(data.longitude == Approx(106.827192306519)); @@ -75,13 +75,13 @@ SCENARIO("Extracting satellite system from valid GxRMC message", "[GxRMC-02]") WHEN("GPS") { std::string const GPRMC = "$GPRMC,122311.239,A,0610.522,S,10649.632,E,,,290620,000.0,W*6D\r\n"; - nmea::GxRMC::parse(GPRMC.c_str(), data); + nmea::GxRMC::parse(const_cast(GPRMC.c_str()), data); REQUIRE(data.source == nmea::RmcSource::GPS); } WHEN("GNSS") { std::string const GNSS = "$GNRMC,090348.80,A,4838.00682,N,01301.61381,E,1.533,,301020,,,A*61\r\n"; - nmea::GxRMC::parse(GNSS.c_str(), data); + nmea::GxRMC::parse(const_cast(GNSS.c_str()), data); REQUIRE(data.source == nmea::RmcSource::GNSS); } } @@ -90,7 +90,7 @@ TEST_CASE("Extracting speed over ground from valid GPRMC message", "[GxRMC-03]") { std::string const GPRMC = ("$GPRMC,052856.105,A,5230.874,N,01321.056,E,085.7,206.4,080720,000.0,W*78\r\n"); - nmea::GxRMC::parse(GPRMC.c_str(), data); + nmea::GxRMC::parse(const_cast(GPRMC.c_str()), data); /* 85.7 kts ~= 44.088 m/s */ REQUIRE(data.speed == Approx(44.088f)); @@ -100,7 +100,7 @@ TEST_CASE("Extracting track angle from valid GPRMC message", "[GxRMC-04]") { std::string const GPRMC = ("$GPRMC,052856.105,A,5230.874,N,01321.056,E,085.7,206.4,080720,000.0,W*78\r\n"); - nmea::GxRMC::parse(GPRMC.c_str(), data); + nmea::GxRMC::parse(const_cast(GPRMC.c_str()), data); REQUIRE(data.course == Approx(206.4f)); } @@ -109,7 +109,7 @@ TEST_CASE("Extracting position time from valid GPRMC message", "[GxRMC-05]") { std::string const GPRMC = ("$GPRMC,052856.105,A,5230.874,N,01321.056,E,085.7,206.4,080720,000.0,W*78\r\n"); - nmea::GxRMC::parse(GPRMC.c_str(), data); + nmea::GxRMC::parse(const_cast(GPRMC.c_str()), data); /* 052856.105 -> 05:28:56.105 -> */ REQUIRE(data.time_utc.hour == 5); @@ -122,7 +122,7 @@ TEST_CASE("Extracting date from valid GPRMC message", "[GxRMC-06]") { std::string const GPRMC = ("$GPRMC,052856.105,A,5230.874,N,01321.056,E,085.7,206.4,080720,000.0,W*78\r\n"); - nmea::GxRMC::parse(GPRMC.c_str(), data); + nmea::GxRMC::parse(const_cast(GPRMC.c_str()), data); REQUIRE(data.date.day == 8); REQUIRE(data.date.month == 7); @@ -133,7 +133,7 @@ TEST_CASE("Extracting magnetic variation from valid GPRMC message", "[GxRMC-07]" { std::string const GPRMC = ("$GPRMC,052856.105,A,5230.874,N,01321.056,E,085.7,206.4,080720,000.0,W*78\r\n"); - nmea::GxRMC::parse(GPRMC.c_str(), data); + nmea::GxRMC::parse(const_cast(GPRMC.c_str()), data); REQUIRE(data.magnetic_variation == Approx(0.0)); } @@ -142,7 +142,7 @@ TEST_CASE("Extracted status indicates void ('V') position data", "[GxRMC-08]") { std::string const GPRMC = ("$GPRMC,052856.105,V,5230.874,N,01321.056,E,085.7,206.4,080720,000.0,W*78\r\n"); - nmea::GxRMC::parse(GPRMC.c_str(), data); + nmea::GxRMC::parse(const_cast(GPRMC.c_str()), data); REQUIRE(data.is_valid == false); } @@ -151,7 +151,7 @@ TEST_CASE("GxRMC message contains only date and time, but no location fix yet ", { std::string const GPRMC = ("$GPRMC,144602.00,V,,,,,,,011120,,,N*7B\r\n"); - nmea::GxRMC::parse(GPRMC.c_str(), data); + nmea::GxRMC::parse(const_cast(GPRMC.c_str()), data); /* RMC TIME = '144602.00' */ REQUIRE(data.time_utc.hour == 14); diff --git a/src/nmea/GxRMC.cpp b/src/nmea/GxRMC.cpp index 53a6441..4be11bf 100644 --- a/src/nmea/GxRMC.cpp +++ b/src/nmea/GxRMC.cpp @@ -35,7 +35,7 @@ constexpr float kts_to_m_per_s(float const v) { return (v / 1.9438444924574f); } * PUBLIC MEMBER FUNCTIONS **************************************************************************************/ -void GxRMC::parse(char const * gxrmc, RmcData & data) +void GxRMC::parse(char * gxrmc, RmcData & data) { ParserState state = ParserState::MessadeId; @@ -43,11 +43,11 @@ void GxRMC::parse(char const * gxrmc, RmcData & data) * with a ',' in order to be able to tokenize all elements * including the one before the checksum. */ - *strchr((char *)gxrmc, '*') = ','; + *strchr(gxrmc, '*') = ','; - for (char * token = strsep((char **)&gxrmc, ","); + for (char * token = strsep(&gxrmc, ","); token != nullptr; - token = strsep((char **)&gxrmc, ",")) + token = strsep(&gxrmc, ",")) { ParserState next_state = state; diff --git a/src/nmea/GxRMC.h b/src/nmea/GxRMC.h index 5024168..9d7f47a 100644 --- a/src/nmea/GxRMC.h +++ b/src/nmea/GxRMC.h @@ -32,7 +32,7 @@ class GxRMC public: - static void parse(char const * gxrmc, RmcData & data); + static void parse(char * gxrmc, RmcData & data); private: