From 911083c49d8ee58dec810dd74ff2f0cf045af381 Mon Sep 17 00:00:00 2001 From: code8buster Date: Sun, 4 Dec 2022 01:57:00 -0500 Subject: [PATCH 1/6] Adds a flag to turn the GPS power rail off entirely on tbeam --- src/ButtonThread.h | 17 +++++++++++++++-- src/gps/GPS.cpp | 1 - src/gps/GPS.h | 4 +++- src/sleep.cpp | 16 ++++++++++++++++ src/sleep.h | 2 +- variants/tbeam/platformio.ini | 1 + 6 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/ButtonThread.h b/src/ButtonThread.h index 088642099..23859b8ad 100644 --- a/src/ButtonThread.h +++ b/src/ButtonThread.h @@ -5,6 +5,7 @@ #include "configuration.h" #include "graphics/Screen.h" #include "power.h" +#include "GPS.h" #include namespace concurrency @@ -159,9 +160,21 @@ class ButtonThread : public concurrency::OSThread static void userButtonDoublePressed() { -#if defined(USE_EINK) && defined(PIN_EINK_EN) + #if defined(USE_EINK) && defined(PIN_EINK_EN) digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW); -#endif + #endif + #if defined(GPS_POWER_TOGGLE) + if(gps->gpsPowerflag) + { + DEBUG_MSG("Flag set to false for gps power\n"); + } + else + { + DEBUG_MSG("Flag set to true to restore power\n"); + } + gps->gpsPowerflag = !(gps->gpsPowerflag); + doGPSpowersave(gps->gpsPowerflag); + #endif } static void userButtonMultiPressed() diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 54dc59cbb..2a00af475 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -276,7 +276,6 @@ bool GPS::setup() delay(10); digitalWrite(PIN_GPS_RESET, 0); #endif - setAwake(true); // Wake GPS power before doing any init bool ok = setupGPS(); diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 8f04b6793..c9f0ff41b 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -77,6 +77,8 @@ class GPS : private concurrency::OSThread /// Return true if we are connected to a GPS bool isConnected() const { return hasGPS; } + bool gpsPowerflag; + /** * Restart our lock attempt - try to get and broadcast a GPS reading ASAP * called after the CPU wakes from light-sleep state @@ -128,7 +130,6 @@ class GPS : private concurrency::OSThread void setNumSatellites(uint8_t n); - private: /// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs /// always returns 0 to indicate okay to sleep int prepareSleep(void *unused); @@ -136,6 +137,7 @@ class GPS : private concurrency::OSThread /// Prepare the GPS for the cpu entering deep sleep, expect to be gone for at least 100s of msecs /// always returns 0 to indicate okay to sleep int prepareDeepSleep(void *unused); + private: /** * Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode diff --git a/src/sleep.cpp b/src/sleep.cpp index 39ee43ebc..7f6735939 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -167,6 +167,22 @@ static void waitEnterSleep() notifySleep.notifyObservers(NULL); } +void doGPSpowersave(bool on) +{ + if (on) + { + DEBUG_MSG("Turning GPS back on\n"); + gps->forceWake(1); + setGPSPower(1); + } + else + { + DEBUG_MSG("Turning off GPS chip\n"); + notifySleep.notifyObservers(NULL); + setGPSPower(0); + } +} + void doDeepSleep(uint64_t msecToWake) { DEBUG_MSG("Entering deep sleep for %lu seconds\n", msecToWake / 1000); diff --git a/src/sleep.h b/src/sleep.h index 7f0592af4..f911a7cc8 100644 --- a/src/sleep.h +++ b/src/sleep.h @@ -13,7 +13,7 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t msecToWake); extern esp_sleep_source_t wakeCause; #endif void setGPSPower(bool on); - +void doGPSpowersave(bool on); // Perform power on init that we do on each wake from deep sleep void initDeepSleep(); diff --git a/variants/tbeam/platformio.ini b/variants/tbeam/platformio.ini index 578a74f7b..df526ae5b 100644 --- a/variants/tbeam/platformio.ini +++ b/variants/tbeam/platformio.ini @@ -6,4 +6,5 @@ lib_deps = ${esp32_base.lib_deps} build_flags = ${esp32_base.build_flags} -D TBEAM_V10 -I variants/tbeam + ;-DGPS_POWER_TOGGLE ;uncomment this line to allow a double press on the user button to turn off gps entirely. upload_speed = 921600 From 53da7cb0361a7bc7b165c7ce735dbfef3328b6b3 Mon Sep 17 00:00:00 2001 From: code8buster Date: Sun, 4 Dec 2022 02:38:14 -0500 Subject: [PATCH 2/6] Add initialized value to constructor --- src/gps/GPS.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gps/GPS.h b/src/gps/GPS.h index c9f0ff41b..f77d13a80 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -77,7 +77,7 @@ class GPS : private concurrency::OSThread /// Return true if we are connected to a GPS bool isConnected() const { return hasGPS; } - bool gpsPowerflag; + bool gpsPowerflag = 1; /** * Restart our lock attempt - try to get and broadcast a GPS reading ASAP From 8507125e986f595f12e4ab8840fe31b30533bf23 Mon Sep 17 00:00:00 2001 From: code8buster Date: Tue, 13 Dec 2022 17:23:58 -0500 Subject: [PATCH 3/6] Remove extraneous flag, use gps_enabled. Ensure factory reset is not triggered while chip is off and gps_enabled=0 --- src/ButtonThread.h | 7 +++---- src/GPSStatus.h | 9 +++++++-- src/gps/GPS.cpp | 23 ++++++++++++++++++++--- src/gps/GPS.h | 3 ++- src/sleep.cpp | 6 +++++- src/sleep.h | 2 ++ 6 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/ButtonThread.h b/src/ButtonThread.h index 23859b8ad..985f0352b 100644 --- a/src/ButtonThread.h +++ b/src/ButtonThread.h @@ -5,7 +5,6 @@ #include "configuration.h" #include "graphics/Screen.h" #include "power.h" -#include "GPS.h" #include namespace concurrency @@ -164,7 +163,7 @@ class ButtonThread : public concurrency::OSThread digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW); #endif #if defined(GPS_POWER_TOGGLE) - if(gps->gpsPowerflag) + if(config.position.gps_enabled) { DEBUG_MSG("Flag set to false for gps power\n"); } @@ -172,8 +171,8 @@ class ButtonThread : public concurrency::OSThread { DEBUG_MSG("Flag set to true to restore power\n"); } - gps->gpsPowerflag = !(gps->gpsPowerflag); - doGPSpowersave(gps->gpsPowerflag); + config.position.gps_enabled = !(config.position.gps_enabled); + doGPSpowersave(config.position.gps_enabled); #endif } diff --git a/src/GPSStatus.h b/src/GPSStatus.h index 35a0b11f2..ef97c59b7 100644 --- a/src/GPSStatus.h +++ b/src/GPSStatus.h @@ -20,16 +20,19 @@ class GPSStatus : public Status bool hasLock = false; // default to false, until we complete our first read bool isConnected = false; // Do we have a GPS we are talking to + bool isPowerSaving = false; //Are we in power saving state + Position p = Position_init_default; public: GPSStatus() { statusType = STATUS_TYPE_GPS; } // preferred method - GPSStatus(bool hasLock, bool isConnected, const Position &pos) : Status() + GPSStatus(bool hasLock, bool isConnected, bool isPowerSaving, const Position &pos) : Status() { this->hasLock = hasLock; this->isConnected = isConnected; + this->isPowerSaving = isPowerSaving; // all-in-one struct copy this->p = pos; @@ -44,6 +47,8 @@ class GPSStatus : public Status bool getIsConnected() const { return isConnected; } + bool getIsPowerSaving() const { return isPowerSaving;} + int32_t getLatitude() const { if (config.position.fixed_position) { @@ -94,7 +99,7 @@ class GPSStatus : public Status #ifdef GPS_EXTRAVERBOSE DEBUG_MSG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.pos_timestamp, p.pos_timestamp); #endif - return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected || + return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected || newStatus->isPowerSaving !=isPowerSaving || newStatus->p.latitude_i != p.latitude_i || newStatus->p.longitude_i != p.longitude_i || newStatus->p.altitude != p.altitude || newStatus->p.altitude_hae != p.altitude_hae || newStatus->p.PDOP != p.PDOP || newStatus->p.ground_track != p.ground_track || diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 2a00af475..7e860cdd0 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -270,6 +270,12 @@ bool GPS::setup() pinMode(PIN_GPS_EN, OUTPUT); #endif +#ifdef HAS_PMU +if(config.position.gps_enabled){ + setGPSPower(true); +} +#endif + #ifdef PIN_GPS_RESET digitalWrite(PIN_GPS_RESET, 1); // assert for 10ms pinMode(PIN_GPS_RESET, OUTPUT); @@ -282,8 +288,12 @@ bool GPS::setup() if (ok) { notifySleepObserver.observe(¬ifySleep); notifyDeepSleepObserver.observe(¬ifyDeepSleep); + notifyGPSSleepObserver.observe(¬ifyGPSSleep); + } + if (config.position.gps_enabled==false) { + setAwake(false); + doGPSpowersave(false); } - return ok; } @@ -292,6 +302,7 @@ GPS::~GPS() // we really should unregister our sleep observer notifySleepObserver.unobserve(¬ifySleep); notifyDeepSleepObserver.unobserve(¬ifyDeepSleep); + notifyGPSSleepObserver.observe(¬ifyGPSSleep); } bool GPS::hasLock() @@ -404,7 +415,7 @@ void GPS::publishUpdate() DEBUG_MSG("publishing pos@%x:2, hasVal=%d, GPSlock=%d\n", p.timestamp, hasValidLocation, hasLock()); // Notify any status instances that are observing us - const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasValidLocation, isConnected(), p); + const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasValidLocation, isConnected(), isPowerSaving(), p); newStatus.notifyObservers(&status); } } @@ -415,7 +426,7 @@ int32_t GPS::runOnce() // if we have received valid NMEA claim we are connected setConnected(); } else { - if(gnssModel == GNSS_MODEL_UBLOX){ + if((config.position.gps_enabled == 1) && (gnssModel == GNSS_MODEL_UBLOX)){ // reset the GPS on next bootup if(devicestate.did_gps_reset && (millis() > 60000) && !hasFlow()) { DEBUG_MSG("GPS is not communicating, trying factory reset on next bootup.\n"); @@ -517,6 +528,7 @@ int GPS::prepareDeepSleep(void *unused) DEBUG_MSG("GPS deep sleep!\n"); // For deep sleep we also want abandon any lock attempts (because we want minimum power) + getSleepTime(); setAwake(false); return 0; @@ -652,6 +664,11 @@ GPS *createGps() return new_gps; } } + else{ + GPS *new_gps = new NMEAGPS(); + new_gps->setup(); + return new_gps; + } return nullptr; #endif } diff --git a/src/gps/GPS.h b/src/gps/GPS.h index f77d13a80..a8a82a033 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -49,6 +49,7 @@ class GPS : private concurrency::OSThread CallbackObserver notifySleepObserver = CallbackObserver(this, &GPS::prepareSleep); CallbackObserver notifyDeepSleepObserver = CallbackObserver(this, &GPS::prepareDeepSleep); + CallbackObserver notifyGPSSleepObserver = CallbackObserver(this, &GPS::prepareDeepSleep); public: /** If !NULL we will use this serial port to construct our GPS */ @@ -77,7 +78,7 @@ class GPS : private concurrency::OSThread /// Return true if we are connected to a GPS bool isConnected() const { return hasGPS; } - bool gpsPowerflag = 1; + bool isPowerSaving() const { return !config.position.gps_enabled;} /** * Restart our lock attempt - try to get and broadcast a GPS reading ASAP diff --git a/src/sleep.cpp b/src/sleep.cpp index 7f6735939..46d14d623 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -29,7 +29,9 @@ Observable preflightSleep; /// Called to tell observers we are now entering sleep and you should prepare. Must return 0 /// notifySleep will be called for light or deep sleep, notifyDeepSleep is only called for deep sleep +/// notifyGPSSleep will be called when config.position.gps_enabled is set to 0 or from buttonthread when GPS_POWER_TOGGLE is enabled. Observable notifySleep, notifyDeepSleep; +Observable notifyGPSSleep; // deep sleep support RTC_DATA_ATTR int bootCount = 0; @@ -169,6 +171,7 @@ static void waitEnterSleep() void doGPSpowersave(bool on) { + #ifdef HAS_PMU if (on) { DEBUG_MSG("Turning GPS back on\n"); @@ -178,9 +181,10 @@ void doGPSpowersave(bool on) else { DEBUG_MSG("Turning off GPS chip\n"); - notifySleep.notifyObservers(NULL); + notifyGPSSleep.notifyObservers(NULL); setGPSPower(0); } + #endif } void doDeepSleep(uint64_t msecToWake) diff --git a/src/sleep.h b/src/sleep.h index f911a7cc8..af59a8dad 100644 --- a/src/sleep.h +++ b/src/sleep.h @@ -37,4 +37,6 @@ extern Observable notifySleep; /// Called to tell observers we are now entering (deep) sleep and you should prepare. Must return 0 extern Observable notifyDeepSleep; +/// Called to tell GPS thread to enter deep sleep independently of LoRa/MCU sleep, prior to full poweroff. Must return 0 +extern Observable notifyGPSSleep; void enableModemSleep(); \ No newline at end of file From 06be74ae7c99c1ec33a2da61ade737b0632e64e5 Mon Sep 17 00:00:00 2001 From: code8buster Date: Wed, 14 Dec 2022 19:58:15 -0500 Subject: [PATCH 4/6] Added indicative text to screen for disabled GPS, made sleep methods private again --- src/gps/GPS.h | 2 +- src/graphics/Screen.cpp | 30 ++++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/gps/GPS.h b/src/gps/GPS.h index a8a82a033..5d24268d7 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -131,6 +131,7 @@ class GPS : private concurrency::OSThread void setNumSatellites(uint8_t n); + private: /// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs /// always returns 0 to indicate okay to sleep int prepareSleep(void *unused); @@ -138,7 +139,6 @@ class GPS : private concurrency::OSThread /// Prepare the GPS for the cpu entering deep sleep, expect to be gone for at least 100s of msecs /// always returns 0 to indicate okay to sleep int prepareDeepSleep(void *unused); - private: /** * Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index eac78dd64..81ed10444 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -506,6 +506,22 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus } } +//Draw status when gps is disabled by PMU +static void drawGPSpowerstat(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps){ +String displayLine = ""; +displayLine = "GPS disabled"; +int16_t xPos = display->getStringWidth(displayLine); + #ifdef HAS_PMU + if (!config.position.gps_enabled){ + display->drawString(x + xPos, y, displayLine); + #ifdef GPS_POWER_TOGGLE + display->drawString(x + xPos, y - 2 + FONT_HEIGHT_SMALL, " by button"); + #endif + //display->drawString(x + xPos, y + 2, displayLine); + } + #endif +} + static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps) { String displayLine = ""; @@ -1372,7 +1388,15 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 // Display nodes status drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus); // Display GPS status + if (!config.position.gps_enabled){ + int16_t yPos = y + 2; + #ifdef GPS_POWER_TOGGLE + yPos = (y + 10 + FONT_HEIGHT_SMALL); + #endif + drawGPSpowerstat(display, x, yPos, gpsStatus); + } else { drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus); + } // Draw the channel name display->drawString(x, y + FONT_HEIGHT_SMALL, channelStr); @@ -1613,7 +1637,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat char chUtil[13]; sprintf(chUtil, "ChUtil %2.0f%%", airTime->channelUtilizationPercent()); display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), y + FONT_HEIGHT_SMALL * 1, chUtil); - +if (config.position.gps_enabled) { // Line 3 if (config.display.gps_format != Config_DisplayConfig_GpsCoordinateFormat_DMS) // if DMS then don't draw altitude @@ -1621,7 +1645,9 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat // Line 4 drawGPScoordinates(display, x, y + FONT_HEIGHT_SMALL * 3, gpsStatus); - +} else { + drawGPSpowerstat(display, x - (SCREEN_WIDTH / 4), y + FONT_HEIGHT_SMALL * 2, gpsStatus); +} /* Display a heartbeat pixel that blinks every time the frame is redrawn */ #ifdef SHOW_REDRAWS if (heartbeat) From f2229e6977315f01fc98c09febd30e9c54aa8706 Mon Sep 17 00:00:00 2001 From: code8buster Date: Thu, 15 Dec 2022 11:08:37 -0500 Subject: [PATCH 5/6] Decrease click time window to avoid spurious double press detections while cycling windows quickly, build power toggle by default --- src/ButtonThread.h | 1 + variants/tbeam/platformio.ini | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ButtonThread.h b/src/ButtonThread.h index 985f0352b..0e9830f3f 100644 --- a/src/ButtonThread.h +++ b/src/ButtonThread.h @@ -51,6 +51,7 @@ class ButtonThread : public concurrency::OSThread pinMode(BUTTON_PIN, INPUT_PULLUP_SENSE); #endif userButton.attachClick(userButtonPressed); + userButton.setClickTicks(300); userButton.attachDuringLongPress(userButtonPressedLong); userButton.attachDoubleClick(userButtonDoublePressed); userButton.attachMultiClick(userButtonMultiPressed); diff --git a/variants/tbeam/platformio.ini b/variants/tbeam/platformio.ini index df526ae5b..76a03d126 100644 --- a/variants/tbeam/platformio.ini +++ b/variants/tbeam/platformio.ini @@ -6,5 +6,5 @@ lib_deps = ${esp32_base.lib_deps} build_flags = ${esp32_base.build_flags} -D TBEAM_V10 -I variants/tbeam - ;-DGPS_POWER_TOGGLE ;uncomment this line to allow a double press on the user button to turn off gps entirely. + -DGPS_POWER_TOGGLE ; comment this line to disable double press function on the user button to turn off gps entirely. upload_speed = 921600 From a788f16e91da9281ff8b3705fd3947babcdcd4ff Mon Sep 17 00:00:00 2001 From: code8buster Date: Thu, 15 Dec 2022 12:02:04 -0500 Subject: [PATCH 6/6] Potentially stop bad things happening on devices without a PMU --- src/sleep.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sleep.cpp b/src/sleep.cpp index 46d14d623..72b7f7527 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -185,6 +185,18 @@ void doGPSpowersave(bool on) setGPSPower(0); } #endif + #ifdef PIN_GPS_WAKE + if (on) + { + DEBUG_MSG("Waking GPS"); + gps->forceWake(1); + } + else + { + DEBUG_MSG("GPS entering sleep"); + notifyGPSSleep.notifyObservers(NULL); + } + #endif } void doDeepSleep(uint64_t msecToWake)