#pragma once #include #include #include #include #include #include #include namespace roro::gnss { enum class Constellation : uint8_t { Unknown, Gps, Glonass, Galileo, BeiDou, Qzss, Navic }; const char* constellationName(Constellation c); enum class FixType : uint8_t { None, TwoD, ThreeD }; struct Satellite { Constellation system = Constellation::Unknown; int prn = 0; int elevation = 0; // degrees above the horizon int azimuth = 0; // degrees from north, clockwise int snr = -1; // dB-Hz; -1 when not tracked bool used = false; // part of the current Fix }; // Everything the receiver has said, as of the last sentence (see CONTEXT.md: Fix). struct GnssState { FixType fix = FixType::None; bool positionValid = false; double latitude = 0, longitude = 0; // degrees, south and west negative bool altitudeValid = false; float altitudeM = 0; // above mean sea level float speedKmh = 0; bool courseValid = false; float courseDeg = 0; int satellitesUsed = 0; float hdop = 99.9f; // UTC, trusted only with a Fix: the receiver reports a time without one, from its own clock. bool timeValid = false; int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0; std::vector satellites; // in view, all constellations, one entry per satellite int64_t utcSeconds() const; // seconds since 1970-01-01 UTC; meaningful when timeValid }; // NMEA 0183 (4.10 style, as the Cap's AT6668 sends it): RMC, GGA, GSA and GSV, with the // constellation taken from the talker ID or GSA's system ID field. Host-tested; no hardware here. class NmeaParser { public: // Raw bytes from the UART, in any chunks. void feed(const char* data, size_t len); // One sentence without its line end. False if malformed or its checksum is wrong. bool sentence(const std::string& line); const GnssState& state() const { return state_; } uint32_t goodSentences() const { return good_; } uint32_t badSentences() const { return bad_; } private: using Fields = std::vector; void rmc(const Fields& f); void gga(const Fields& f); void gsa(const Fields& f, Constellation talker); void gsv(const Fields& f, Constellation talker); void rebuildSatellites(); static constexpr size_t kMaxLine = 120; std::string line_; bool overflow_ = false; uint32_t good_ = 0, bad_ = 0; GnssState state_; // GSV sequences per (constellation, signal): pending until their last message. std::map, std::vector> pending_, inView_; std::map> used_; // per constellation, from GSA }; } // namespace roro::gnss