From d13a482112103e354c529432834cb76541976dd9 Mon Sep 17 00:00:00 2001 From: Mario Konrad Date: Wed, 14 Oct 2020 20:30:47 +0200 Subject: [PATCH] NMEA: GSV satellite info field SNR is optional Thanks to https://github.com/norton-dev for reporting the issue about SNR being optional. --- examples/qtnmeadiag/MainWindow.cpp | 4 +-- include/marnav/nmea/gsv.hpp | 19 +++++----- src/marnav/nmea/gsv.cpp | 10 +++--- src/nmeadump.cpp | 12 +++++-- test/nmea/Test_nmea_gsv.cpp | 73 +++++++++++++++++++++++++++++++------- 5 files changed, 89 insertions(+), 29 deletions(-) diff --git a/examples/qtnmeadiag/MainWindow.cpp b/examples/qtnmeadiag/MainWindow.cpp index efac77fa..8f94aa93 100644 --- a/examples/qtnmeadiag/MainWindow.cpp +++ b/examples/qtnmeadiag/MainWindow.cpp @@ -260,8 +260,8 @@ static QString details_gsv(const marnav::nmea::sentence * s) for (int i = 0; i < 4; ++i) { const auto sat = t->get_sat(i); if (sat) { - result += QString{"\nSat: ID:%1 ELEV:%2 AZIMUTH:%3 SNR:%4"} - .arg(render(sat->id), 2) + result += QString{"\nSat: PRN:%1 ELEV:%2 AZIMUTH:%3 SNR:%4"} + .arg(render(sat->prn), 2) .arg(render(sat->elevation), 2) .arg(render(sat->azimuth), 3) .arg(render(sat->snr), 2); diff --git a/include/marnav/nmea/gsv.hpp b/include/marnav/nmea/gsv.hpp index b535428b..4c58803f 100644 --- a/include/marnav/nmea/gsv.hpp +++ b/include/marnav/nmea/gsv.hpp @@ -21,15 +21,18 @@ namespace nmea /// @endcode /// /// Field Number: -/// 1. total number of GSV messages to be transmitted in this group +/// 1. Total number of GSV messages to be transmitted in this group /// 2. 1-origin number of this GSV message within current group -/// 3. total number of satellites in view (leading zeros sent) -/// 4. satellite PRN number (leading zeros sent) -/// 5. elevation in degrees (00-90) (leading zeros sent) -/// 6. azimuth in degrees to true north (000-359) (leading zeros sent) -/// 7. SNR in dB (00-99) (leading zeros sent) more satellite info quadruples like 4-7 n) +/// 3. Total number of satellites in view (leading zeros sent) +/// 4. Satellite PRN (pseudo random noise) number (leading zeros sent) +/// 5. Elevation in degrees (00-90) (leading zeros sent) +/// 6. Azimuth in degrees to true north (000-359) (leading zeros sent) +/// 7. SNR (signal to noise ratio) in dB (00-99) (leading zeros sent), +/// apparently this may be not defined. /// 8. checksum /// +/// after 7: more satellite info quadruples like 4-7 +/// /// Example: /// @code /// $GPGSV,3,1,11,03,03,111,00,04,15,270,00,06,01,010,00,13,06,292,00*74 @@ -45,10 +48,10 @@ class gsv : public sentence public: struct satellite_info { - uint32_t id; + uint32_t prn; uint32_t elevation; uint32_t azimuth; // azimuth against true - uint32_t snr; + utils::optional snr; }; constexpr static sentence_id ID = sentence_id::GSV; diff --git a/src/marnav/nmea/gsv.cpp b/src/marnav/nmea/gsv.cpp index 8995560c..ef25904b 100644 --- a/src/marnav/nmea/gsv.cpp +++ b/src/marnav/nmea/gsv.cpp @@ -14,7 +14,7 @@ inline std::string to_string(const utils::optional & data) if (!data) return std::string{",,,"}; auto const & value = data.value(); - return format(value.id, 2) + "," + format(value.elevation, 2) + "," + return format(value.prn, 2) + "," + format(value.elevation, 2) + "," + format(value.azimuth, 3) + "," + format(value.snr, 2); } } @@ -47,13 +47,13 @@ gsv::gsv(talker talk, fields::const_iterator first, fields::const_iterator last) const int num_satellite_info = std::min(4, static_cast((size - 3) / 4)); int index = 3; - for (int id = 0; id < num_satellite_info; ++id, index += 4) { + for (int i = 0; i < num_satellite_info; ++i, index += 4) { satellite_info info; - read(*(first + index + 0), info.id); + read(*(first + index + 0), info.prn); read(*(first + index + 1), info.elevation); read(*(first + index + 2), info.azimuth); read(*(first + index + 3), info.snr); - set_sat(id, info); + set_sat(i, info); } } @@ -74,7 +74,7 @@ void gsv::set_message_number(uint32_t t) void gsv::check_index(int index) const { if ((index < 0) || (index > 3)) { - throw std::out_of_range{"satellite id out of range"}; + throw std::out_of_range{"satellite index out of range"}; } } diff --git a/src/nmeadump.cpp b/src/nmeadump.cpp index 5c02b075..91517b99 100644 --- a/src/nmeadump.cpp +++ b/src/nmeadump.cpp @@ -152,6 +152,7 @@ #include #include +#include #include #include @@ -186,6 +187,7 @@ static struct { std::string port; marnav::io::serial::baud speed; std::string file; + std::string input_string; } config; } global; @@ -207,6 +209,9 @@ static bool parse_options(int argc, char ** argv) ("f,file", "Specifies the file to use.", cxxopts::value(global.config.file)) + ("i,input", + "String to parse", + cxxopts::value(global.config.input_string)) ; // clang-format on @@ -1049,8 +1054,8 @@ static void print_detail_gsv(const marnav::nmea::sentence * s) for (int i = 0; i < 4; ++i) { const auto sat = t->get_sat(i); if (sat) { - print("Sat", fmt::sprintf("ID:%02u ELEV:%02u AZIMUTH:%03u SNR:%02u", sat->id, - sat->elevation, sat->azimuth, sat->snr)); + print("Sat", fmt::sprintf("PRN:%02u ELEV:%02u AZIMUTH:%03u SNR:%s", sat->prn, + sat->elevation, sat->azimuth, render(sat->snr))); } } } @@ -2109,6 +2114,9 @@ int main(int argc, char ** argv) utils::make_unique(global.config.port, global.config.speed, serial::databits::bit_8, serial::stopbits::bit_1, serial::parity::none)}; process([&](std::string & line) { return source.read_sentence(line); }); + } else if (!global.config.input_string.empty()) { + std::istringstream is(global.config.input_string); + process([&](std::string & line){ return !!std::getline(is, line); }); } else { std::cin.sync_with_stdio(false); process([&](std::string & line) { return !!std::getline(std::cin, line); }); diff --git a/test/nmea/Test_nmea_gsv.cpp b/test/nmea/Test_nmea_gsv.cpp index 0ac3d448..6cf7fd4d 100644 --- a/test/nmea/Test_nmea_gsv.cpp +++ b/test/nmea/Test_nmea_gsv.cpp @@ -121,33 +121,82 @@ TEST_F(Test_nmea_gsv, get_sat) auto gsv = nmea::sentence_cast(s); ASSERT_NE(nullptr, gsv); + EXPECT_EQ(3u, gsv->get_n_messages()); + EXPECT_EQ(1u, gsv->get_message_number()); + EXPECT_EQ(11u, gsv->get_n_satellites_in_view()); + { - auto sat = *gsv->get_sat(0); - EXPECT_EQ(3u, sat.id); + const auto sat = *gsv->get_sat(0); + EXPECT_EQ(3u, sat.prn); EXPECT_EQ(3u, sat.elevation); EXPECT_EQ(111u, sat.azimuth); - EXPECT_EQ(0u, sat.snr); + EXPECT_EQ(0u, *sat.snr); } { - auto sat = *gsv->get_sat(1); - EXPECT_EQ(4u, sat.id); + const auto sat = *gsv->get_sat(1); + EXPECT_EQ(4u, sat.prn); EXPECT_EQ(15u, sat.elevation); EXPECT_EQ(270u, sat.azimuth); - EXPECT_EQ(0u, sat.snr); + EXPECT_EQ(0u, *sat.snr); } { - auto sat = *gsv->get_sat(2); - EXPECT_EQ(6u, sat.id); + const auto sat = *gsv->get_sat(2); + EXPECT_EQ(6u, sat.prn); EXPECT_EQ(1u, sat.elevation); EXPECT_EQ(10u, sat.azimuth); - EXPECT_EQ(0u, sat.snr); + EXPECT_EQ(0u, *sat.snr); } { - auto sat = *gsv->get_sat(3); - EXPECT_EQ(13u, sat.id); + const auto sat = *gsv->get_sat(3); + EXPECT_EQ(13u, sat.prn); EXPECT_EQ(6u, sat.elevation); EXPECT_EQ(292u, sat.azimuth); - EXPECT_EQ(0u, sat.snr); + EXPECT_EQ(0u, *sat.snr); + } +} + +TEST_F(Test_nmea_gsv, get_sat_missing_snr_github_issue_35) +{ + // thanks to github.com/norton-dev for providing this example + + auto s = nmea::make_sentence( + "$GPGSV,3,1,09,09,74,265,,04,63,066,14,06,50,261,,03,32,123,31*7B"); + ASSERT_NE(nullptr, s); + + auto gsv = nmea::sentence_cast(s); + ASSERT_NE(nullptr, gsv); + + EXPECT_EQ(3u, gsv->get_n_messages()); + EXPECT_EQ(1u, gsv->get_message_number()); + EXPECT_EQ(9u, gsv->get_n_satellites_in_view()); + + { + const auto sat = *gsv->get_sat(0); + EXPECT_EQ(9u, sat.prn); + EXPECT_EQ(74u, sat.elevation); + EXPECT_EQ(265u, sat.azimuth); + EXPECT_FALSE(sat.snr); + } + { + const auto sat = *gsv->get_sat(1); + EXPECT_EQ(4u, sat.prn); + EXPECT_EQ(63u, sat.elevation); + EXPECT_EQ(66u, sat.azimuth); + EXPECT_EQ(14u, *sat.snr); + } + { + const auto sat = *gsv->get_sat(2); + EXPECT_EQ(6u, sat.prn); + EXPECT_EQ(50u, sat.elevation); + EXPECT_EQ(261u, sat.azimuth); + EXPECT_FALSE(sat.snr); + } + { + const auto sat = *gsv->get_sat(3); + EXPECT_EQ(3u, sat.prn); + EXPECT_EQ(32u, sat.elevation); + EXPECT_EQ(123u, sat.azimuth); + EXPECT_EQ(31u, *sat.snr); } } } -- 2.11.4.GIT