upm/tests/unit/nmea_gps/nmea_gps_tests.cxx
Noel Eck 3a077df5f6 nmea_gps: Update to handle parsing into structures
NMEA GPS class now uses threads to handle parsing NMEA sentences.
Currently only handles GGA, GSV, and GLL types.  Added queues for
holding parsed data.

    * Parsing thread
    * Parse GPS Fix from GGA and GLL
    * Parse satellite info from GSV
    * Provide a queue for GPS fix data as well as raw sentences
      (for debugging)
    * Target structures and NMEAGPS class have a __str__() method
      which summarizes the objects into a std::string.  These are
      tied to the __str__ method in python
    * Added google unit test for the above functionality

Signed-off-by: Noel Eck <noel.eck@intel.com>
2018-05-23 08:30:22 -07:00

247 lines
7.5 KiB
C++

#include "gtest/gtest.h"
#include "nmea_gps.hpp"
#include "mraa.hpp"
#include <algorithm>
#include <random>
/* NMEA GPS test fixture */
class nmea_gps_unit : public ::testing::Test
{
protected:
/* One-time setup logic if needed */
nmea_gps_unit() = default;
/* One-time tear-down logic if needed */
~nmea_gps_unit() override = default;
/* Fail if not MOCK platform */
void SetUp() override
{
ASSERT_EQ(mraa::getPlatformType(), mraa::MOCK_PLATFORM) <<
"NMEA_GPS test requires mraa compiled with mraa::MOCK_PLATFORM";
}
/* Per-test tear-down logic if needed */
void TearDown() override {}
};
/* Basic tests */
TEST_F(nmea_gps_unit, DOA)
{
upm::NMEAGPS gps(0, 115200, -1);
/* Min queue size is 1 */
gps.setMaxQueueDepth(0);
ASSERT_EQ(gps.getMaxQueueDepth(), 1);
/* Max queue size is 1000 */
gps.setMaxQueueDepth(1001);
ASSERT_EQ(gps.getMaxQueueDepth(), 1000);
/* Queues should be empty */
ASSERT_EQ(gps.fixQueueSize(), 0);
ASSERT_EQ(gps.rawSentenceQueueSize(), 0);
}
/* Check parsing varying length sentences */
TEST_F(nmea_gps_unit, parse_max_size)
{
upm::NMEAGPS gps(0, 115200, -1);
/* Parse an sentence that is too long to be NMEA */
gps.parseNMEASentence("$GPGSV,2,1,08,07,64,079,,08,39,066,,09,25,159,,09,25,159,,09,25,159,,09,25,159,,09,25,159,,09,25,159,,09,25,159,,07,64,079,*73");
ASSERT_EQ(gps.rawSentenceQueueSize(), 1);
ASSERT_EQ(gps.satellites().size(), 0);
}
/* Basic test */
TEST_F(nmea_gps_unit, parse_basic)
{
upm::NMEAGPS gps(0, 115200, -1);
/* Parse an invalid sentence */
gps.parseNMEASentence("$GPGGA,182333.50,,,,,0,00,99.99,,,,,,*6B");
}
/* Parse an invalid sentence */
TEST_F(nmea_gps_unit, parse_gps_fix_invalid)
{
upm::NMEAGPS gps(0, 115200, -1);
/* Parse an invalid sentence */
gps.parseNMEASentence("$GPGGA,182333.50,,,,,0,00,99.99,,,,,,*6B");
/* Should be 1 entry in the raw queue */
ASSERT_EQ(gps.rawSentenceQueueSize(), 1);
/* Should be 0 in GPS fix queue */
ASSERT_EQ(gps.fixQueueSize(), 0);
/* Get the GPS fix */
upm::gps_fix f = gps.getFix();
ASSERT_EQ(f.valid, false);
ASSERT_EQ(f.quality, upm::gps_fix_quality::no_fix);
/* Call the string method for coverage */
f.__str__();
/* Get the 1 raw sentence */
gps.getRawSentence();
/* Should be 0 entries in each queue */
ASSERT_EQ(gps.rawSentenceQueueSize(), 0);
ASSERT_EQ(gps.fixQueueSize(), 0);
}
std::string randstr(size_t size)
{
std::string retstr(".", size);
std::random_device rd;
std::default_random_engine eng(rd());
std::uniform_int_distribution<char> distr(32, 126);
for (size_t i = 0; i < size; i++)
retstr[i] = distr(eng);
return retstr;
}
/* Parse bogus sentences */
TEST_F(nmea_gps_unit, parse_gps_fix_bogus)
{
upm::NMEAGPS gps(0, 115200, -1);
/* Parse some bogus sentences */
std::string gga = "$GPGGA,182333.50,,,,,0,00,99.99,,,,,,*6B";
gps.parseNMEASentence(gga);
for (size_t i = 0; i < gga.size(); i++)
{
std::string tmp = gga;
gps.parseNMEASentence(tmp.replace(i, 1, "x"));
}
for (int i = 0; i < 1000; i++)
gps.parseNMEASentence(randstr(40));
/* Still no GPS fix */
ASSERT_EQ(gps.fixQueueSize(), 0);
}
/* Parse valid gga sentences */
TEST_F(nmea_gps_unit, parse_gps_fix_valid)
{
upm::NMEAGPS gps(0, 115200, -1);
/* Parse a valid sentence */
gps.parseNMEASentence("$GPGGA,172814.0,3723.46587704,N,12202.26957864,W,"
+ std::string("2,6,1.2,18.893,M,-25.669,M,2.0,0031*4F"));
/* Should be 1 entry in GPS fix queue */
ASSERT_EQ(gps.fixQueueSize(), 1);
upm::gps_fix f = gps.getFix();
ASSERT_EQ(f.valid, true) << f.__str__();
}
/* Parse valid gsv sentences */
TEST_F(nmea_gps_unit, parse_gsv_valid)
{
upm::NMEAGPS gps(0, 115200, -1);
std::vector<std::string> snts =
{
"$GPGSV,2,1,08,07,64,079,,08,39,066,,09,25,159,,11,15,117,*7B",
"$GPGSV,2,2,08,13,25,313,,30,78,336,22,48,37,194,,51,35,158,*75",
"$GPGSV,2,2,08,13,25,313,,30,78,336,21,48,37,194,,51,35,158,*76",
"$GPGSV,2,2,08,13,25,313,,30,78,336,,48,37,194,,51,35,158,*75",
"$GPGSV,2,1,08,07,64,079,,08,39,066,,09,25,159,,11,15,117,*7B",
"$GPGSV,2,2,08,13,25,313,,30,78,336,21,48,37,194,,51,35,158,*76",
"$GPGSV,2,2,08,13,25,313,,30,78,336,20,48,37,194,,51,35,158,*77",
"$GPGSV,2,1,08,07,64,079,,08,39,066,,09,25,159,,11,15,117,*7B",
"$GPGSV,2,2,08,13,25,313,,30,78,336,18,48,37,194,,51,35,158,*7C",
"$GPGSV,2,2,08,13,25,313,,30,78,336,17,48,37,194,,51,35,158,*73",
"$GPGSV,2,1,08,07,64,080,,08,39,066,,09,25,159,,11,15,117,*7D",
"$GPGSV,2,2,08,13,26,313,,30,78,336,13,48,37,194,,51,35,158,*74",
"$GPGSV,2,1,08,07,64,080,,08,39,066,,09,25,159,,11,15,117,*7D",
"$GPGSV,2,2,08,13,26,313,,30,78,336,09,48,37,194,,51,35,158,*7F",
"$GPGSV,2,1,08,07,64,080,,08,39,066,,09,25,160,,11,15,117,*77",
"$GPGSV,2,2,08,13,26,313,,30,78,336,23,48,37,194,,51,35,158,*77",
"$GPGSV,3,3,09,51,35,158,*4E",
"$GPGSV,2,1,08,07,64,080,22,08,39,066,,09,25,160,,11,15,117,*77",
"$GPGSV,2,1,08,07,64,080,21,08,39,066,,09,25,160,,11,15,117,*74"
};
/* Parse the first sentence */
gps.parseNMEASentence(snts.front());
/* Should have 4 satellites */
auto sats = gps.satellites();
ASSERT_EQ(sats.size(), 4);
ASSERT_EQ(sats[0].prn, "07");
ASSERT_EQ(sats[0].elevation_deg, 64);
ASSERT_EQ(sats[0].azimuth_deg, 79);
ASSERT_EQ(sats[0].snr, 0);
ASSERT_EQ(sats[1].prn, "08");
ASSERT_EQ(sats[1].elevation_deg, 39);
ASSERT_EQ(sats[1].azimuth_deg, 66);
ASSERT_EQ(sats[1].snr, 0);
ASSERT_EQ(sats[2].prn, "09");
ASSERT_EQ(sats[2].elevation_deg, 25);
ASSERT_EQ(sats[2].azimuth_deg, 159);
ASSERT_EQ(sats[2].snr, 0);
ASSERT_EQ(sats[3].prn, "11");
ASSERT_EQ(sats[3].elevation_deg, 15);
ASSERT_EQ(sats[3].azimuth_deg, 117);
ASSERT_EQ(sats[3].snr, 0);
/* Parse the rest */
for(const auto& sentence : snts)
gps.parseNMEASentence(sentence);
/* Finish up with 8 satellites */
sats = gps.satellites();
ASSERT_EQ(sats.size(), 8);
/* Verify the last satellite */
ASSERT_EQ(sats.back().prn, "11");
ASSERT_EQ(sats.back().elevation_deg, 15);
ASSERT_EQ(sats.back().azimuth_deg, 117);
ASSERT_EQ(sats.back().snr, 0);
/* The 4th should have a non-zero snr */
ASSERT_EQ(sats[4].snr, 21);
}
/* Parse valid gll sentences */
TEST_F(nmea_gps_unit, parse_gll_valid)
{
upm::NMEAGPS gps(0, 115200, -1);
std::vector<std::string> snts =
{
"$GPGLL,4532.55107,N,12257.68422,W,170004.20,A,A*74",
"$GPGLL,4532.55008,N,12257.68195,W,170005.00,A,A*70",
"$GPGLL,4532.55027,N,12257.68252,W,170006.10,A,A*77",
"$GPGLL,4532.54370,N,12257.65873,W,170006.90,A,A*7B",
"$GPGLL,4532.54230,N,12257.65302,W,170008.00,A,A*74"
};
/* Parse the first sentence */
gps.parseNMEASentence(snts.front());
/* Get the fix */
upm::gps_fix f = gps.getFix();
ASSERT_EQ(f.valid, true) << f.__str__();
ASSERT_FLOAT_EQ(f.coordinates.latitude, 45.542517833333335) << f.__str__();
ASSERT_FLOAT_EQ(f.coordinates.longitude, -122.96140366666667) << f.__str__();
ASSERT_EQ(f.time_utc, "170004.20") << f.__str__();
/* Parse the rest */
for(const auto& sentence : snts)
gps.parseNMEASentence(sentence);
/* Should have 5 GPS fixes */
ASSERT_EQ(gps.fixQueueSize(), 5);
}