diff --git a/src/ButtonThread.h b/src/ButtonThread.h index dff871f1f..f9131c84a 100644 --- a/src/ButtonThread.h +++ b/src/ButtonThread.h @@ -52,6 +52,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); @@ -164,9 +165,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(config.position.gps_enabled) + { + DEBUG_MSG("Flag set to false for gps power\n"); + } + else + { + DEBUG_MSG("Flag set to true to restore power\n"); + } + config.position.gps_enabled = !(config.position.gps_enabled); + doGPSpowersave(config.position.gps_enabled); + #endif } static void userButtonMultiPressed() 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 54dc59cbb..7e860cdd0 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -270,21 +270,30 @@ 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); delay(10); digitalWrite(PIN_GPS_RESET, 0); #endif - setAwake(true); // Wake GPS power before doing any init bool ok = setupGPS(); if (ok) { notifySleepObserver.observe(¬ifySleep); notifyDeepSleepObserver.observe(¬ifyDeepSleep); + notifyGPSSleepObserver.observe(¬ifyGPSSleep); + } + if (config.position.gps_enabled==false) { + setAwake(false); + doGPSpowersave(false); } - return ok; } @@ -293,6 +302,7 @@ GPS::~GPS() // we really should unregister our sleep observer notifySleepObserver.unobserve(¬ifySleep); notifyDeepSleepObserver.unobserve(¬ifyDeepSleep); + notifyGPSSleepObserver.observe(¬ifyGPSSleep); } bool GPS::hasLock() @@ -405,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); } } @@ -416,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"); @@ -518,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; @@ -653,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 8f04b6793..5d24268d7 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,6 +78,8 @@ class GPS : private concurrency::OSThread /// Return true if we are connected to a GPS bool isConnected() const { return hasGPS; } + bool isPowerSaving() const { return !config.position.gps_enabled;} + /** * Restart our lock attempt - try to get and broadcast a GPS reading ASAP * called after the CPU wakes from light-sleep state diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index f1c3fdccc..3ea4463ea 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -512,6 +512,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 = ""; @@ -1384,7 +1400,16 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 // Display nodes status drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 3, nodeStatus); // Display GPS status - drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 3, gpsStatus); + 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); + drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 3, gpsStatus); + } display->setColor(WHITE); // Draw the channel name @@ -1643,7 +1668,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 @@ -1651,7 +1676,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) diff --git a/src/sleep.cpp b/src/sleep.cpp index 6625da2a3..40426a777 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; @@ -167,6 +169,36 @@ static void waitEnterSleep() notifySleep.notifyObservers(NULL); } +void doGPSpowersave(bool on) +{ + #ifdef HAS_PMU + if (on) + { + DEBUG_MSG("Turning GPS back on\n"); + gps->forceWake(1); + setGPSPower(1); + } + else + { + DEBUG_MSG("Turning off GPS chip\n"); + notifyGPSSleep.notifyObservers(NULL); + 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) { DEBUG_MSG("Entering deep sleep for %lu seconds\n", msecToWake / 1000); diff --git a/src/sleep.h b/src/sleep.h index 7f0592af4..af59a8dad 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(); @@ -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 diff --git a/variants/tbeam/platformio.ini b/variants/tbeam/platformio.ini index 578a74f7b..76a03d126 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 ; comment this line to disable double press function on the user button to turn off gps entirely. upload_speed = 921600