From c0c83ad38956102aceb99eaabfcebcc2e4a475f6 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Wed, 7 Oct 2020 17:46:25 +0800 Subject: [PATCH 01/12] If we are not supposed to share locations make sure phone doesn't either --- docs/software/gps-todo.txt | 28 +--------------------------- src/mesh/PhoneAPI.cpp | 6 +++++- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/docs/software/gps-todo.txt b/docs/software/gps-todo.txt index 79503ebc..ca8a2781 100644 --- a/docs/software/gps-todo.txt +++ b/docs/software/gps-todo.txt @@ -1,4 +1,4 @@ -gps todo - bug 376 +You probably don't care about this ugly file of personal notes ;-) for taiwan region: bin/run.sh --set region 8 @@ -6,40 +6,14 @@ bin/run.sh --set region 8 time only mode ./bin/run.sh --set gps_operation 3 -increase acquisition time until ublox power management can be improved see 9.3.1 - ublox parsing failure record power measurements and update spreadsheet -fix has_gps based on new logic - make sure we are turning off lora radio in deep sleep -don't send locations if the user has forbidden that (lie to phone so phone won't either) - have loop methods return allowable sleep time (from their perspective) increase main cpu sleep time -add set router mode in python tool - it will also set GPS to stationary -make sure location still gets set once per boot and stays marked as valid on the gui -send position updates super rarely -turn off checking for usb power and forcing always on -(which will shrink DARK and NB period to zero and - make light_sleep very long) - warn people about crummy gps antennas - add to faq - -gps states - -Active - for gps_attempt_time seconds -Sleeping - for (gps_update_rate or sleep forever) seconds -ForcedSleep - PowerFSM says we don't want to use GPS right now -(no need for sleep forever state) - -gps triggers -GPS_TRIG_FORCE_SLEEP - from powerfsm -GPS_TRIG_FORCE_WAKE - from powerfsm -GPS_SETTINGS - if GPS settings changed, reset params and possibly become active - diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 3cbcef17..fce496c8 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -109,7 +109,11 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) break; case STATE_SEND_MY_INFO: - myNodeInfo.has_gps = gps && gps->isConnected; // Update with latest GPS connect info + // If the user has specified they don't want our node to share its location, make sure to tell the phone + // app not to send locations on our behalf. + myNodeInfo.has_gps = (radioConfig.preferences.location_share == LocationSharing_LocDisabled) + ? true + : (gps && gps->isConnected); // Update with latest GPS connect info fromRadioScratch.which_variant = FromRadio_my_info_tag; fromRadioScratch.variant.my_info = myNodeInfo; state = STATE_SEND_RADIO; From b47c54b5b69af631fe6794c00861b4bbeda1c477 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Wed, 7 Oct 2020 17:52:44 +0800 Subject: [PATCH 02/12] keep lora radio totally unpowered when in deep-sleep --- docs/software/gps-todo.txt | 2 -- src/sleep.cpp | 11 ++++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/software/gps-todo.txt b/docs/software/gps-todo.txt index ca8a2781..5dc8c273 100644 --- a/docs/software/gps-todo.txt +++ b/docs/software/gps-todo.txt @@ -10,8 +10,6 @@ ublox parsing failure record power measurements and update spreadsheet -make sure we are turning off lora radio in deep sleep - have loop methods return allowable sleep time (from their perspective) increase main cpu sleep time diff --git a/src/sleep.cpp b/src/sleep.cpp index a6753d8a..d3a55062 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -170,17 +170,18 @@ void doDeepSleep(uint64_t msecToWake) #ifdef TBEAM_V10 if (axp192_found) { + // Obsolete comment: from back when we we used to receive lora packets while CPU was in deep sleep. + // We no longer do that, because our light-sleep current draws are low enough and it provides fast start/low cost + // wake. We currently use deep sleep only for 'we want our device to actually be off - because our battery is + // critically low'. So in deep sleep we DO shut down power to LORA (and when we boot later we completely reinit it) + // // No need to turn this off if the power draw in sleep mode really is just 0.2uA and turning it off would // leave floating input for the IRQ line - // If we want to leave the radio receving in would be 11.5mA current draw, but most of the time it is just waiting // in its sequencer (true?) so the average power draw should be much lower even if we were listinging for packets // all the time. - // axp.setPowerOutPut(AXP192_LDO2, AXP202_OFF); // LORA radio - - // now done by UBloxGPS.cpp - // setGPSPower(false); + axp.setPowerOutPut(AXP192_LDO2, AXP202_OFF); // LORA radio } #endif From fc82e872d6e159c9394f84283f82de5cec156d0a Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 8 Oct 2020 05:23:52 +0800 Subject: [PATCH 03/12] don't require gps to have lock before we'll trust GPS time --- docs/software/gps-todo.txt | 3 +++ platformio.ini | 2 +- src/gps/UBloxGPS.cpp | 32 +++++++++++++++----------------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/docs/software/gps-todo.txt b/docs/software/gps-todo.txt index 5dc8c273..ab750d9e 100644 --- a/docs/software/gps-todo.txt +++ b/docs/software/gps-todo.txt @@ -6,6 +6,9 @@ bin/run.sh --set region 8 time only mode ./bin/run.sh --set gps_operation 3 +allow longer locking attempts +allow locking while cpu sleeps +test with crummy antenna ublox parsing failure record power measurements and update spreadsheet diff --git a/platformio.ini b/platformio.ini index b48dc393..504165bc 100644 --- a/platformio.ini +++ b/platformio.ini @@ -62,7 +62,7 @@ lib_deps = 1260 ; OneButton library for non-blocking button debounce 1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib https://github.com/meshtastic/arduino-fsm.git - https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#cb8353dfddd1b0e205098f5e70d5f2a5f74b4838 + https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad https://github.com/meshtastic/RadioLib.git#1083c2e76f9906c5f80dfec726facebf8413eef0 https://github.com/meshtastic/TinyGPSPlus.git https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460 diff --git a/src/gps/UBloxGPS.cpp b/src/gps/UBloxGPS.cpp index 1007162b..ba30935f 100644 --- a/src/gps/UBloxGPS.cpp +++ b/src/gps/UBloxGPS.cpp @@ -138,23 +138,21 @@ void UBloxGPS::whileActive() */ bool UBloxGPS::lookForTime() { - if (fixType >= 2) { - if (ublox.moduleQueried.gpsSecond) { - /* 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 = ublox.getSecond(0); - t.tm_min = ublox.getMinute(0); - t.tm_hour = ublox.getHour(0); - t.tm_mday = ublox.getDay(0); - t.tm_mon = ublox.getMonth(0) - 1; - t.tm_year = ublox.getYear(0) - 1900; - t.tm_isdst = false; - perhapsSetRTC(t); - return true; - } + if (ublox.moduleQueried.gpsSecond) { + /* 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 = ublox.getSecond(0); + t.tm_min = ublox.getMinute(0); + t.tm_hour = ublox.getHour(0); + t.tm_mday = ublox.getDay(0); + t.tm_mon = ublox.getMonth(0) - 1; + t.tm_year = ublox.getYear(0) - 1900; + t.tm_isdst = false; + perhapsSetRTC(t); + return true; } return false; From bdcd5c3981f3977f0e2de338e7489d0dd553ff70 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 8 Oct 2020 06:22:25 +0800 Subject: [PATCH 04/12] allow reporting # sats before we ahve a fix --- docs/software/gps-todo.txt | 1 - platformio.ini | 2 +- src/gps/UBloxGPS.cpp | 12 ++++++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/software/gps-todo.txt b/docs/software/gps-todo.txt index ab750d9e..f22e53f9 100644 --- a/docs/software/gps-todo.txt +++ b/docs/software/gps-todo.txt @@ -6,7 +6,6 @@ bin/run.sh --set region 8 time only mode ./bin/run.sh --set gps_operation 3 -allow longer locking attempts allow locking while cpu sleeps test with crummy antenna ublox parsing failure diff --git a/platformio.ini b/platformio.ini index 504165bc..cf255f38 100644 --- a/platformio.ini +++ b/platformio.ini @@ -63,7 +63,7 @@ lib_deps = 1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib https://github.com/meshtastic/arduino-fsm.git https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad - https://github.com/meshtastic/RadioLib.git#1083c2e76f9906c5f80dfec726facebf8413eef0 + https://github.com/meshtastic/RadioLib.git#8657380241bce681c33aab46598bbf13b11f876c https://github.com/meshtastic/TinyGPSPlus.git https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460 Wire ; explicitly needed here because the AXP202 library forgets to add it diff --git a/src/gps/UBloxGPS.cpp b/src/gps/UBloxGPS.cpp index ba30935f..f59b3bf0 100644 --- a/src/gps/UBloxGPS.cpp +++ b/src/gps/UBloxGPS.cpp @@ -32,7 +32,7 @@ bool UBloxGPS::setupGPS() _serial_gps->begin(GPS_BAUDRATE); #endif #ifndef NO_ESP32 - _serial_gps->setRxBufferSize(1024); // the default is 256 + _serial_gps->setRxBufferSize(2048); // the default is 256 #endif } @@ -126,7 +126,7 @@ void UBloxGPS::whileActive() // Update fixtype if (ublox.moduleQueried.fixType) { fixType = ublox.getFixType(0); - DEBUG_MSG("GPS fix type %d\n", fixType); + DEBUG_MSG("GPS fix type %d, numSats %d\n", fixType, numSatellites); } } @@ -168,6 +168,12 @@ bool UBloxGPS::lookForLocation() { bool foundLocation = false; + if (ublox.moduleQueried.SIV) + numSatellites = ublox.getSIV(0); + + if (ublox.moduleQueried.pDOP) + dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it + // we only notify if position has changed due to a new fix if ((fixType >= 3 && fixType <= 4)) { if (ublox.moduleQueried.latitude) // rd fixes only @@ -175,12 +181,10 @@ bool UBloxGPS::lookForLocation() latitude = ublox.getLatitude(0); longitude = ublox.getLongitude(0); altitude = ublox.getAltitudeMSL(0) / 1000; // in mm convert to meters - dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it // Note: heading is only currently implmented in the ublox for the 8m chipset - therefore // don't read it here - it will generate an ignored getPVT command on the 6ms // heading = ublox.getHeading(0); - numSatellites = ublox.getSIV(0); // bogus lat lon is reported as 0 or 0 (can be bogus just for one) // Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg! From 1a3cc40c7e1e842bcef37aba07d0c7a9fe1a8230 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 8 Oct 2020 06:23:05 +0800 Subject: [PATCH 05/12] sx1262 better to check for header because preamble might never result in irq --- src/main.cpp | 8 ++++++-- src/mesh/RadioLibInterface.h | 8 +++++--- src/mesh/SX1262Interface.cpp | 8 +++++--- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f4e811f5..a6affea1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -151,6 +151,8 @@ void userButtonPressedLong() screen.adjustBrightness(); } +RadioInterface *rIf = NULL; + void setup() { #ifdef USE_SEGGER @@ -298,8 +300,7 @@ void setup() digitalWrite(SX1262_ANT_SW, 1); #endif - // MUST BE AFTER service.init, so we have our radio config settings (from nodedb init) - RadioInterface *rIf = NULL; + // radio init MUST BE AFTER service.init, so we have our radio config settings (from nodedb init) #if defined(RF95_IRQ) if (!rIf) { @@ -405,6 +406,9 @@ void loop() loopWifi(); + // For debugging + // if (rIf) ((RadioLibInterface *)rIf)->isActivelyReceiving(); + // Show boot screen for first 3 seconds, then switch to normal operation. static bool showingBootScreen = true; if (showingBootScreen && (millis() > 3000)) { diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index d393077b..b1d62bdb 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -137,6 +137,11 @@ class RadioLibInterface : public RadioInterface, private concurrency::PeriodicTa */ virtual void startReceive() = 0; + /** are we actively receiving a packet (only called during receiving state) + * This method is only public to facilitate debugging. Do not call. + */ + virtual bool isActivelyReceiving() = 0; + private: /** if we have something waiting to send, start a short random timer so we can come check for collision before actually doing * the transmit @@ -176,9 +181,6 @@ class RadioLibInterface : public RadioInterface, private concurrency::PeriodicTa /** Could we send right now (i.e. either not actively receiving or transmitting)? */ virtual bool canSendImmediately(); - /** are we actively receiving a packet (only called during receiving state) */ - virtual bool isActivelyReceiving() = 0; - /** * Raw ISR handler that just calls our polymorphic method */ diff --git a/src/mesh/SX1262Interface.cpp b/src/mesh/SX1262Interface.cpp index b17acd9f..a177441a 100644 --- a/src/mesh/SX1262Interface.cpp +++ b/src/mesh/SX1262Interface.cpp @@ -179,16 +179,18 @@ void SX1262Interface::startReceive() /** Could we send right now (i.e. either not actively receving or transmitting)? */ bool SX1262Interface::isActivelyReceiving() { - // The IRQ status will be cleared when we start our read operation. Check if we've started a preamble, but haven't yet + // The IRQ status will be cleared when we start our read operation. Check if we've started a header, but haven't yet // received and handled the interrupt for reading the packet/handling errors. + // FIXME: it would be better to check for preamble, but we currently have our ISR not set to fire for packets that + // never even get a valid header, so we don't want preamble to get set and stay set due to noise on the network. uint16_t irq = lora.getIrqStatus(); - bool hasPreamble = (irq & SX126X_IRQ_PREAMBLE_DETECTED); + bool hasPreamble = (irq & SX126X_IRQ_HEADER_VALID); // this is not correct - often always true - need to add an extra conditional // size_t bytesPending = lora.getPacketLength(); - // if (hasPreamble || bytesPending) DEBUG_MSG("rx hasPre %d, bytes %d\n", hasPreamble, bytesPending); + // if (hasPreamble) DEBUG_MSG("rx hasPreamble\n"); return hasPreamble; } From 62c228b9867333311f02f2e60b24d2dc87759882 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 8 Oct 2020 06:23:53 +0800 Subject: [PATCH 06/12] gps: don't stop lock attempts just because the main cpu is sleeping --- src/gps/GPS.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index ba43041d..29a6179d 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -151,7 +151,7 @@ uint32_t GPS::getWakeTime() const return t; // already maxint if (t == 0) - t = 5 * 60; // Allow up to 5 mins for each attempt (probably will be much less if we can find sats) + t = 15 * 60; // Allow up to 5 mins for each attempt (probably will be much less if we can find sats) t *= 1000; // msecs @@ -208,7 +208,7 @@ void GPS::loop() // While we are awake if (isAwake) { // DEBUG_MSG("looking for location\n"); - if ((now - lastWhileActiveMsec) > 1000) { + if ((now - lastWhileActiveMsec) > 5000) { lastWhileActiveMsec = now; whileActive(); } @@ -224,7 +224,7 @@ void GPS::loop() // Once we get a location we no longer desperately want an update // or if we got a time and we are in GpsOpTimeOnly mode // DEBUG_MSG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime); - if (gotLoc || tooLong || (gotTime && getGpsOp() == GpsOperation_GpsOpTimeOnly)) { + if ((gotLoc && timeSetFromGPS) || tooLong || (gotTime && getGpsOp() == GpsOperation_GpsOpTimeOnly)) { if (gotLoc) hasValidLocation = true; @@ -247,7 +247,10 @@ void GPS::forceWake(bool on) wakeAllowed = true; } else { wakeAllowed = false; - setAwake(false); + + // Note: if the gps was already awake, we DO NOT shut it down, because we want to allow it to complete its lock + // attempt even if we are in light sleep. Once the attempt succeeds (or times out) we'll then shut it down. + // setAwake(false); } } From f00d07baa32a714b1be2fb5a370f98de3978fbc7 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 8 Oct 2020 07:28:57 +0800 Subject: [PATCH 07/12] RTC: pull rtc code into own file for cleanup --- docs/software/gps-todo.txt | 4 +-- src/gps/GPS.cpp | 68 +---------------------------------- src/gps/GPS.h | 14 -------- src/gps/NMEAGPS.cpp | 1 + src/gps/RTC.cpp | 72 ++++++++++++++++++++++++++++++++++++++ src/gps/RTC.h | 19 ++++++++++ src/gps/UBloxGPS.cpp | 1 + src/main.cpp | 1 + src/mesh/MeshService.cpp | 1 + src/mesh/NodeDB.cpp | 1 + src/mesh/Router.cpp | 2 +- 11 files changed, 100 insertions(+), 84 deletions(-) create mode 100644 src/gps/RTC.cpp create mode 100644 src/gps/RTC.h diff --git a/docs/software/gps-todo.txt b/docs/software/gps-todo.txt index f22e53f9..9612da31 100644 --- a/docs/software/gps-todo.txt +++ b/docs/software/gps-todo.txt @@ -6,8 +6,8 @@ bin/run.sh --set region 8 time only mode ./bin/run.sh --set gps_operation 3 -allow locking while cpu sleeps -test with crummy antenna +set time provisionally from net even if we have gps + ublox parsing failure record power measurements and update spreadsheet diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 29a6179d..f39772d3 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -4,7 +4,7 @@ #include "configuration.h" #include "sleep.h" #include -#include +#include "RTC.h" // If we have a serial GPS port it will not be null #ifdef GPS_RX_PIN @@ -23,75 +23,9 @@ uint8_t GPS::i2cAddress = GPS_I2C_ADDRESS; uint8_t GPS::i2cAddress = 0; #endif -bool timeSetFromGPS; // We try to set our time from GPS each time we wake from sleep GPS *gps; -// stuff that really should be in in the instance instead... -static uint32_t - timeStartMsec; // Once we have a GPS lock, this is where we hold the initial msec clock that corresponds to that time -static uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only updated once on initial lock - -void readFromRTC() -{ - struct timeval tv; /* btw settimeofday() is helpfull here too*/ - - if (!gettimeofday(&tv, NULL)) { - uint32_t now = millis(); - - DEBUG_MSG("Read RTC time as %ld (cur millis %u) valid=%d\n", tv.tv_sec, now, timeSetFromGPS); - timeStartMsec = now; - zeroOffsetSecs = tv.tv_sec; - } -} - -/// If we haven't yet set our RTC this boot, set it from a GPS derived time -bool perhapsSetRTC(const struct timeval *tv) -{ - if (!timeSetFromGPS) { - timeSetFromGPS = true; - DEBUG_MSG("Setting RTC %ld secs\n", tv->tv_sec); -#ifndef NO_ESP32 - settimeofday(tv, NULL); -#else - DEBUG_MSG("ERROR TIME SETTING NOT IMPLEMENTED!\n"); -#endif - readFromRTC(); - return true; - } else { - return false; - } -} - -bool 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 month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec); - return false; - } else { - return perhapsSetRTC(&tv); - } -} - -uint32_t getTime() -{ - return ((millis() - timeStartMsec) / 1000) + zeroOffsetSecs; -} - -uint32_t getValidTime() -{ - return timeSetFromGPS ? getTime() : 0; -} bool GPS::setup() { diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 1f8429a4..3c0b0c48 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -1,25 +1,11 @@ #pragma once -#include "../concurrency/PeriodicTask.h" #include "GPSStatus.h" #include "Observer.h" -#include "sys/time.h" - -/// If we haven't yet set our RTC this boot, set it from a GPS derived time -bool perhapsSetRTC(const struct timeval *tv); -bool perhapsSetRTC(struct tm &t); // Generate a string representation of DOP const char *getDOPString(uint32_t dop); -/// Return time since 1970 in secs. Until we have a GPS lock we will be returning time based at zero -uint32_t getTime(); - -/// Return time since 1970 in secs. If we don't have a GPS lock return zero -uint32_t getValidTime(); - -void readFromRTC(); - /** * A gps class that only reads from the GPS periodically (and FIXME - eventually keeps the gps powered down except when reading) * diff --git a/src/gps/NMEAGPS.cpp b/src/gps/NMEAGPS.cpp index 1b6bb1b3..41b1d476 100644 --- a/src/gps/NMEAGPS.cpp +++ b/src/gps/NMEAGPS.cpp @@ -1,5 +1,6 @@ #include "NMEAGPS.h" #include "configuration.h" +#include "RTC.h" static int32_t toDegInt(RawDegrees d) { diff --git a/src/gps/RTC.cpp b/src/gps/RTC.cpp new file mode 100644 index 00000000..de55ebdb --- /dev/null +++ b/src/gps/RTC.cpp @@ -0,0 +1,72 @@ +#include "configuration.h" +#include "RTC.h" +#include +#include + +bool timeSetFromGPS; // We try to set our time from GPS each time we wake from sleep + +// stuff that really should be in in the instance instead... +static uint32_t + timeStartMsec; // Once we have a GPS lock, this is where we hold the initial msec clock that corresponds to that time +static uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only updated once on initial lock + +void readFromRTC() +{ + struct timeval tv; /* btw settimeofday() is helpfull here too*/ + + if (!gettimeofday(&tv, NULL)) { + uint32_t now = millis(); + + DEBUG_MSG("Read RTC time as %ld (cur millis %u) valid=%d\n", tv.tv_sec, now, timeSetFromGPS); + timeStartMsec = now; + zeroOffsetSecs = tv.tv_sec; + } +} + +/// If we haven't yet set our RTC this boot, set it from a GPS derived time +bool perhapsSetRTC(const struct timeval *tv) +{ + if (!timeSetFromGPS) { + timeSetFromGPS = true; + DEBUG_MSG("Setting RTC %ld secs\n", tv->tv_sec); +#ifndef NO_ESP32 + settimeofday(tv, NULL); +#else + DEBUG_MSG("ERROR TIME SETTING NOT IMPLEMENTED!\n"); +#endif + readFromRTC(); + return true; + } else { + return false; + } +} + +bool 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 month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec); + return false; + } else { + return perhapsSetRTC(&tv); + } +} + +uint32_t getTime() +{ + return ((millis() - timeStartMsec) / 1000) + zeroOffsetSecs; +} + +uint32_t getValidTime() +{ + return timeSetFromGPS ? getTime() : 0; +} diff --git a/src/gps/RTC.h b/src/gps/RTC.h new file mode 100644 index 00000000..869de4b2 --- /dev/null +++ b/src/gps/RTC.h @@ -0,0 +1,19 @@ +#pragma once + +#include "configuration.h" +#include "sys/time.h" +#include + +extern bool timeSetFromGPS; // We try to set our time from GPS each time we wake from sleep + +/// If we haven't yet set our RTC this boot, set it from a GPS derived time +bool perhapsSetRTC(const struct timeval *tv); +bool 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(); + +/// Return time since 1970 in secs. If we don't have a GPS lock return zero +uint32_t getValidTime(); + +void readFromRTC(); \ No newline at end of file diff --git a/src/gps/UBloxGPS.cpp b/src/gps/UBloxGPS.cpp index f59b3bf0..36541719 100644 --- a/src/gps/UBloxGPS.cpp +++ b/src/gps/UBloxGPS.cpp @@ -1,4 +1,5 @@ #include "UBloxGPS.h" +#include "RTC.h" #include "error.h" #include "sleep.h" #include diff --git a/src/main.cpp b/src/main.cpp index a6affea1..1e1f1e01 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -34,6 +34,7 @@ // #include "rom/rtc.h" #include "DSRRouter.h" // #include "debug.h" +#include "RTC.h" #include "SPILock.h" #include "graphics/Screen.h" #include "main.h" diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index b514b0c5..5201fcd9 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -10,6 +10,7 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" +#include "RTC.h" #include "main.h" #include "mesh-pb-constants.h" #include "power.h" diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 349e7e67..1224ae6d 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -10,6 +10,7 @@ #include "NodeDB.h" #include "PacketHistory.h" #include "PowerFSM.h" +#include "RTC.h" #include "Router.h" #include "configuration.h" #include "error.h" diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 74bb2196..6a338200 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -1,6 +1,6 @@ #include "Router.h" #include "CryptoEngine.h" -#include "GPS.h" +#include "RTC.h" #include "configuration.h" #include "mesh-pb-constants.h" #include From 023f1c24fb8d3dd6c0326e837ee2c4ce421cb37a Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 8 Oct 2020 07:46:20 +0800 Subject: [PATCH 08/12] RTC: add notion of 'quality' for different time sources Allow use of mesh based time until a GPS time arrives --- docs/software/gps-todo.txt | 2 -- src/gps/GPS.cpp | 11 +++++------ src/gps/NMEAGPS.cpp | 2 +- src/gps/RTC.cpp | 23 ++++++++++++++--------- src/gps/RTC.h | 21 ++++++++++++++++----- src/gps/UBloxGPS.cpp | 2 +- src/mesh/MeshService.cpp | 10 +++------- 7 files changed, 40 insertions(+), 31 deletions(-) diff --git a/docs/software/gps-todo.txt b/docs/software/gps-todo.txt index 9612da31..5dc8c273 100644 --- a/docs/software/gps-todo.txt +++ b/docs/software/gps-todo.txt @@ -6,8 +6,6 @@ bin/run.sh --set region 8 time only mode ./bin/run.sh --set gps_operation 3 -set time provisionally from net even if we have gps - ublox parsing failure record power measurements and update spreadsheet diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index f39772d3..8e75e20f 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -1,10 +1,10 @@ #include "GPS.h" #include "NodeDB.h" +#include "RTC.h" #include "configuration.h" #include "sleep.h" #include -#include "RTC.h" // If we have a serial GPS port it will not be null #ifdef GPS_RX_PIN @@ -23,10 +23,8 @@ uint8_t GPS::i2cAddress = GPS_I2C_ADDRESS; uint8_t GPS::i2cAddress = 0; #endif - GPS *gps; - bool GPS::setup() { setAwake(true); // Wake GPS power before doing any init @@ -99,7 +97,8 @@ uint32_t GPS::getSleepTime() const uint32_t t = radioConfig.preferences.gps_update_interval; auto op = getGpsOp(); - if ((timeSetFromGPS && op == GpsOperation_GpsOpTimeOnly) || (op == GpsOperation_GpsOpDisabled)) + bool gotTime = (getRTCQuality() >= RTCQualityGPS); + if ((gotTime && op == GpsOperation_GpsOpTimeOnly) || (op == GpsOperation_GpsOpDisabled)) t = UINT32_MAX; // Sleep forever now if (t == UINT32_MAX) @@ -148,7 +147,7 @@ void GPS::loop() } // If we've already set time from the GPS, no need to ask the GPS - bool gotTime = timeSetFromGPS || lookForTime(); + bool gotTime = (getRTCQuality() >= RTCQualityGPS) || lookForTime(); bool gotLoc = lookForLocation(); // We've been awake too long - force sleep @@ -158,7 +157,7 @@ void GPS::loop() // Once we get a location we no longer desperately want an update // or if we got a time and we are in GpsOpTimeOnly mode // DEBUG_MSG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime); - if ((gotLoc && timeSetFromGPS) || tooLong || (gotTime && getGpsOp() == GpsOperation_GpsOpTimeOnly)) { + if ((gotLoc && gotTime) || tooLong || (gotTime && getGpsOp() == GpsOperation_GpsOpTimeOnly)) { if (gotLoc) hasValidLocation = true; diff --git a/src/gps/NMEAGPS.cpp b/src/gps/NMEAGPS.cpp index 41b1d476..50367469 100644 --- a/src/gps/NMEAGPS.cpp +++ b/src/gps/NMEAGPS.cpp @@ -45,7 +45,7 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s t.tm_mon = d.month() - 1; t.tm_year = d.year() - 1900; t.tm_isdst = false; - perhapsSetRTC(t); + perhapsSetRTC(RTCQualityGPS, t); return true; } else diff --git a/src/gps/RTC.cpp b/src/gps/RTC.cpp index de55ebdb..ff2e9afa 100644 --- a/src/gps/RTC.cpp +++ b/src/gps/RTC.cpp @@ -1,9 +1,14 @@ -#include "configuration.h" #include "RTC.h" +#include "configuration.h" #include #include -bool timeSetFromGPS; // We try to set our time from GPS each time we wake from sleep +static RTCQuality currentQuality = RTCQualityNone; + +RTCQuality getRTCQuality() +{ + return currentQuality; +} // stuff that really should be in in the instance instead... static uint32_t @@ -17,17 +22,17 @@ void readFromRTC() if (!gettimeofday(&tv, NULL)) { uint32_t now = millis(); - DEBUG_MSG("Read RTC time as %ld (cur millis %u) valid=%d\n", tv.tv_sec, now, timeSetFromGPS); + DEBUG_MSG("Read RTC time as %ld (cur millis %u) quality=%d\n", tv.tv_sec, now, currentQuality); timeStartMsec = now; zeroOffsetSecs = tv.tv_sec; } } /// If we haven't yet set our RTC this boot, set it from a GPS derived time -bool perhapsSetRTC(const struct timeval *tv) +bool perhapsSetRTC(RTCQuality q, const struct timeval *tv) { - if (!timeSetFromGPS) { - timeSetFromGPS = true; + if (q > currentQuality) { + currentQuality = q; DEBUG_MSG("Setting RTC %ld secs\n", tv->tv_sec); #ifndef NO_ESP32 settimeofday(tv, NULL); @@ -41,7 +46,7 @@ bool perhapsSetRTC(const struct timeval *tv) } } -bool perhapsSetRTC(struct tm &t) +bool perhapsSetRTC(RTCQuality q, 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 @@ -57,7 +62,7 @@ bool perhapsSetRTC(struct tm &t) // DEBUG_MSG("Ignoring invalid GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec); return false; } else { - return perhapsSetRTC(&tv); + return perhapsSetRTC(q, &tv); } } @@ -68,5 +73,5 @@ uint32_t getTime() uint32_t getValidTime() { - return timeSetFromGPS ? getTime() : 0; + return (currentQuality >= RTCQualityFromNet) ? getTime() : 0; } diff --git a/src/gps/RTC.h b/src/gps/RTC.h index 869de4b2..e17ca7a9 100644 --- a/src/gps/RTC.h +++ b/src/gps/RTC.h @@ -4,16 +4,27 @@ #include "sys/time.h" #include -extern bool timeSetFromGPS; // We try to set our time from GPS each time we wake from sleep +enum RTCQuality { + /// We haven't had our RTC set yet + RTCQualityNone = 0, + + /// Some other node gave us a time we can use + RTCQualityFromNet = 1, + + /// Our time is based on our own GPS + RTCQualityGPS = 2 +}; + +RTCQuality getRTCQuality(); /// If we haven't yet set our RTC this boot, set it from a GPS derived time -bool perhapsSetRTC(const struct timeval *tv); -bool perhapsSetRTC(struct tm &t); +bool perhapsSetRTC(RTCQuality q, const struct timeval *tv); +bool perhapsSetRTC(RTCQuality q, struct tm &t); -/// Return time since 1970 in secs. Until we have a GPS lock we will be returning time based at zero +/// Return time since 1970 in secs. While quality is RTCQualityNone we will be returning time based at zero uint32_t getTime(); -/// Return time since 1970 in secs. If we don't have a GPS lock return zero +/// Return time since 1970 in secs. If quality is RTCQualityNone return zero uint32_t getValidTime(); void readFromRTC(); \ No newline at end of file diff --git a/src/gps/UBloxGPS.cpp b/src/gps/UBloxGPS.cpp index 36541719..acbe0220 100644 --- a/src/gps/UBloxGPS.cpp +++ b/src/gps/UBloxGPS.cpp @@ -152,7 +152,7 @@ bool UBloxGPS::lookForTime() t.tm_mon = ublox.getMonth(0) - 1; t.tm_year = ublox.getYear(0) - 1900; t.tm_isdst = false; - perhapsSetRTC(t); + perhapsSetRTC(RTCQualityGPS, t); return true; } diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 5201fcd9..a3242327 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -140,7 +140,7 @@ void MeshService::handleIncomingPosition(const MeshPacket *mp) tv.tv_sec = secs; tv.tv_usec = 0; - perhapsSetRTC(&tv); + perhapsSetRTC(RTCQualityFromNet, &tv); } } else { DEBUG_MSG("Ignoring incoming packet - not a position\n"); @@ -151,12 +151,8 @@ int MeshService::handleFromRadio(const MeshPacket *mp) { powerFSM.trigger(EVENT_RECEIVED_PACKET); // Possibly keep the node from sleeping - // If it is a position packet, perhaps set our clock (if we don't have a GPS of our own, otherwise wait for that to work) - if (!gps->isConnected) - handleIncomingPosition(mp); - else { - DEBUG_MSG("Ignoring incoming time, because we have a GPS\n"); - } + // If it is a position packet, perhaps set our clock + handleIncomingPosition(mp); if (mp->which_payload == MeshPacket_decoded_tag && mp->decoded.which_payload == SubPacket_user_tag) { mp = handleFromRadioUser(mp); From e8b8ec69f137bddfed3479c026f1ee3977b9be55 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 8 Oct 2020 07:48:14 +0800 Subject: [PATCH 09/12] 1.1.2 --- bin/version.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/version.sh b/bin/version.sh index fb34ea22..75c088c9 100644 --- a/bin/version.sh +++ b/bin/version.sh @@ -1,3 +1,3 @@ -export VERSION=1.1.1 \ No newline at end of file +export VERSION=1.1.2 \ No newline at end of file From 113859e79191b9def46aba366985885f58115856 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 8 Oct 2020 09:57:59 +0800 Subject: [PATCH 10/12] increase sx1272 max power +#define MAX_POWER 27 // if we use 20 we are limited to 1% duty cycle or hw might overheat. For continuous operation set a limit of 17 +// In theory up to 27 dBm is possible, but the modules installed in most radios can cope with a max of 20. So BIG WARNING +// if you set power to something higher than 17 or 20 you might fry your board. --- src/mesh/RF95Interface.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp index babd9475..341c27e0 100644 --- a/src/mesh/RF95Interface.cpp +++ b/src/mesh/RF95Interface.cpp @@ -3,8 +3,10 @@ #include "RadioLibRF95.h" #include -#define MAX_POWER 20 +#define MAX_POWER 27 // if we use 20 we are limited to 1% duty cycle or hw might overheat. For continuous operation set a limit of 17 +// In theory up to 27 dBm is possible, but the modules installed in most radios can cope with a max of 20. So BIG WARNING +// if you set power to something higher than 17 or 20 you might fry your board. #define POWER_DEFAULT 17 // How much power to use if the user hasn't set a power level From 7a4b8cde111ff22e655e598230b11ebb7f3ee688 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 8 Oct 2020 10:51:31 +0800 Subject: [PATCH 11/12] keep rf95 max power at 20 dBm so users don't smoke their boards --- src/mesh/RF95Interface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp index 341c27e0..9410ad65 100644 --- a/src/mesh/RF95Interface.cpp +++ b/src/mesh/RF95Interface.cpp @@ -3,7 +3,7 @@ #include "RadioLibRF95.h" #include -#define MAX_POWER 27 +#define MAX_POWER 20 // if we use 20 we are limited to 1% duty cycle or hw might overheat. For continuous operation set a limit of 17 // In theory up to 27 dBm is possible, but the modules installed in most radios can cope with a max of 20. So BIG WARNING // if you set power to something higher than 17 or 20 you might fry your board. From 4a70ba1f7a1ac2e1aae74ed28daa3876b5442dba Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 9 Oct 2020 10:01:13 +0800 Subject: [PATCH 12/12] fix nodeinfo stored times (I think) for @lgoix --- src/gps/RTC.cpp | 4 ++-- src/gps/RTC.h | 2 +- src/mesh/MeshService.cpp | 9 +++++---- src/mesh/NodeDB.cpp | 6 +++--- src/mesh/Router.cpp | 5 ++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/gps/RTC.cpp b/src/gps/RTC.cpp index ff2e9afa..bc65dea1 100644 --- a/src/gps/RTC.cpp +++ b/src/gps/RTC.cpp @@ -71,7 +71,7 @@ uint32_t getTime() return ((millis() - timeStartMsec) / 1000) + zeroOffsetSecs; } -uint32_t getValidTime() +uint32_t getValidTime(RTCQuality minQuality) { - return (currentQuality >= RTCQualityFromNet) ? getTime() : 0; + return (currentQuality >= minQuality) ? getTime() : 0; } diff --git a/src/gps/RTC.h b/src/gps/RTC.h index e17ca7a9..d6e8703e 100644 --- a/src/gps/RTC.h +++ b/src/gps/RTC.h @@ -25,6 +25,6 @@ bool perhapsSetRTC(RTCQuality q, struct tm &t); uint32_t getTime(); /// Return time since 1970 in secs. If quality is RTCQualityNone return zero -uint32_t getValidTime(); +uint32_t getValidTime(RTCQuality minQuality); void readFromRTC(); \ No newline at end of file diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index a3242327..399d9690 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -151,7 +151,7 @@ int MeshService::handleFromRadio(const MeshPacket *mp) { powerFSM.trigger(EVENT_RECEIVED_PACKET); // Possibly keep the node from sleeping - // If it is a position packet, perhaps set our clock + // If it is a position packet, perhaps set our clock - this must be before nodeDB.updateFrom handleIncomingPosition(mp); if (mp->which_payload == MeshPacket_decoded_tag && mp->decoded.which_payload == SubPacket_user_tag) { @@ -226,7 +226,7 @@ void MeshService::handleToRadio(MeshPacket &p) if (p.id == 0) p.id = generatePacketId(); // If the phone didn't supply one, then pick one - p.rx_time = getValidTime(); // Record the time the packet arrived from the phone + p.rx_time = getValidTime(RTCQualityFromNet); // Record the time the packet arrived from the phone // (so we update our nodedb for the local node) // Send the packet into the mesh @@ -285,7 +285,7 @@ void MeshService::sendOurPosition(NodeNum dest, bool wantReplies) p->decoded.which_payload = SubPacket_position_tag; p->decoded.position = node->position; p->decoded.want_response = wantReplies; - p->decoded.position.time = getValidTime(); // This nodedb timestamp might be stale, so update it if our clock is valid. + p->decoded.position.time = getValidTime(RTCQualityGPS); // This nodedb timestamp might be stale, so update it if our clock is valid. sendToMesh(p); } @@ -303,9 +303,10 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused) pos.altitude = gps->altitude; pos.latitude_i = gps->latitude; pos.longitude_i = gps->longitude; - pos.time = getValidTime(); } + pos.time = getValidTime(RTCQualityGPS); + // Include our current battery voltage in our position announcement pos.battery_level = powerStatus->getBatteryChargePercent(); updateBatteryLevel(pos.battery_level); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 1224ae6d..613665dc 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -415,10 +415,10 @@ void NodeDB::updateFrom(const MeshPacket &mp) switch (p.which_payload) { case SubPacket_position_tag: { - // we carefully preserve the old time, because we always trust our local timestamps more - uint32_t oldtime = info->position.time; + // we always trust our local timestamps more info->position = p.position; - info->position.time = oldtime; + if (mp.rx_time) + info->position.time = mp.rx_time; info->has_position = true; updateGUIforNode = info; notifyObservers(true); // Force an update whether or not our node counts have changed diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 6a338200..e352a5b2 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -89,7 +89,7 @@ MeshPacket *Router::allocForSending() p->to = NODENUM_BROADCAST; p->hop_limit = HOP_RELIABLE; p->id = generatePacketId(); - p->rx_time = getValidTime(); // Just in case we process the packet locally - make sure it has a valid timestamp + p->rx_time = getValidTime(RTCQualityFromNet); // Just in case we process the packet locally - make sure it has a valid timestamp return p; } @@ -198,9 +198,8 @@ NodeNum Router::getNodeNum() */ void Router::handleReceived(MeshPacket *p) { - // FIXME, this class shouldn't EVER need to know about the GPS, move getValidTime() into a non gps dependent function // Also, we should set the time from the ISR and it should have msec level resolution - p->rx_time = getValidTime(); // store the arrival timestamp for the phone + p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone // Take those raw bytes and convert them back into a well structured protobuf we can understand if (perhapsDecode(p)) {