From c2be6c4068d474c17f4cf22951101efde93dfd10 Mon Sep 17 00:00:00 2001 From: geeksville Date: Mon, 4 May 2020 17:39:57 -0700 Subject: [PATCH] WIP on #124 --- .vscode/settings.json | 1 + docs/software/nrf52-TODO.md | 3 +- platformio.ini | 3 +- src/gps/GPS.cpp | 18 ++++++++++++ src/gps/GPS.h | 6 +++- src/gps/NEMAGPS.cpp | 56 +++++++++++++++++++++++++++++++++++++ src/gps/NEMAGPS.h | 19 +++++++++++++ src/gps/UBloxGPS.cpp | 50 ++++++++++++--------------------- src/main.cpp | 9 +++++- 9 files changed, 129 insertions(+), 36 deletions(-) create mode 100644 src/gps/NEMAGPS.cpp create mode 100644 src/gps/NEMAGPS.h diff --git a/.vscode/settings.json b/.vscode/settings.json index bfef8191b..ebed64343 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -52,6 +52,7 @@ "cSpell.words": [ "Blox", "Meshtastic", + "NEMAGPS", "Ublox", "descs", "protobufs" diff --git a/docs/software/nrf52-TODO.md b/docs/software/nrf52-TODO.md index 6bc5fb0d2..59a467fef 100644 --- a/docs/software/nrf52-TODO.md +++ b/docs/software/nrf52-TODO.md @@ -9,7 +9,7 @@ Minimum items needed to make sure hardware is good. - plug in correct variants for the real board - Use the PMU driver on real hardware - add a NEMA based GPS driver to test GPS -- Use new radio driver on real hardware +- Use new radio driver on real hardware - Use UC1701 LCD driver on real hardware. Still need to create at startup and probe on SPI - test the LEDs - test the buttons @@ -24,6 +24,7 @@ Minimum items needed to make sure hardware is good. Needed to be fully functional at least at the same level of the ESP32 boards. At this point users would probably want them. +- stop polling for GPS characters, instead stay blocked on read in a thread - increase preamble length? - will break other clients? so all devices must update - enable BLE DFU somehow - set appversion/hwversion diff --git a/platformio.ini b/platformio.ini index b64bcf002..61b61d677 100644 --- a/platformio.ini +++ b/platformio.ini @@ -74,7 +74,8 @@ lib_deps = https://github.com/meshtastic/arduino-fsm.git https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git https://github.com/meshtastic/RadioLib.git - + https://github.com/meshtastic/TinyGPSPlus.git + ; Common settings for ESP targes, mixin with extends = esp32_base [esp32_base] src_filter = diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 9273a6ed2..d8d73784e 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -50,6 +50,24 @@ void perhapsSetRTC(const struct timeval *tv) } } +void perhapsSetRTC(struct tm &t) +{ + /* Convert to unix time + The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970 + (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z). + */ + time_t res = mktime(&t); + struct timeval tv; + tv.tv_sec = res; + tv.tv_usec = 0; // time.centisecond() * (10 / 1000); + + DEBUG_MSG("Got time from GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec); + if (t.tm_year < 0 || t.tm_year >= 300) + DEBUG_MSG("Ignoring invalid GPS time\n"); + else + perhapsSetRTC(&tv); +} + #include uint32_t getTime() diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 1c25ec2f4..3eb972843 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -6,6 +6,7 @@ /// If we haven't yet set our RTC this boot, set it from a GPS derived time void perhapsSetRTC(const struct timeval *tv); +void perhapsSetRTC(struct tm &t); /// Return time since 1970 in secs. Until we have a GPS lock we will be returning time based at zero uint32_t getTime(); @@ -37,7 +38,10 @@ class GPS : public Observable /** * Returns true if we succeeded */ - virtual bool setup() = 0; + virtual bool setup() { return true; } + + /// A loop callback for subclasses that need it. FIXME, instead just block on serial reads + virtual void loop() {} /// Returns ture if we have acquired GPS lock. bool hasLock() const { return hasValidLocation; } diff --git a/src/gps/NEMAGPS.cpp b/src/gps/NEMAGPS.cpp new file mode 100644 index 000000000..74cdf7606 --- /dev/null +++ b/src/gps/NEMAGPS.cpp @@ -0,0 +1,56 @@ +#include "NEMAGPS.h" +#include "configuration.h" + +static int32_t toDegInt(RawDegrees d) +{ + int32_t degMult = 10000000; // 1e7 + int32_t r = d.deg * degMult + d.billionths / 100; + if (d.negative) + r *= -1; + return r; +} + +void NEMAGPS::loop() +{ + while (_serial_gps.available() > 0) { + int c = _serial_gps.read(); + Serial.write(c); + reader.encode(c); + } + + auto ti = reader.time; + auto d = reader.date; + if (ti.isUpdated() && ti.isValid() && d.isValid()) { + /* Convert to unix time +The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970 +(midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z). +*/ + struct tm t; + t.tm_sec = ti.second(); + t.tm_min = ti.minute(); + t.tm_hour = ti.hour(); + t.tm_mday = d.day(); + t.tm_mon = d.month() - 1; + t.tm_year = d.year() - 1900; + t.tm_isdst = false; + perhapsSetRTC(t); + } + + if (reader.altitude.isUpdated() || reader.location.isUpdated()) { // probably get updated at the same time + if (reader.altitude.isValid()) + altitude = reader.altitude.meters(); + + auto loc = reader.location; + if (loc.isValid()) { + latitude = toDegInt(loc.rawLat()); + longitude = toDegInt(loc.rawLng()); + } + + // expect gps pos lat=37.520825, lon=-122.309162, alt=158 + DEBUG_MSG("new NEMA GPS pos lat=%f, lon=%f, alt=%d\n", latitude * 1e-7, longitude * 1e-7, altitude); + + hasValidLocation = (latitude != 0) || (longitude != 0); // bogus lat lon is reported as 0,0 + if (hasValidLocation) + notifyObservers(NULL); + } +} \ No newline at end of file diff --git a/src/gps/NEMAGPS.h b/src/gps/NEMAGPS.h new file mode 100644 index 000000000..ddaf77ee2 --- /dev/null +++ b/src/gps/NEMAGPS.h @@ -0,0 +1,19 @@ +#pragma once + +#include "GPS.h" +#include "Observer.h" +#include "PeriodicTask.h" +#include "TinyGPS++.h" + +/** + * A gps class thatreads from a NEMA GPS stream (and FIXME - eventually keeps the gps powered down except when reading) + * + * When new data is available it will notify observers. + */ +class NEMAGPS : public GPS +{ + TinyGPSPlus reader; + + public: + virtual void loop(); +}; diff --git a/src/gps/UBloxGPS.cpp b/src/gps/UBloxGPS.cpp index 881fd2977..54f7810ee 100644 --- a/src/gps/UBloxGPS.cpp +++ b/src/gps/UBloxGPS.cpp @@ -9,8 +9,6 @@ UBloxGPS::UBloxGPS() : PeriodicTask() bool UBloxGPS::setup() { - PeriodicTask::setup(); - #ifdef GPS_RX_PIN _serial_gps.begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN); #else @@ -30,18 +28,18 @@ bool UBloxGPS::setup() if (isConnected) { DEBUG_MSG("Connected to UBLOX GPS successfully\n"); - bool factoryReset = false; + bool factoryReset = true; bool ok; if (factoryReset) { // It is useful to force back into factory defaults (9600baud, NEMA to test the behavior of boards that don't have // GPS_TX connected) ublox.factoryReset(); - delay(2000); + delay(3000); isConnected = ublox.begin(_serial_gps); DEBUG_MSG("Factory reset success=%d\n", isConnected); - if (isConnected) { - ublox.assumeAutoPVT(true, true); // Just parse NEMA for now - } + ok = ublox.saveConfiguration(3000); + assert(ok); + return false; } else { ok = ublox.setUART1Output(COM_TYPE_UBX, 500); // Use native API assert(ok); @@ -57,12 +55,10 @@ bool UBloxGPS::setup() ok = ublox.saveConfiguration(3000); assert(ok); + PeriodicTask::setup(); // We don't start our periodic task unless we actually found the device + return true; } else { - // Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just - // assume NEMA at 9600 baud. - DEBUG_MSG("ERROR: No bidirectional GPS found, hoping that it still might work\n"); - return false; } } @@ -80,26 +76,24 @@ void UBloxGPS::doTask() { uint8_t fixtype = 3; // If we are only using the RX pin, assume we have a 3d fix - if (isConnected) { - // Consume all characters that have arrived + assert(isConnected); - // getPVT automatically calls checkUblox - ublox.checkUblox(); // See if new data is available. Process bytes as they come in. + // Consume all characters that have arrived - // If we don't have a fix (a quick check), don't try waiting for a solution) - // Hmmm my fix type reading returns zeros for fix, which doesn't seem correct, because it is still sptting out positions - // turn off for now - // fixtype = ublox.getFixType(); - DEBUG_MSG("fix type %d\n", fixtype); - } + // getPVT automatically calls checkUblox + ublox.checkUblox(); // See if new data is available. Process bytes as they come in. + + // If we don't have a fix (a quick check), don't try waiting for a solution) + // Hmmm my fix type reading returns zeros for fix, which doesn't seem correct, because it is still sptting out positions + // turn off for now + // fixtype = ublox.getFixType(); + DEBUG_MSG("fix type %d\n", fixtype); // DEBUG_MSG("sec %d\n", ublox.getSecond()); // DEBUG_MSG("lat %d\n", ublox.getLatitude()); // any fix that has time if (ublox.getT()) { - struct timeval tv; - /* Convert to unix time The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z). @@ -112,15 +106,7 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s t.tm_mon = ublox.getMonth() - 1; t.tm_year = ublox.getYear() - 1900; t.tm_isdst = false; - time_t res = mktime(&t); - tv.tv_sec = res; - tv.tv_usec = 0; // time.centisecond() * (10 / 1000); - - DEBUG_MSG("Got time from GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec); - if (t.tm_year < 0 || t.tm_year >= 300) - DEBUG_MSG("Ignoring invalid GPS time\n"); - else - perhapsSetRTC(&tv); + perhapsSetRTC(t); } if ((fixtype >= 3 && fixtype <= 4) && ublox.getP()) // rd fixes only diff --git a/src/main.cpp b/src/main.cpp index b70ddb99f..3971ae9bf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ #include "MeshRadio.h" #include "MeshService.h" +#include "NEMAGPS.h" #include "NodeDB.h" #include "Periodic.h" #include "PowerFSM.h" @@ -193,7 +194,12 @@ void setup() // Init GPS - first try ublox gps = new UBloxGPS(); if (!gps->setup()) { - // FIXME - fallback to NEMA + // Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just + // assume NEMA at 9600 baud. + DEBUG_MSG("ERROR: No UBLOX GPS found, hoping that NEMA might work\n"); + delete gps; + gps = new NEMAGPS(); + gps->setup(); } service.init(); @@ -263,6 +269,7 @@ void loop() { uint32_t msecstosleep = 1000 * 30; // How long can we sleep before we again need to service the main loop? + gps->loop(); // FIXME, remove from main, instead block on read router.loop(); powerFSM.run_machine(); service.loop();