From e9215a5d705ef4e24c7bd28e53eb12c96140d32a Mon Sep 17 00:00:00 2001 From: Manuel <71137295+mverch67@users.noreply.github.com> Date: Sat, 30 Sep 2023 13:43:36 +0200 Subject: [PATCH 01/23] revert KB_POWERON changes (#2847) --- src/PowerFSM.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index eceb545fe..e6a2836bb 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -154,9 +154,6 @@ static void darkEnter() { setBluetoothEnable(true); screen->setOn(false); -#ifdef KB_POWERON - digitalWrite(KB_POWERON, LOW); -#endif } static void serialEnter() @@ -184,9 +181,6 @@ static void powerEnter() } else { screen->setOn(true); setBluetoothEnable(true); -#ifdef KB_POWERON - digitalWrite(KB_POWERON, HIGH); -#endif // within enter() the function getState() returns the state we came from if (strcmp(powerFSM.getState()->name, "BOOT") != 0 && strcmp(powerFSM.getState()->name, "POWER") != 0 && strcmp(powerFSM.getState()->name, "DARK") != 0) { @@ -217,9 +211,6 @@ static void onEnter() LOG_DEBUG("Enter state: ON\n"); screen->setOn(true); setBluetoothEnable(true); -#ifdef KB_POWERON - digitalWrite(KB_POWERON, HIGH); -#endif } static void onIdle() From 6ebec8fcd9aac91ee7efd240cb5cbe7b9321b1d3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 30 Sep 2023 20:40:04 -0500 Subject: [PATCH 02/23] [create-pull-request] automated change (#2849) Co-authored-by: thebentern --- protobufs | 2 +- src/mesh/generated/meshtastic/config.pb.h | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/protobufs b/protobufs index fb28d5935..0fb2f8471 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit fb28d593526467977cf353959a66e11373928282 +Subproject commit 0fb2f847141006c36d7e9d5118766f3a5da4225a diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 4b8bef8a1..2a811140f 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -30,10 +30,14 @@ typedef enum _meshtastic_Config_DeviceConfig_Role { or any other packet type. They will simply rebroadcast any mesh packets on the same frequency, channel num, spread factor, and coding rate. */ meshtastic_Config_DeviceConfig_Role_REPEATER = 4, /* Tracker device role - Position Mesh packets will be prioritized higher and sent more frequently by default. */ + Position Mesh packets will be prioritized higher and sent more frequently by default. + When used in conjunction with power.is_power_saving = true, nodes will wake up, + send position, and then sleep for position.position_broadcast_secs seconds. */ meshtastic_Config_DeviceConfig_Role_TRACKER = 5, /* Sensor device role - Telemetry Mesh packets will be prioritized higher and sent more frequently by default. */ + Telemetry Mesh packets will be prioritized higher and sent more frequently by default. + When used in conjunction with power.is_power_saving = true, nodes will wake up, + send environment telemetry, and then sleep for telemetry.environment_update_interval seconds. */ meshtastic_Config_DeviceConfig_Role_SENSOR = 6 } meshtastic_Config_DeviceConfig_Role; From 1552aa008167384ab3eb06bf486154a326074350 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 30 Sep 2023 21:09:17 -0500 Subject: [PATCH 03/23] Tracker role wakeup and sleep cycle when power.is_power_saving true (#2846) * WIP * Sleepy sleepy low power tracker * Sleepy tracker clear * NRF52 PoC * Simplify NRF52 "sleep" * Trackers aren't polite * Remove unnecessary include * Removed accidental commit * Fixed not-so-sleepy T-Beam due to button gpio mask precendence * Added sleepOnNextExecution for allowing fulfillment of pending messages before shutting down * Cleanup * Don't wantResponse for trackers * Heltec wireless tracker doesn't like the button interrupt (maybe all s3 because user button press doubles as bootloader mode trigger?) --- src/Power.cpp | 2 +- src/PowerFSM.cpp | 2 +- src/concurrency/OSThread.h | 1 + src/modules/PositionModule.cpp | 38 +++++++++++++++++++++++++++---- src/modules/PositionModule.h | 5 +++- src/platform/esp32/main-esp32.cpp | 13 +++-------- src/platform/nrf52/main-nrf52.cpp | 14 ++++++++---- src/sleep.cpp | 24 ++++++++++--------- src/sleep.h | 2 +- 9 files changed, 68 insertions(+), 33 deletions(-) diff --git a/src/Power.cpp b/src/Power.cpp index 460f598b3..57d6513a7 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -414,7 +414,7 @@ void Power::shutdown() #ifdef PIN_LED3 ledOff(PIN_LED2); #endif - doDeepSleep(DELAY_FOREVER); + doDeepSleep(DELAY_FOREVER, false); #endif } diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index e6a2836bb..b8c70292c 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -45,7 +45,7 @@ static void sdsEnter() { LOG_DEBUG("Enter state: SDS\n"); // FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw - doDeepSleep(getConfiguredOrDefaultMs(config.power.sds_secs)); + doDeepSleep(getConfiguredOrDefaultMs(config.power.sds_secs), false); } extern Power *power; diff --git a/src/concurrency/OSThread.h b/src/concurrency/OSThread.h index 7957ee952..0fbfe2e17 100644 --- a/src/concurrency/OSThread.h +++ b/src/concurrency/OSThread.h @@ -67,6 +67,7 @@ class OSThread : public Thread * Returns desired period for next invocation (or RUN_SAME for no change) */ virtual int32_t runOnce() = 0; + bool sleepOnNextExecution = false; // Do not override this virtual void run(); diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index 39e467cda..29ddde4ce 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -1,4 +1,5 @@ #include "PositionModule.h" +#include "GPS.h" #include "MeshService.h" #include "NodeDB.h" #include "RTC.h" @@ -7,6 +8,8 @@ #include "airtime.h" #include "configuration.h" #include "gps/GeoCoord.h" +#include "sleep.h" +#include "target_specific.h" PositionModule *positionModule; @@ -14,8 +17,22 @@ PositionModule::PositionModule() : ProtobufModule("position", meshtastic_PortNum_POSITION_APP, &meshtastic_Position_msg), concurrency::OSThread("PositionModule") { - isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others - setIntervalFromNow(60 * 1000); // Send our initial position 60 seconds after we start (to give GPS time to setup) + isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others + if (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER) + setIntervalFromNow(60 * 1000); + + // Power saving trackers should clear their position on startup to avoid waking up and sending a stale position + if (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER && config.power.is_power_saving) { + clearPosition(); + } +} + +void PositionModule::clearPosition() +{ + LOG_DEBUG("Clearing position on startup for sleepy tracker (ー。ー) zzz\n"); + meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum()); + node->position.latitude_i = 0; + node->position.longitude_i = 0; } bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Position *pptr) @@ -148,7 +165,7 @@ void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t cha } p->to = dest; - p->decoded.want_response = wantReplies; + p->decoded.want_response = config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER ? false : wantReplies; if (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER) p->priority = meshtastic_MeshPacket_Priority_RELIABLE; else @@ -159,10 +176,23 @@ void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t cha p->channel = channel; service.sendToMesh(p, RX_SRC_LOCAL, true); + + if (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER && config.power.is_power_saving) { + LOG_DEBUG("Starting next execution in 3 seconds and then going to sleep.\n"); + sleepOnNextExecution = true; + setIntervalFromNow(3000); + } } int32_t PositionModule::runOnce() { + if (sleepOnNextExecution == true) { + sleepOnNextExecution = false; + uint32_t nightyNightMs = getConfiguredOrDefaultMs(config.position.position_broadcast_secs); + LOG_DEBUG("Sleeping for %ims, then awaking to send position again.\n", nightyNightMs); + doDeepSleep(nightyNightMs, false); + } + meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum()); // We limit our GPS broadcasts to a max rate @@ -172,7 +202,7 @@ int32_t PositionModule::runOnce() if (lastGpsSend == 0 || msSinceLastSend >= intervalMs) { // Only send packets if the channel is less than 40% utilized. - if (airTime->isTxAllowedChannelUtil()) { + if (airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER)) { if (hasValidPosition(node)) { lastGpsSend = now; diff --git a/src/modules/PositionModule.h b/src/modules/PositionModule.h index 3114f31e1..1b7eca800 100644 --- a/src/modules/PositionModule.h +++ b/src/modules/PositionModule.h @@ -49,6 +49,9 @@ class PositionModule : public ProtobufModule, private concu private: struct SmartPosition getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition); + + /** Only used in power saving trackers for now */ + void clearPosition(); }; struct SmartPosition { @@ -57,4 +60,4 @@ struct SmartPosition { bool hasTraveledOverThreshold; }; -extern PositionModule *positionModule; +extern PositionModule *positionModule; \ No newline at end of file diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp index 17a312664..d9bc57b02 100644 --- a/src/platform/esp32/main-esp32.cpp +++ b/src/platform/esp32/main-esp32.cpp @@ -200,22 +200,15 @@ void cpuDeepSleep(uint32_t msecToWake) esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); #ifdef BUTTON_PIN - // Only GPIOs which are have RTC functionality can be used in this bit map: 0,2,4,12-15,25-27,32-39. -#if SOC_RTCIO_HOLD_SUPPORTED - uint64_t gpioMask = (1ULL << config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN); + +#if SOC_PM_SUPPORT_EXT_WAKEUP && !defined(HELTEC_WIRELESS_TRACKER) + esp_sleep_enable_ext0_wakeup((gpio_num_t)(1ULL << (config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN)), LOW); #endif #ifdef BUTTON_NEED_PULLUP gpio_pullup_en((gpio_num_t)BUTTON_PIN); #endif - // Not needed because both of the current boards have external pullups - // FIXME change polarity in hw so we can wake on ANY_HIGH instead - that would allow us to use all three buttons (instead of - // just the first) gpio_pullup_en((gpio_num_t)BUTTON_PIN); - -#if SOC_PM_SUPPORT_EXT_WAKEUP - esp_sleep_enable_ext1_wakeup(gpioMask, ESP_EXT1_WAKEUP_ALL_LOW); -#endif #endif esp_sleep_enable_timer_wakeup(msecToWake * 1000ULL); // call expects usecs diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index fd6fe2cc2..6b986c778 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -184,10 +184,16 @@ void cpuDeepSleep(uint32_t msecToWake) // FIXME, use non-init RAM per // https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled - auto ok = sd_power_system_off(); - if (ok != NRF_SUCCESS) { - LOG_ERROR("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!\n"); - NRF_POWER->SYSTEMOFF = 1; + if (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER && config.power.is_power_saving == true) { + sd_power_mode_set(NRF_POWER_MODE_LOWPWR); + delay(msecToWake); + NVIC_SystemReset(); + } else { + auto ok = sd_power_system_off(); + if (ok != NRF_SUCCESS) { + LOG_ERROR("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!\n"); + NRF_POWER->SYSTEMOFF = 1; + } } // The following code should not be run, because we are off diff --git a/src/sleep.cpp b/src/sleep.cpp index 62ce0064f..d9fb1ba50 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -135,16 +135,18 @@ bool doPreflightSleep() } /// Tell devices we are going to sleep and wait for them to handle things -static void waitEnterSleep() +static void waitEnterSleep(bool skipPreflight = false) { - uint32_t now = millis(); - while (!doPreflightSleep()) { - delay(100); // Kinda yucky - wait until radio says say we can shutdown (finished in process sends/receives) + if (!skipPreflight) { + uint32_t now = millis(); + while (!doPreflightSleep()) { + delay(100); // Kinda yucky - wait until radio says say we can shutdown (finished in process sends/receives) - if (millis() - now > 30 * 1000) { // If we wait too long just report an error and go to sleep - RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_SLEEP_ENTER_WAIT); - assert(0); // FIXME - for now we just restart, need to fix bug #167 - break; + if (millis() - now > 30 * 1000) { // If we wait too long just report an error and go to sleep + RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_SLEEP_ENTER_WAIT); + assert(0); // FIXME - for now we just restart, need to fix bug #167 + break; + } } } @@ -155,7 +157,7 @@ static void waitEnterSleep() notifySleep.notifyObservers(NULL); } -void doDeepSleep(uint32_t msecToWake) +void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) { if (INCLUDE_vTaskSuspend && (msecToWake == portMAX_DELAY)) { LOG_INFO("Entering deep sleep forever\n"); @@ -165,7 +167,7 @@ void doDeepSleep(uint32_t msecToWake) // not using wifi yet, but once we are this is needed to shutoff the radio hw // esp_wifi_stop(); - waitEnterSleep(); + waitEnterSleep(skipPreflight); notifyDeepSleep.notifyObservers(NULL); screen->doDeepSleep(); // datasheet says this will draw only 10ua @@ -227,7 +229,7 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r { // LOG_DEBUG("Enter light sleep\n"); - waitEnterSleep(); + waitEnterSleep(false); uint64_t sleepUsec = sleepMsec * 1000LL; diff --git a/src/sleep.h b/src/sleep.h index 8ff81035c..a592ad2c1 100644 --- a/src/sleep.h +++ b/src/sleep.h @@ -4,7 +4,7 @@ #include "Observer.h" #include "configuration.h" -void doDeepSleep(uint32_t msecToWake), cpuDeepSleep(uint32_t msecToWake); +void doDeepSleep(uint32_t msecToWake, bool skipPreflight), cpuDeepSleep(uint32_t msecToWake); #ifdef ARCH_ESP32 #include "esp_sleep.h" From 47c6738c0dc415d2817ae7420838fc6fb6eac86c Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Sat, 30 Sep 2023 23:38:51 -0500 Subject: [PATCH 04/23] Fix GPS init bug -- power up even when disabled (#2850) --- src/gps/GPS.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 13afaa3e6..6a0b5e3dd 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -899,9 +899,7 @@ GPS *GPS::createGps() LOG_DEBUG("Using " NMEA_MSG_GXGSA " for 3DFIX and PDOP\n"); #endif - if (config.position.gps_enabled) { - new_gps->setGPSPower(true, false); - } + new_gps->setGPSPower(true, false); #ifdef PIN_GPS_RESET digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms From 5ecdbd0dbb4fe8b030a38d34e17a880f39c9c40c Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sun, 1 Oct 2023 12:48:12 -0500 Subject: [PATCH 05/23] Removed non-functional deep sleep button awake functionality (user can RST instead) (#2852) * Fixed mask length * Don't want_response if we're a tracker or sensor * Fixes * Removing non-functioning deep sleep button awake --- src/modules/NodeInfoModule.cpp | 4 +++- src/platform/esp32/main-esp32.cpp | 12 ------------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index 09819dab1..855ba9cde 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -40,7 +40,9 @@ void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t cha meshtastic_MeshPacket *p = allocReply(); if (p) { // Check whether we didn't ignore it p->to = dest; - p->decoded.want_response = wantReplies; + p->decoded.want_response = (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER && + config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && + wantReplies; p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; if (channel > 0) { LOG_DEBUG("sending ourNodeInfo to channel %d\n", channel); diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp index d9bc57b02..524f8035f 100644 --- a/src/platform/esp32/main-esp32.cpp +++ b/src/platform/esp32/main-esp32.cpp @@ -199,18 +199,6 @@ void cpuDeepSleep(uint32_t msecToWake) // We want RTC peripherals to stay on esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); -#ifdef BUTTON_PIN - -#if SOC_PM_SUPPORT_EXT_WAKEUP && !defined(HELTEC_WIRELESS_TRACKER) - esp_sleep_enable_ext0_wakeup((gpio_num_t)(1ULL << (config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN)), LOW); -#endif - -#ifdef BUTTON_NEED_PULLUP - gpio_pullup_en((gpio_num_t)BUTTON_PIN); -#endif - -#endif - esp_sleep_enable_timer_wakeup(msecToWake * 1000ULL); // call expects usecs esp_deep_sleep_start(); // TBD mA sleep current (battery) } \ No newline at end of file From 50db2d0e9b2a119e5c359c87b3474c023e13a847 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Sun, 1 Oct 2023 20:39:18 -0500 Subject: [PATCH 06/23] Add timeout to ublox PMREQ command (#2851) --- src/gps/GPS.cpp | 16 ++++++++++------ src/gps/GPS.h | 4 ++-- src/gps/ubx.h | 2 +- src/sleep.cpp | 2 +- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 6a0b5e3dd..87cda5c4b 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -433,7 +433,7 @@ GPS::~GPS() notifyGPSSleepObserver.observe(¬ifyGPSSleep); } -void GPS::setGPSPower(bool on, bool standbyOnly) +void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime) { LOG_INFO("Setting GPS power=%d\n", on); if (on) { @@ -483,6 +483,10 @@ void GPS::setGPSPower(bool on, bool standbyOnly) if (!on) { if (gnssModel == GNSS_MODEL_UBLOX) { uint8_t msglen; + LOG_DEBUG("Sleep Time: %i\n", sleepTime); + for (int i = 0; i < 4; i++) { + gps->_message_PMREQ[0 + i] = sleepTime >> (i * 8); // Encode the sleep time in millis into the packet + } msglen = gps->makeUBXPacket(0x02, 0x41, 0x08, gps->_message_PMREQ); gps->_serial_gps->write(gps->UBXscratch, msglen); } @@ -514,7 +518,7 @@ void GPS::setAwake(bool on) LOG_DEBUG("WANT GPS=%d\n", on); isAwake = on; if (!enabled) { // short circuit if the user has disabled GPS - setGPSPower(false, false); + setGPSPower(false, false, 0); return; } @@ -532,12 +536,12 @@ void GPS::setAwake(bool on) } if ((int32_t)getSleepTime() - averageLockTime > 15 * 60 * 1000) { // 15 minutes is probably long enough to make a complete poweroff worth it. - setGPSPower(on, false); + setGPSPower(on, false, getSleepTime() - averageLockTime); } else if ((int32_t)getSleepTime() - averageLockTime > 10000) { // 10 seconds is enough for standby #ifdef GPS_UC6580 - setGPSPower(on, false); + setGPSPower(on, false, getSleepTime() - averageLockTime); #else - setGPSPower(on, true); + setGPSPower(on, true, getSleepTime() - averageLockTime); #endif } else if (averageLockTime > 20000) { averageLockTime -= 1000; // eventually want to sleep again. @@ -899,7 +903,7 @@ GPS *GPS::createGps() LOG_DEBUG("Using " NMEA_MSG_GXGSA " for 3DFIX and PDOP\n"); #endif - new_gps->setGPSPower(true, false); + new_gps->setGPSPower(true, false, 0); #ifdef PIN_GPS_RESET digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 4269acf2d..bdd0b31a7 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -94,7 +94,7 @@ class GPS : private concurrency::OSThread /** If !NULL we will use this serial port to construct our GPS */ static HardwareSerial *_serial_gps; - static const uint8_t _message_PMREQ[]; + static uint8_t _message_PMREQ[]; static const uint8_t _message_CFG_RXM_PSM[]; static const uint8_t _message_CFG_RXM_ECO[]; static const uint8_t _message_CFG_PM2[]; @@ -132,7 +132,7 @@ class GPS : private concurrency::OSThread // Disable the thread int32_t disable() override; - void setGPSPower(bool on, bool standbyOnly); + void setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime); /// Returns true if we have acquired GPS lock. virtual bool hasLock(); diff --git a/src/gps/ubx.h b/src/gps/ubx.h index 6493b2ce7..2be2d1d33 100644 --- a/src/gps/ubx.h +++ b/src/gps/ubx.h @@ -1,4 +1,4 @@ -const uint8_t GPS::_message_PMREQ[] PROGMEM = { +uint8_t GPS::_message_PMREQ[] PROGMEM = { 0x00, 0x00, // 4 bytes duration of request task 0x00, 0x00, // (milliseconds) 0x02, 0x00, // Task flag bitfield diff --git a/src/sleep.cpp b/src/sleep.cpp index d9fb1ba50..9d0468e70 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -175,7 +175,7 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) nodeDB.saveToDisk(); // Kill GPS power completely (even if previously we just had it in sleep mode) - gps->setGPSPower(false, false); + gps->setGPSPower(false, false, 0); setLed(false); From a6e4402e41d2054562334aea74b5d64f9e5124f9 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 2 Oct 2023 06:28:05 -0500 Subject: [PATCH 07/23] Screen on secs router default (#2855) --- src/mesh/NodeDB.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 51c1b3043..f906acd58 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -192,7 +192,7 @@ extern NodeDB nodeDB; #define default_sds_secs IF_ROUTER(ONE_DAY, UINT32_MAX) // Default to forever super deep sleep #define default_ls_secs IF_ROUTER(ONE_DAY, 5 * 60) #define default_min_wake_secs 10 -#define default_screen_on_secs 60 * 10 +#define default_screen_on_secs IF_ROUTER(1, 60 * 10) #define default_mqtt_address "mqtt.meshtastic.org" #define default_mqtt_username "meshdev" From 94c2ade272d70b07530c68dc14215aa729fab219 Mon Sep 17 00:00:00 2001 From: Manuel <71137295+mverch67@users.noreply.github.com> Date: Mon, 2 Oct 2023 23:16:29 +0200 Subject: [PATCH 08/23] make esp32 deepsleep button wakeup functional again (#2854) * make deepsleep button wakeup functional again * Remove unused var * Cleanup comment * suppress screen wake on button * add resume screen * trunk fmt * added missing #ifdef --------- Co-authored-by: Ben Meadors --- src/PowerFSM.cpp | 4 +--- src/graphics/Screen.cpp | 23 ++++++++++++++++++++--- src/platform/esp32/main-esp32.cpp | 22 ++++++++++++++++++++-- src/sleep.cpp | 26 ++++++++++++++++++++++---- 4 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index b8c70292c..b9c7586e4 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -348,10 +348,8 @@ void PowerFSM_setup() getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, "Screen-on timeout"); +// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally) #ifdef ARCH_ESP32 - State *lowPowerState = &stateLS; - // We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally) - // See: https://github.com/meshtastic/firmware/issues/1071 if (isRouter || config.power.is_power_saving) { powerFSM.add_timed_transition(&stateNB, &stateLS, diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 9ccd28aba..547d7f59e 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -164,11 +164,28 @@ static void drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDispl // FIXME - draw serial # somewhere? } +#ifdef ARCH_ESP32 +static void drawFrameResume(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + uint16_t x_offset = display->width() / 2; + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->setFont(FONT_MEDIUM); + display->drawString(x_offset + x, 26 + y, "Resuming..."); +} +#endif + static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { - // Draw region in upper left - const char *region = myRegion ? myRegion->name : NULL; - drawIconScreen(region, display, state, x, y); +#ifdef ARCH_ESP32 + if (wakeCause == ESP_SLEEP_WAKEUP_TIMER || wakeCause == ESP_SLEEP_WAKEUP_EXT1) { + drawFrameResume(display, state, x, y); + } else +#endif + { + // Draw region in upper left + const char *region = myRegion ? myRegion->name : NULL; + drawIconScreen(region, display, state, x, y); + } } static void drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp index 524f8035f..833e058d8 100644 --- a/src/platform/esp32/main-esp32.cpp +++ b/src/platform/esp32/main-esp32.cpp @@ -193,8 +193,26 @@ void cpuDeepSleep(uint32_t msecToWake) rtc_gpio_isolate((gpio_num_t)rtcGpios[i]); #endif - // FIXME, disable internal rtc pullups/pulldowns on the non isolated pins. for inputs that we aren't using - // to detect wake and in normal operation the external part drives them hard. + // FIXME, disable internal rtc pullups/pulldowns on the non isolated pins. for inputs that we aren't using + // to detect wake and in normal operation the external part drives them hard. +#ifdef BUTTON_PIN + // Only GPIOs which are have RTC functionality can be used in this bit map: 0,2,4,12-15,25-27,32-39. +#if SOC_RTCIO_HOLD_SUPPORTED + uint64_t gpioMask = (1ULL << (config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN)); +#endif + +#ifdef BUTTON_NEED_PULLUP + gpio_pullup_en((gpio_num_t)BUTTON_PIN); +#endif + + // Not needed because both of the current boards have external pullups + // FIXME change polarity in hw so we can wake on ANY_HIGH instead - that would allow us to use all three buttons (instead of + // just the first) gpio_pullup_en((gpio_num_t)BUTTON_PIN); + +#if SOC_PM_SUPPORT_EXT_WAKEUP + esp_sleep_enable_ext1_wakeup(gpioMask, ESP_EXT1_WAKEUP_ALL_LOW); +#endif +#endif // We want RTC peripherals to stay on esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); diff --git a/src/sleep.cpp b/src/sleep.cpp index 9d0468e70..532aad519 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -95,7 +95,29 @@ void initDeepSleep() { #ifdef ARCH_ESP32 bootCount++; + const char *reason; wakeCause = esp_sleep_get_wakeup_cause(); + + switch (wakeCause) { + case ESP_SLEEP_WAKEUP_EXT0: + reason = "ext0 RTC_IO"; + break; + case ESP_SLEEP_WAKEUP_EXT1: + reason = "ext1 RTC_CNTL"; + break; + case ESP_SLEEP_WAKEUP_TIMER: + reason = "timer"; + break; + case ESP_SLEEP_WAKEUP_TOUCHPAD: + reason = "touchpad"; + break; + case ESP_SLEEP_WAKEUP_ULP: + reason = "ULP program"; + break; + default: + reason = "reset"; + break; + } /* Not using yet because we are using wake on all buttons being low @@ -106,7 +128,6 @@ void initDeepSleep() #ifdef DEBUG_PORT // If we booted because our timer ran out or the user pressed reset, send those as fake events - const char *reason = "reset"; // our best guess RESET_REASON hwReason = rtc_get_reset_reason(0); if (hwReason == RTCWDT_BROWN_OUT_RESET) @@ -118,9 +139,6 @@ void initDeepSleep() if (hwReason == TG1WDT_SYS_RESET) reason = "intWatchdog"; - if (wakeCause == ESP_SLEEP_WAKEUP_TIMER) - reason = "timeout"; - LOG_INFO("Booted, wake cause %d (boot count %d), reset_reason=%s\n", wakeCause, bootCount, reason); #endif #endif From f301e236eb145f502735212a2e60752a51716318 Mon Sep 17 00:00:00 2001 From: Manuel <71137295+mverch67@users.noreply.github.com> Date: Tue, 3 Oct 2023 13:37:46 +0200 Subject: [PATCH 09/23] fix crash during shutdown (#2859) * fix null pointer access * ptr initialize --- src/gps/GPS.cpp | 2 +- src/sleep.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 87cda5c4b..025e6007b 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -20,7 +20,7 @@ HardwareSerial *GPS::_serial_gps = &Serial1; HardwareSerial *GPS::_serial_gps = NULL; #endif -GPS *gps; +GPS *gps = nullptr; /// Multiple GPS instances might use the same serial port (in sequence), but we can /// only init that port once. diff --git a/src/sleep.cpp b/src/sleep.cpp index 532aad519..da3e43dcb 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -193,7 +193,8 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) nodeDB.saveToDisk(); // Kill GPS power completely (even if previously we just had it in sleep mode) - gps->setGPSPower(false, false, 0); + if (gps) + gps->setGPSPower(false, false, 0); setLed(false); From 37c3d159782684bd230af30302011b9a49592e65 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Tue, 3 Oct 2023 13:39:35 +0200 Subject: [PATCH 10/23] Check if packet is decrypted before using portnum when converting to JSON (#2857) Co-authored-by: Ben Meadors --- src/mqtt/MQTT.cpp | 125 ++++++++++++++++++++++------------------------ 1 file changed, 59 insertions(+), 66 deletions(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 791a4194b..f369f873f 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -516,34 +516,34 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) JSONObject msgPayload; JSONObject jsonObj; - switch (mp->decoded.portnum) { - case meshtastic_PortNum_TEXT_MESSAGE_APP: { - msgType = "text"; - // convert bytes to string - LOG_DEBUG("got text message of size %u\n", mp->decoded.payload.size); - char payloadStr[(mp->decoded.payload.size) + 1]; - memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size); - payloadStr[mp->decoded.payload.size] = 0; // null terminated string - // check if this is a JSON payload - JSONValue *json_value = JSON::Parse(payloadStr); - if (json_value != NULL) { - LOG_INFO("text message payload is of type json\n"); - // if it is, then we can just use the json object - jsonObj["payload"] = json_value; - } else { - // if it isn't, then we need to create a json object - // with the string as the value - LOG_INFO("text message payload is of type plaintext\n"); - msgPayload["text"] = new JSONValue(payloadStr); - jsonObj["payload"] = new JSONValue(msgPayload); + if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { + switch (mp->decoded.portnum) { + case meshtastic_PortNum_TEXT_MESSAGE_APP: { + msgType = "text"; + // convert bytes to string + LOG_DEBUG("got text message of size %u\n", mp->decoded.payload.size); + char payloadStr[(mp->decoded.payload.size) + 1]; + memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size); + payloadStr[mp->decoded.payload.size] = 0; // null terminated string + // check if this is a JSON payload + JSONValue *json_value = JSON::Parse(payloadStr); + if (json_value != NULL) { + LOG_INFO("text message payload is of type json\n"); + // if it is, then we can just use the json object + jsonObj["payload"] = json_value; + } else { + // if it isn't, then we need to create a json object + // with the string as the value + LOG_INFO("text message payload is of type plaintext\n"); + msgPayload["text"] = new JSONValue(payloadStr); + jsonObj["payload"] = new JSONValue(msgPayload); + } + break; } - break; - } - case meshtastic_PortNum_TELEMETRY_APP: { - msgType = "telemetry"; - meshtastic_Telemetry scratch; - meshtastic_Telemetry *decoded = NULL; - if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { + case meshtastic_PortNum_TELEMETRY_APP: { + msgType = "telemetry"; + meshtastic_Telemetry scratch; + meshtastic_Telemetry *decoded = NULL; memset(&scratch, 0, sizeof(scratch)); if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Telemetry_msg, &scratch)) { decoded = &scratch; @@ -564,14 +564,12 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) } else { LOG_ERROR("Error decoding protobuf for telemetry message!\n"); } - }; - break; - } - case meshtastic_PortNum_NODEINFO_APP: { - msgType = "nodeinfo"; - meshtastic_User scratch; - meshtastic_User *decoded = NULL; - if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { + break; + } + case meshtastic_PortNum_NODEINFO_APP: { + msgType = "nodeinfo"; + meshtastic_User scratch; + meshtastic_User *decoded = NULL; memset(&scratch, 0, sizeof(scratch)); if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_User_msg, &scratch)) { decoded = &scratch; @@ -583,14 +581,12 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) } else { LOG_ERROR("Error decoding protobuf for nodeinfo message!\n"); } - }; - break; - } - case meshtastic_PortNum_POSITION_APP: { - msgType = "position"; - meshtastic_Position scratch; - meshtastic_Position *decoded = NULL; - if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { + break; + } + case meshtastic_PortNum_POSITION_APP: { + msgType = "position"; + meshtastic_Position scratch; + meshtastic_Position *decoded = NULL; memset(&scratch, 0, sizeof(scratch)); if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Position_msg, &scratch)) { decoded = &scratch; @@ -627,15 +623,12 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) } else { LOG_ERROR("Error decoding protobuf for position message!\n"); } - }; - break; - } - - case meshtastic_PortNum_WAYPOINT_APP: { - msgType = "position"; - meshtastic_Waypoint scratch; - meshtastic_Waypoint *decoded = NULL; - if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { + break; + } + case meshtastic_PortNum_WAYPOINT_APP: { + msgType = "position"; + meshtastic_Waypoint scratch; + meshtastic_Waypoint *decoded = NULL; memset(&scratch, 0, sizeof(scratch)); if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) { decoded = &scratch; @@ -650,14 +643,12 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) } else { LOG_ERROR("Error decoding protobuf for position message!\n"); } - }; - break; - } - case meshtastic_PortNum_NEIGHBORINFO_APP: { - msgType = "neighborinfo"; - meshtastic_NeighborInfo scratch; - meshtastic_NeighborInfo *decoded = NULL; - if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { + break; + } + case meshtastic_PortNum_NEIGHBORINFO_APP: { + msgType = "neighborinfo"; + meshtastic_NeighborInfo scratch; + meshtastic_NeighborInfo *decoded = NULL; memset(&scratch, 0, sizeof(scratch)); if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_NeighborInfo_msg, &scratch)) { @@ -678,12 +669,14 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) } else { LOG_ERROR("Error decoding protobuf for neighborinfo message!\n"); } - }; - break; - } - // add more packet types here if needed - default: - break; + break; + } + // add more packet types here if needed + default: + break; + } + } else { + LOG_WARN("Couldn't convert encrypted payload of MeshPacket to JSON\n"); } jsonObj["id"] = new JSONValue((uint)mp->id); From 2a6c8be68416d818b9b60e43ab15ceead297afe2 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 3 Oct 2023 10:09:27 -0500 Subject: [PATCH 11/23] Avoid problematic sleep state transitions for power saving sensors and trackers (#2860) * Avoid problematic sleep state transitions for power saving sensors and trackers * Line got duped :-| --- src/PowerFSM.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index b9c7586e4..c64599ce6 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -245,6 +245,8 @@ Fsm powerFSM(&stateBOOT); void PowerFSM_setup() { bool isRouter = (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ? 1 : 0); + bool isTrackerOrSensor = config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER || + config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR; bool hasPower = isPowered(); LOG_INFO("PowerFSM init, USB power=%d\n", hasPower ? 1 : 0); @@ -351,7 +353,9 @@ void PowerFSM_setup() // We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally) #ifdef ARCH_ESP32 // See: https://github.com/meshtastic/firmware/issues/1071 - if (isRouter || config.power.is_power_saving) { + // Don't add power saving transitions if we are a power saving tracker or sensor. Sleep will be initiatiated through the + // modules + if ((isRouter || config.power.is_power_saving) && !isTrackerOrSensor) { powerFSM.add_timed_transition(&stateNB, &stateLS, getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL, "Min wake timeout"); From aa38f53aed372875bf820473bb2d99091120c46f Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Tue, 3 Oct 2023 12:05:40 -0500 Subject: [PATCH 12/23] Fix for T-Beam 1.2 GPS (#2858) * Fix for T-Beam 1.2 GPS, with DEBUG enabled * Don't break other devices * Saving GPS data on this breaks on next boot. Fix. * derp * disable the extra verbosity * Try the same sort of factory reset as the Lilygo image * Catch GPS reboots and squash * trunk * GPS --------- Co-authored-by: Ben Meadors --- platformio.ini | 2 +- src/gps/GPS.cpp | 130 +++++++++++++++++++++++++++------------ src/gps/GPS.h | 2 + variants/tbeam/variant.h | 1 + 4 files changed, 95 insertions(+), 40 deletions(-) diff --git a/platformio.ini b/platformio.ini index 0a5029f9d..a6ad6f873 100644 --- a/platformio.ini +++ b/platformio.ini @@ -70,7 +70,7 @@ lib_deps = https://github.com/meshtastic/esp8266-oled-ssd1306.git#b38094e03dfa964fbc0e799bc374e91a605c1223 ; ESP8266_SSD1306 https://github.com/mathertel/OneButton#2.1.0 ; OneButton library for non-blocking button debounce https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159 - https://github.com/meshtastic/TinyGPSPlus.git#127ad674ef85f0201cb68a065879653ed94792c4 + https://github.com/meshtastic/TinyGPSPlus.git#076e8d2c8fb702d9be5b08c55b93ff76f8af7e61 https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3 nanopb/Nanopb@^0.4.7 erriez/ErriezCRC32@^1.0.1 diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 025e6007b..eb8cec1c9 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -76,28 +76,25 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis) while (millis() < startTimeout) { if (_serial_gps->available()) { b = _serial_gps->read(); +#ifdef GPS_DEBUG + LOG_DEBUG("%02X", (char *)buffer); +#endif buffer[bytesRead] = b; bytesRead++; if ((bytesRead == 767) || (b == '\r')) { if (strnstr((char *)buffer, message, bytesRead) != nullptr) { #ifdef GPS_DEBUG - buffer[bytesRead] = '\0'; - LOG_DEBUG("%s\r", (char *)buffer); + LOG_DEBUG("\r"); #endif return GNSS_RESPONSE_OK; } else { -#ifdef GPS_DEBUG - buffer[bytesRead] = '\0'; - LOG_INFO("Bytes read:%s\n", (char *)buffer); -#endif bytesRead = 0; } } } } #ifdef GPS_DEBUG - buffer[bytesRead] = '\0'; - LOG_INFO("Bytes read:%s\n", (char *)buffer); + LOG_DEBUG("\n"); #endif return GNSS_RESPONSE_NONE; } @@ -252,10 +249,18 @@ int GPS::getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t bool GPS::setup() { int msglen = 0; + bool isProblematicGPS = false; if (!didSerialInit) { #if !defined(GPS_UC6580) - if (tx_gpio) { +#ifdef HAS_PMU + // The T-Beam 1.2 has issues with the GPS + if (HW_VENDOR == meshtastic_HardwareModel_TBEAM && PMU->getChipModel() == XPOWERS_AXP2101) { + gnssModel = GNSS_MODEL_UBLOX; + isProblematicGPS = true; + } +#endif + if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) { LOG_DEBUG("Probing for GPS at %d \n", serialSpeeds[speedSelect]); gnssModel = probe(serialSpeeds[speedSelect]); if (gnssModel == GNSS_MODEL_UNKNOWN) { @@ -390,32 +395,36 @@ bool GPS::setup() LOG_WARN("Unable to enable powersaving for GPS.\n"); } } else { - if (strncmp(info.hwVersion, "00040007", 8) == 0) { // This PSM mode has only been tested on this hardware - msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_PSM); - _serial_gps->write(UBXscratch, msglen); - if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) { - LOG_WARN("Unable to enable powersaving mode for GPS.\n"); - } - msglen = makeUBXPacket(0x06, 0x3B, 44, _message_CFG_PM2); - _serial_gps->write(UBXscratch, msglen); - if (getACK(0x06, 0x3B, 300) != GNSS_RESPONSE_OK) { - LOG_WARN("Unable to enable powersaving details for GPS.\n"); - } - } else { - msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_ECO); - _serial_gps->write(UBXscratch, msglen); - if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) { - LOG_WARN("Unable to enable powersaving ECO mode for GPS.\n"); + if (!(isProblematicGPS)) { + if (strncmp(info.hwVersion, "00040007", 8) == 0) { // This PSM mode has only been tested on this hardware + msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_PSM); + _serial_gps->write(UBXscratch, msglen); + if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) { + LOG_WARN("Unable to enable powersaving mode for GPS.\n"); + } + msglen = makeUBXPacket(0x06, 0x3B, 44, _message_CFG_PM2); + _serial_gps->write(UBXscratch, msglen); + if (getACK(0x06, 0x3B, 300) != GNSS_RESPONSE_OK) { + LOG_WARN("Unable to enable powersaving details for GPS.\n"); + } + } else { + msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_ECO); + _serial_gps->write(UBXscratch, msglen); + if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) { + LOG_WARN("Unable to enable powersaving ECO mode for GPS.\n"); + } } } } - - msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE), _message_SAVE); - _serial_gps->write(UBXscratch, msglen); - if (getACK(0x06, 0x09, 300) != GNSS_RESPONSE_OK) { - LOG_WARN("Unable to save GNSS module configuration.\n"); - } else { - LOG_INFO("GNSS module configuration saved!\n"); + // The T-beam 1.2 has issues. + if (!(isProblematicGPS)) { + msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE), _message_SAVE); + _serial_gps->write(UBXscratch, msglen); + if (getACK(0x06, 0x09, 300) != GNSS_RESPONSE_OK) { + LOG_WARN("Unable to save GNSS module configuration.\n"); + } else { + LOG_INFO("GNSS module configuration saved!\n"); + } } } didSerialInit = true; @@ -635,6 +644,11 @@ int32_t GPS::runOnce() } } } + // At least one GPS has a bad habit of losing its mind from time to time + if (rebootsSeen > 2) { + rebootsSeen = 0; + gps->factoryReset(); + } // If we are overdue for an update, turn on the GPS and at least publish the current status uint32_t now = millis(); @@ -958,11 +972,38 @@ bool GPS::factoryReset() digitalWrite(PIN_GPS_REINIT, 1); #endif - // send the UBLOX Factory Reset Command regardless of detect state, something is very wrong, just assume it's UBLOX. - // Factory Reset - byte _message_reset[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFB, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x17, 0x2B, 0x7E}; - _serial_gps->write(_message_reset, sizeof(_message_reset)); + if (HW_VENDOR == meshtastic_HardwareModel_TBEAM) { + byte _message_reset1[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1C, 0xA2}; + _serial_gps->write(_message_reset1, sizeof(_message_reset1)); + if (getACK(0x05, 0x01, 10000)) { + LOG_INFO("Get ack success!\n"); + } + delay(100); + byte _message_reset2[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1B, 0xA1}; + _serial_gps->write(_message_reset2, sizeof(_message_reset2)); + if (getACK(0x05, 0x01, 10000)) { + LOG_INFO("Get ack success!\n"); + } + delay(100); + byte _message_reset3[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0x1D, 0xB3}; + _serial_gps->write(_message_reset3, sizeof(_message_reset3)); + if (getACK(0x05, 0x01, 10000)) { + LOG_INFO("Get ack success!\n"); + } + // Reset device ram to COLDSTART state + // byte _message_CFG_RST_COLDSTART[] = {0xB5, 0x62, 0x06, 0x04, 0x04, 0x00, 0xFF, 0xB9, 0x00, 0x00, 0xC6, 0x8B}; + // _serial_gps->write(_message_CFG_RST_COLDSTART, sizeof(_message_CFG_RST_COLDSTART)); + // delay(1000); + } else { + // send the UBLOX Factory Reset Command regardless of detect state, something is very wrong, just assume it's UBLOX. + // Factory Reset + byte _message_reset[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFB, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x17, 0x2B, 0x7E}; + _serial_gps->write(_message_reset, sizeof(_message_reset)); + } delay(1000); return true; } @@ -1159,6 +1200,7 @@ bool GPS::hasFlow() bool GPS::whileIdle() { + int charsInBuf = 0; bool isValid = false; if (!isAwake) { clearBuffer(); @@ -1175,10 +1217,20 @@ bool GPS::whileIdle() // First consume any chars that have piled up at the receiver while (_serial_gps->available() > 0) { int c = _serial_gps->read(); - // LOG_DEBUG("%c", c); + UBXscratch[charsInBuf] = c; +#ifdef GPS_DEBUG + LOG_DEBUG("%c", c); +#endif isValid |= reader.encode(c); + if (charsInBuf > sizeof(UBXscratch) - 10 || c == '\r') { + if (strnstr((char *)UBXscratch, "$GPTXT,01,01,02,u-blox ag - www.u-blox.com*50", charsInBuf)) { + rebootsSeen++; + } + charsInBuf = 0; + } else { + charsInBuf++; + } } - return isValid; } void GPS::enable() diff --git a/src/gps/GPS.h b/src/gps/GPS.h index bdd0b31a7..d52c79182 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -154,6 +154,8 @@ class GPS : private concurrency::OSThread // scratch space for creating ublox packets uint8_t UBXscratch[250] = {0}; + int rebootsSeen = 0; + int getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID, uint32_t waitMillis); GPS_RESPONSE getACK(uint8_t c, uint8_t i, uint32_t waitMillis); GPS_RESPONSE getACK(const char *message, uint32_t waitMillis); diff --git a/variants/tbeam/variant.h b/variants/tbeam/variant.h index 84a3477d4..a0ba70bfd 100644 --- a/variants/tbeam/variant.h +++ b/variants/tbeam/variant.h @@ -42,3 +42,4 @@ #define GPS_UBLOX #define GPS_RX_PIN 34 #define GPS_TX_PIN 12 +// #define GPS_DEBUG \ No newline at end of file From 7cebd79475b4b00187406ecde07429651947b8be Mon Sep 17 00:00:00 2001 From: code8buster <20384924+code8buster@users.noreply.github.com> Date: Wed, 4 Oct 2023 00:50:27 +0000 Subject: [PATCH 13/23] Use doNotEnterOff flag to prevent GNSS poweroff before fix acquisition (#2861) Co-authored-by: Ben Meadors --- src/gps/ubx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gps/ubx.h b/src/gps/ubx.h index 2be2d1d33..bc839c41e 100644 --- a/src/gps/ubx.h +++ b/src/gps/ubx.h @@ -17,7 +17,7 @@ const uint8_t GPS::_message_CFG_RXM_ECO[] PROGMEM = { const uint8_t GPS::_message_CFG_PM2[] PROGMEM = { 0x01, 0x06, 0x00, 0x00, // version, Reserved - 0x0e, 0x81, 0x42, 0x01, // flags + 0x0E, 0x81, 0x43, 0x01, // flags 0xE8, 0x03, 0x00, 0x00, // update period 1000 ms 0x10, 0x27, 0x00, 0x00, // search period 10s 0x00, 0x00, 0x00, 0x00, // Grod offset 0 @@ -189,4 +189,4 @@ const uint8_t GPS::_message_SAVE[] = { 0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections 0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded 0x0F // deviceMask: BBR, Flash, EEPROM, and SPI Flash -}; \ No newline at end of file +}; From fbf74fc0b21842f25e681bd2e783588a59559520 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 4 Oct 2023 10:23:55 -0500 Subject: [PATCH 14/23] [create-pull-request] automated change (#2863) Co-authored-by: thebentern --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index fc48509e1..43b9f255e 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 2 -build = 10 +build = 11 From fc06754e1f9e66b88ed47dab86b6bdb20a8cd78d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Thu, 5 Oct 2023 05:24:25 +0200 Subject: [PATCH 15/23] Possibly fix #2704 "Heltec Wireless Tracker screen doesn't display anything" (#2749) * fix #2704 Co-authored-by: Ben Meadors Co-authored-by: Jonathan Bennett --- src/Power.cpp | 12 ++++ src/graphics/TFTDisplay.cpp | 49 ++++++++++++++- src/main.cpp | 73 +++++++++++++++++++++- src/main.h | 2 + src/sleep.cpp | 8 ++- variants/heltec_wireless_tracker/variant.h | 20 ++++-- 6 files changed, 155 insertions(+), 9 deletions(-) diff --git a/src/Power.cpp b/src/Power.cpp index 57d6513a7..da2c9da93 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -175,9 +175,21 @@ class AnalogBatteryLevel : public HasBatteryLevel uint32_t raw = 0; #ifdef ARCH_ESP32 #ifndef BAT_MEASURE_ADC_UNIT // ADC1 +#ifdef ADC_CTRL + if (heltec_version == 5) { + pinMode(ADC_CTRL, OUTPUT); + digitalWrite(ADC_CTRL, HIGH); + delay(10); + } +#endif for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) { raw += adc1_get_raw(adc_channel); } +#ifdef ADC_CTRL + if (heltec_version == 5) { + digitalWrite(ADC_CTRL, LOW); + } +#endif #else // ADC2 int32_t adc_buf = 0; for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) { diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index 71ce35e82..5eec2b200 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -1,4 +1,5 @@ #include "configuration.h" +#include "main.h" #ifndef TFT_BACKLIGHT_ON #define TFT_BACKLIGHT_ON HIGH @@ -81,8 +82,16 @@ class LGFX : public lgfx::LGFX_Device { auto cfg = _light_instance.config(); // Gets a structure for backlight settings. +#ifdef ST7735_BL_V03 + if (heltec_version == 3) { + cfg.pin_bl = ST7735_BL_V03; + } else { + cfg.pin_bl = ST7735_BL_V05; + } +#else cfg.pin_bl = ST7735_BL; // Pin number to which the backlight is connected - cfg.invert = true; // true to invert the brightness of the backlight +#endif + cfg.invert = true; // true to invert the brightness of the backlight // cfg.freq = 44100; // PWM frequency of backlight // cfg.pwm_channel = 1; // PWM channel number to use @@ -364,9 +373,23 @@ void TFTDisplay::sendCommand(uint8_t com) // handle display on/off directly switch (com) { case DISPLAYON: { +#if defined(ST7735_BACKLIGHT_EN_V03) && defined(TFT_BACKLIGHT_ON) + if (heltec_version == 3) { + digitalWrite(ST7735_BACKLIGHT_EN_V03, TFT_BACKLIGHT_ON); + } else { + digitalWrite(ST7735_BACKLIGHT_EN_V05, TFT_BACKLIGHT_ON); + } +#endif #if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON) digitalWrite(TFT_BL, TFT_BACKLIGHT_ON); #endif +#ifdef VTFT_CTRL_V03 + if (heltec_version == 3) { + digitalWrite(VTFT_CTRL_V03, LOW); + } else { + digitalWrite(VTFT_CTRL_V05, LOW); + } +#endif #ifdef VTFT_CTRL digitalWrite(VTFT_CTRL, LOW); #endif @@ -376,9 +399,23 @@ void TFTDisplay::sendCommand(uint8_t com) break; } case DISPLAYOFF: { +#if defined(ST7735_BACKLIGHT_EN_V03) && defined(TFT_BACKLIGHT_ON) + if (heltec_version == 3) { + digitalWrite(ST7735_BACKLIGHT_EN_V03, !TFT_BACKLIGHT_ON); + } else { + digitalWrite(ST7735_BACKLIGHT_EN_V05, !TFT_BACKLIGHT_ON); + } +#endif #if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON) digitalWrite(TFT_BL, !TFT_BACKLIGHT_ON); #endif +#ifdef VTFT_CTRL_V03 + if (heltec_version == 3) { + digitalWrite(VTFT_CTRL_V03, HIGH); + } else { + digitalWrite(VTFT_CTRL_V05, HIGH); + } +#endif #ifdef VTFT_CTRL digitalWrite(VTFT_CTRL, HIGH); #endif @@ -436,6 +473,16 @@ bool TFTDisplay::connect() pinMode(TFT_BL, OUTPUT); #endif +#ifdef ST7735_BACKLIGHT_EN_V03 + if (heltec_version == 3) { + digitalWrite(ST7735_BACKLIGHT_EN_V03, TFT_BACKLIGHT_ON); + pinMode(ST7735_BACKLIGHT_EN_V03, OUTPUT); + } else { + digitalWrite(ST7735_BACKLIGHT_EN_V05, TFT_BACKLIGHT_ON); + pinMode(ST7735_BACKLIGHT_EN_V05, OUTPUT); + } +#endif + tft.init(); #if defined(M5STACK) tft.setRotation(0); diff --git a/src/main.cpp b/src/main.cpp index a4caad3fd..c9ba4c795 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -146,6 +146,25 @@ const char *getDeviceName() return name; } +#ifdef VEXT_ENABLE_V03 + +#include + +static uint32_t calibrate_one(rtc_cal_sel_t cal_clk, const char *name) +{ + const uint32_t cal_count = 1000; + uint32_t cali_val; + for (int i = 0; i < 5; ++i) { + cali_val = rtc_clk_cal(cal_clk, cal_count); + } + return cali_val; +} + +int heltec_version = 3; + +#define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk) +#endif + static int32_t ledBlinker() { static bool ledOn; @@ -216,11 +235,63 @@ void setup() digitalWrite(PIN_EINK_PWR_ON, HIGH); #endif -#ifdef VEXT_ENABLE +#ifdef ST7735_BL_V03 // Heltec Wireless Tracker PCB Change Detect/Hack + + rtc_clk_32k_enable(true); + CALIBRATE_ONE(RTC_CAL_RTC_MUX); + if (CALIBRATE_ONE(RTC_CAL_32K_XTAL) != 0) { + rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL); + CALIBRATE_ONE(RTC_CAL_RTC_MUX); + CALIBRATE_ONE(RTC_CAL_32K_XTAL); + } + + if (rtc_clk_slow_freq_get() != RTC_SLOW_FREQ_32K_XTAL) { + heltec_version = 3; + } else { + heltec_version = 5; + } +#endif + +#if defined(VEXT_ENABLE_V03) + if (heltec_version == 3) { + pinMode(VEXT_ENABLE_V03, OUTPUT); + digitalWrite(VEXT_ENABLE_V03, 0); // turn on the display power + LOG_DEBUG("HELTEC Detect Tracker V1.0\n"); + } else { + pinMode(VEXT_ENABLE_V05, OUTPUT); + digitalWrite(VEXT_ENABLE_V05, 1); // turn on the display power + LOG_DEBUG("HELTEC Detect Tracker V1.1\n"); + } +#elif defined(VEXT_ENABLE) pinMode(VEXT_ENABLE, OUTPUT); digitalWrite(VEXT_ENABLE, 0); // turn on the display power #endif +#if defined(VGNSS_CTRL_V03) + if (heltec_version == 3) { + pinMode(VGNSS_CTRL_V03, OUTPUT); + digitalWrite(VGNSS_CTRL_V03, LOW); + } else { + pinMode(VGNSS_CTRL_V05, OUTPUT); + digitalWrite(VGNSS_CTRL_V05, LOW); + } +#endif + +#if defined(VTFT_CTRL_V03) + if (heltec_version == 3) { + pinMode(VTFT_CTRL_V03, OUTPUT); + digitalWrite(VTFT_CTRL_V03, LOW); + } else { + pinMode(VTFT_CTRL_V05, OUTPUT); + digitalWrite(VTFT_CTRL_V05, LOW); + } +#endif + +#if defined(VGNSS_CTRL) + pinMode(VGNSS_CTRL, OUTPUT); + digitalWrite(VGNSS_CTRL, LOW); +#endif + #if defined(VTFT_CTRL) pinMode(VTFT_CTRL, OUTPUT); digitalWrite(VTFT_CTRL, LOW); diff --git a/src/main.h b/src/main.h index 301e8a10c..3f0120406 100644 --- a/src/main.h +++ b/src/main.h @@ -64,6 +64,8 @@ extern uint32_t shutdownAtMsec; extern uint32_t serialSinceMsec; +extern int heltec_version; + // If a thread does something that might need for it to be rescheduled ASAP it can set this flag // This will suppress the current delay and instead try to run ASAP. extern bool runASAP; diff --git a/src/sleep.cpp b/src/sleep.cpp index da3e43dcb..b0f4aec88 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -202,7 +202,13 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) digitalWrite(RESET_OLED, 1); // put the display in reset before killing its power #endif -#ifdef VEXT_ENABLE +#if defined(VEXT_ENABLE_V03) + if (heltec_version == 3) { + digitalWrite(VEXT_ENABLE_V03, 1); // turn off the display power + } else { + digitalWrite(VEXT_ENABLE_V05, 0); // turn off the display power + } +#elif defined(VEXT_ENABLE) digitalWrite(VEXT_ENABLE, 1); // turn off the display power #endif diff --git a/variants/heltec_wireless_tracker/variant.h b/variants/heltec_wireless_tracker/variant.h index cfb752d03..4a1b61038 100644 --- a/variants/heltec_wireless_tracker/variant.h +++ b/variants/heltec_wireless_tracker/variant.h @@ -9,9 +9,11 @@ #define ST7735_RESET 39 #define ST7735_MISO -1 #define ST7735_BUSY -1 -#define ST7735_BL 45 +#define ST7735_BL_V03 45 +#define ST7735_BL_V05 21 /* V1.1 PCB marking */ #define ST7735_SPI_HOST SPI3_HOST -#define ST7735_BACKLIGHT_EN 45 +#define ST7735_BACKLIGHT_EN_V03 45 +#define ST7735_BACKLIGHT_EN_V05 21 #define SPI_FREQUENCY 40000000 #define SPI_READ_FREQUENCY 16000000 #define SCREEN_ROTATE @@ -19,17 +21,20 @@ #define TFT_WIDTH 80 #define TFT_OFFSET_X 26 #define TFT_OFFSET_Y 0 -#define VTFT_CTRL 46 // Heltec Tracker needs this pulled low for TFT +#define VTFT_CTRL_V03 46 // Heltec Tracker needs this pulled low for TFT +#define VTFT_CTRL_V05 -1 #define SCREEN_TRANSITION_FRAMERATE 1 // fps #define DISPLAY_FORCE_SMALL_FONTS -#define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost +#define VEXT_ENABLE_V03 Vext // active low, powers the oled display and the lora antenna boost +#define VEXT_ENABLE_V05 3 // active HIGH, powers the oled display #define BUTTON_PIN 0 #define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage #define ADC_CHANNEL ADC1_GPIO1_CHANNEL #define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider #define ADC_MULTIPLIER 4.9 +#define ADC_CTRL 2 // active HIGH, powers the voltage divider. Only on 1.1 #undef GPS_RX_PIN #undef GPS_TX_PIN @@ -37,9 +42,12 @@ #define GPS_TX_PIN 34 #define PIN_GPS_RESET 35 #define PIN_GPS_PPS 36 -#define VGNSS_CTRL 37 // Heltec Tracker needs this pulled low for GPS -#define PIN_GPS_EN VGNSS_CTRL + +#define VGNSS_CTRL_V03 37 // Heltec Tracker needs this pulled low for GPS +#define VGNSS_CTRL_V05 -1 // Heltec Tracker needs this pulled low for GPS +#define PIN_GPS_EN VGNSS_CTRL_V03 #define GPS_EN_ACTIVE LOW + #define GPS_RESET_MODE LOW #define GPS_UC6580 From 950d5f09464fb6049c9e9c4c35a4b5c5205f4e73 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 5 Oct 2023 12:42:03 -0500 Subject: [PATCH 16/23] Power saving sensor (#2865) * Trunk * Again * This thing just keeps updating itself * Ignore tools * Sleepy sensor * Batrunkadunk --- .trunk/.gitignore | 2 +- .trunk/trunk.yaml | 26 +++++++++---------- src/modules/PositionModule.cpp | 4 +-- .../Telemetry/EnvironmentTelemetry.cpp | 15 +++++++++++ src/platform/nrf52/main-nrf52.cpp | 14 ++++++---- 5 files changed, 40 insertions(+), 21 deletions(-) diff --git a/.trunk/.gitignore b/.trunk/.gitignore index 695b51906..1e2465290 100644 --- a/.trunk/.gitignore +++ b/.trunk/.gitignore @@ -2,7 +2,7 @@ *logs *actions *notifications +*tools plugins user_trunk.yaml user.yaml -tools diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 7e81046a7..f2de06f0d 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -1,48 +1,48 @@ version: 0.1 cli: - version: 1.13.0 + version: 1.16.2 plugins: sources: - id: trunk - ref: v1.1.1 + ref: v1.2.5 uri: https://github.com/trunk-io/plugins lint: enabled: - bandit@1.7.5 - - checkov@2.4.1 + - checkov@2.5.0 - terrascan@1.18.3 - - trivy@0.44.1 - - trufflehog@3.48.0 + - trivy@0.45.1 + - trufflehog@3.59.0 - taplo@0.8.1 - - ruff@0.0.284 + - ruff@0.0.292 - yamllint@1.32.0 - isort@5.12.0 - - markdownlint@0.35.0 + - markdownlint@0.37.0 - oxipng@8.0.0 - svgo@3.0.2 - - actionlint@1.6.25 + - actionlint@1.6.26 - flake8@6.1.0 - hadolint@2.12.0 - shfmt@3.6.0 - shellcheck@0.9.0 - - black@23.7.0 + - black@23.9.1 - git-diff-check - - gitleaks@8.17.0 + - gitleaks@8.18.0 - clang-format@16.0.3 - - prettier@3.0.2 + - prettier@3.0.3 disabled: - taplo@0.8.1 - shellcheck@0.9.0 - shfmt@3.6.0 - oxipng@8.0.0 - actionlint@1.6.22 - - markdownlint@0.35.0 + - markdownlint@0.37.0 - hadolint@2.12.0 - svgo@3.0.2 runtimes: enabled: - python@3.10.8 - - go@1.19.5 + - go@1.21.0 - node@18.12.1 actions: disabled: diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index 29ddde4ce..a7beeda28 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -178,9 +178,9 @@ void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t cha service.sendToMesh(p, RX_SRC_LOCAL, true); if (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER && config.power.is_power_saving) { - LOG_DEBUG("Starting next execution in 3 seconds and then going to sleep.\n"); + LOG_DEBUG("Starting next execution in 5 seconds and then going to sleep.\n"); sleepOnNextExecution = true; - setIntervalFromNow(3000); + setIntervalFromNow(5000); } } diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 1f1a0cbf9..1047ade1d 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -8,6 +8,8 @@ #include "configuration.h" #include "main.h" #include "power.h" +#include "sleep.h" +#include "target_specific.h" #include #include @@ -51,6 +53,13 @@ SHT31Sensor sht31Sensor; int32_t EnvironmentTelemetryModule::runOnce() { + if (sleepOnNextExecution == true) { + sleepOnNextExecution = false; + uint32_t nightyNightMs = getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval); + LOG_DEBUG("Sleeping for %ims, then awaking to send metrics again.\n", nightyNightMs); + doDeepSleep(nightyNightMs, true); + } + uint32_t result = UINT32_MAX; /* Uncomment the preferences below if you want to use the module @@ -266,6 +275,12 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) } else { LOG_INFO("Sending packet to mesh\n"); service.sendToMesh(p, RX_SRC_LOCAL, true); + + if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR && config.power.is_power_saving) { + LOG_DEBUG("Starting next execution in 5 seconds and then going to sleep.\n"); + sleepOnNextExecution = true; + setIntervalFromNow(5000); + } } } return valid; diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index 6b986c778..65b45f1e9 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -180,15 +180,19 @@ void cpuDeepSleep(uint32_t msecToWake) digitalWrite(AQ_SET_PIN, LOW); #endif #endif - // FIXME, use system off mode with ram retention for key state? - // FIXME, use non-init RAM per - // https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled - - if (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER && config.power.is_power_saving == true) { + // Sleepy trackers or sensors can low power "sleep" + // Don't enter this if we're sleeping portMAX_DELAY, since that's a shutdown event + if (msecToWake != portMAX_DELAY && + (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER || + config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR) && + config.power.is_power_saving == true) { sd_power_mode_set(NRF_POWER_MODE_LOWPWR); delay(msecToWake); NVIC_SystemReset(); } else { + // FIXME, use system off mode with ram retention for key state? + // FIXME, use non-init RAM per + // https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled auto ok = sd_power_system_off(); if (ok != NRF_SUCCESS) { LOG_ERROR("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!\n"); From ef1d8c8eeed427cbd0fc3b61fee757f0e366598b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 5 Oct 2023 17:51:23 -0500 Subject: [PATCH 17/23] [create-pull-request] automated change (#2869) --- protobufs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protobufs b/protobufs index 0fb2f8471..82f6b6083 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 0fb2f847141006c36d7e9d5118766f3a5da4225a +Subproject commit 82f6b6083f2445b07b07906bf5a91b38f1ee0d95 From 33f28c3d56a5d170456119451b347a067d57d3bd Mon Sep 17 00:00:00 2001 From: pat-trunk-io Date: Fri, 6 Oct 2023 13:02:27 -0700 Subject: [PATCH 18/23] Add trunk githooks to the repo (#2870) --- .trunk/trunk.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index f2de06f0d..7de96bd21 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -47,7 +47,7 @@ runtimes: actions: disabled: - trunk-announce - - trunk-check-pre-push - - trunk-fmt-pre-commit enabled: + - trunk-fmt-pre-commit + - trunk-check-pre-push - trunk-upgrade-available From dc6f0b8e0b639bdf1d8616fdaf45a3063368da45 Mon Sep 17 00:00:00 2001 From: pat-trunk-io Date: Fri, 6 Oct 2023 13:31:04 -0700 Subject: [PATCH 19/23] mention trunk is beta on windows (#2871) Co-authored-by: Ben Meadors --- .github/pull_request_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 32f280a04..512dea311 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -7,7 +7,7 @@ is appreciated." This will allow other devs to potentially save you time by not accidentially duplicating work etc... - Please do not check in files that don't have real changes - Please do not reformat lines that you didn't have to change the code on -- We recommend using the [Visual Studio Code](https://platformio.org/install/ide?install=vscode) editor along with the ['Trunk Check' extension](https://marketplace.visualstudio.com/items?itemName=trunk.io) (WSL2 is required on windows), +- We recommend using the [Visual Studio Code](https://platformio.org/install/ide?install=vscode) editor along with the ['Trunk Check' extension](https://marketplace.visualstudio.com/items?itemName=trunk.io) (In beta for windows, WSL2 for the linux version), because it automatically follows our indentation rules and its auto reformatting will not cause spurious changes to lines. - If your PR fixes a bug, mention "fixes #bugnum" somewhere in your pull request description. - If your other co-developers have comments on your PR please tweak as needed. From 3ddad671a5f7053034627753cd542e87f6323713 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 8 Oct 2023 08:12:42 -0500 Subject: [PATCH 20/23] [create-pull-request] automated change (#2875) Co-authored-by: thebentern --- protobufs | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/protobufs b/protobufs index 82f6b6083..175a5c97f 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 82f6b6083f2445b07b07906bf5a91b38f1ee0d95 +Subproject commit 175a5c97fb608b28f100551d302603efd0c22185 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index c32f55aab..7733e1d99 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -113,6 +113,8 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_PICOMPUTER_S3 = 52, /* Heltec HT-CT62 with ESP32-C3 CPU and SX1262 LoRa */ meshtastic_HardwareModel_HELTEC_HT62 = 53, + /* E22-900M series modules with ESP32-S3 */ + meshtastic_HardwareModel_E22_900M_S3 = 54, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ From 54f0c045e4a3c4fec3079bd0374407fd2df53fb2 Mon Sep 17 00:00:00 2001 From: Sacha Weatherstone Date: Mon, 9 Oct 2023 22:30:02 +1000 Subject: [PATCH 21/23] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d450b88d3..ca8a924fd 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ This repository contains the device firmware for the Meshtastic project. -**[Building Instructions](https://meshtastic.org/docs/development/firmware/build)** -**[Flashing Instructions](https://meshtastic.org/docs/getting-started/flashing-firmware/)** +- **[Building Instructions](https://meshtastic.org/docs/development/firmware/build)** +- **[Flashing Instructions](https://meshtastic.org/docs/getting-started/flashing-firmware/)** ## Stats From 8780d93941248add99aa0dd317b32f1f92c04ace Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Mon, 9 Oct 2023 13:30:51 -0500 Subject: [PATCH 22/23] Remove missed GPS definition (#2878) --- variants/heltec_wsl_v3/variant.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/variants/heltec_wsl_v3/variant.h b/variants/heltec_wsl_v3/variant.h index 240a482f7..417abf34d 100644 --- a/variants/heltec_wsl_v3/variant.h +++ b/variants/heltec_wsl_v3/variant.h @@ -8,8 +8,6 @@ #define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost #define BUTTON_PIN 0 -#define PIN_GPS_EN 46 // GPS power enable pin - #define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage #define ADC_CHANNEL ADC1_GPIO1_CHANNEL #define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider From 10265aabd5214ae271e7c3827e08eaf4776cf56d Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 9 Oct 2023 18:33:04 -0500 Subject: [PATCH 23/23] Fix buggy phone positions (#2876) * Guard-clause channel util. to reduce nesting * Try-fix PhoneAPI position not updating * Trunk * Missed it * Really disable GPS when asked to --------- Co-authored-by: Jonathan Bennett --- src/gps/GPS.cpp | 6 +- src/mesh/NodeDB.cpp | 2 +- src/mesh/NodeDB.h | 7 +++ src/modules/PositionModule.cpp | 108 +++++++++++++++++++-------------- 4 files changed, 75 insertions(+), 48 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index eb8cec1c9..ce5b18af8 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -611,7 +611,7 @@ int32_t GPS::runOnce() return 2000; // Setup failed, re-run in two seconds // We have now loaded our saved preferences from flash - if (config.position.gps_enabled == false && config.position.fixed_position == false) { + if (config.position.gps_enabled == false) { return disable(); } // ONCE we will factory reset the GPS for bug #327 @@ -703,8 +703,8 @@ int32_t GPS::runOnce() // If state has changed do a publish publishUpdate(); - if (config.position.gps_enabled == false) // This should trigger if GPS is disabled but fixed_position is true - return disable(); + if (config.position.fixed_position == true && hasValidLocation) + return disable(); // This should trigger when we have a fixed position, and get that first position // 9600bps is approx 1 byte per msec, so considering our buffer size we never need to wake more often than 200ms // if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake. diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index d7fd84fb7..3b6168f27 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -687,8 +687,8 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou LOG_INFO("updatePosition LOCAL pos@%x, time=%u, latI=%d, lonI=%d, alt=%d\n", p.timestamp, p.time, p.latitude_i, p.longitude_i, p.altitude); + setLocalPosition(p); info->position = ConvertToPositionLite(p); - localPosition = p; } else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.timestamp && !p.location_source) { // FIXME SPECIAL TIME SETTING PACKET FROM EUD TO RADIO // (stop-gap fix for issue #900) diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index f906acd58..22d5a7780 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -131,6 +131,13 @@ class NodeDB meshtastic_NodeInfoLite *getMeshNode(NodeNum n); size_t getNumMeshNodes() { return *numMeshNodes; } + void setLocalPosition(meshtastic_Position position) + { + LOG_DEBUG("Setting local position: latitude=%i, longitude=%i, time=%i\n", position.latitude_i, position.longitude_i, + position.time); + localPosition = position; + } + private: /// Find a node in our DB, create an empty NodeInfoLite if missing meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n); diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index a7beeda28..445bde42b 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -44,10 +44,11 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes // FIXME this can in fact happen with packets sent from EUD (src=RX_SRC_USER) // to set fixed location, EUD-GPS location or just the time (see also issue #900) + bool isLocal = false; if (nodeDB.getNodeNum() == getFrom(&mp)) { LOG_DEBUG("Incoming update from MYSELF\n"); - // LOG_DEBUG("Ignored an incoming update from MYSELF\n"); - // return false; + isLocal = true; + nodeDB.setLocalPosition(p); } // Log packet size and data fields @@ -64,7 +65,8 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes tv.tv_sec = secs; tv.tv_usec = 0; - perhapsSetRTC(RTCQualityFromNet, &tv); + // Set from phone RTC Quality to RTCQualityNTP since it should be approximately so + perhapsSetRTC(isLocal ? RTCQualityNTP : RTCQualityFromNet, &tv); } nodeDB.updatePosition(getFrom(&mp), p); @@ -94,8 +96,9 @@ meshtastic_MeshPacket *PositionModule::allocReply() // Populate a Position struct with ONLY the requested fields meshtastic_Position p = meshtastic_Position_init_default; // Start with an empty structure + // if localPosition is totally empty, put our last saved position (lite) in there if (localPosition.latitude_i == 0 && localPosition.longitude_i == 0) { - localPosition = ConvertToPosition(node->position); + nodeDB.setLocalPosition(ConvertToPosition(node->position)); } localPosition.seq_number++; @@ -184,6 +187,8 @@ void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t cha } } +#define RUNONCE_INTERVAL 5000; + int32_t PositionModule::runOnce() { if (sleepOnNextExecution == true) { @@ -199,60 +204,58 @@ int32_t PositionModule::runOnce() uint32_t now = millis(); uint32_t intervalMs = getConfiguredOrDefaultMs(config.position.position_broadcast_secs, default_broadcast_interval_secs); uint32_t msSinceLastSend = now - lastGpsSend; + // Only send packets if the channel util. is less than 25% utilized or we're a tracker with less than 40% utilized. + if (!airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER)) { + return RUNONCE_INTERVAL; + } if (lastGpsSend == 0 || msSinceLastSend >= intervalMs) { - // Only send packets if the channel is less than 40% utilized. - if (airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER)) { - if (hasValidPosition(node)) { - lastGpsSend = now; + if (hasValidPosition(node)) { + lastGpsSend = now; - lastGpsLatitude = node->position.latitude_i; - lastGpsLongitude = node->position.longitude_i; + lastGpsLatitude = node->position.latitude_i; + lastGpsLongitude = node->position.longitude_i; - // If we changed channels, ask everyone else for their latest info + // If we changed channels, ask everyone else for their latest info + bool requestReplies = currentGeneration != radioGeneration; + currentGeneration = radioGeneration; + + LOG_INFO("Sending pos@%x:6 to mesh (wantReplies=%d)\n", localPosition.timestamp, requestReplies); + sendOurPosition(NODENUM_BROADCAST, requestReplies); + } + } else if (config.position.position_broadcast_smart_enabled) { + const meshtastic_NodeInfoLite *node2 = service.refreshLocalMeshNode(); // should guarantee there is now a position + + if (hasValidPosition(node2)) { + // The minimum time (in seconds) that would pass before we are able to send a new position packet. + const uint32_t minimumTimeThreshold = + getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30); + + auto smartPosition = getDistanceTraveledSinceLastSend(node->position); + + if (smartPosition.hasTraveledOverThreshold && msSinceLastSend >= minimumTimeThreshold) { bool requestReplies = currentGeneration != radioGeneration; currentGeneration = radioGeneration; - LOG_INFO("Sending pos@%x:6 to mesh (wantReplies=%d)\n", localPosition.timestamp, requestReplies); + LOG_INFO("Sending smart pos@%x:6 to mesh (distanceTraveled=%fm, minDistanceThreshold=%im, timeElapsed=%ims, " + "minTimeInterval=%ims)\n", + localPosition.timestamp, smartPosition.distanceTraveled, smartPosition.distanceThreshold, + msSinceLastSend, minimumTimeThreshold); sendOurPosition(NODENUM_BROADCAST, requestReplies); - } - } - } else if (config.position.position_broadcast_smart_enabled) { - // Only send packets if the channel is less than 25% utilized or we're a tracker. - if (airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER)) { - const meshtastic_NodeInfoLite *node2 = service.refreshLocalMeshNode(); // should guarantee there is now a position - if (hasValidPosition(node2)) { - // The minimum time (in seconds) that would pass before we are able to send a new position packet. - const uint32_t minimumTimeThreshold = - getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30); + // Set the current coords as our last ones, after we've compared distance with current and decided to send + lastGpsLatitude = node->position.latitude_i; + lastGpsLongitude = node->position.longitude_i; - auto smartPosition = getDistanceTraveledSinceLastSend(node->position); - - if (smartPosition.hasTraveledOverThreshold && msSinceLastSend >= minimumTimeThreshold) { - bool requestReplies = currentGeneration != radioGeneration; - currentGeneration = radioGeneration; - - LOG_INFO("Sending smart pos@%x:6 to mesh (distanceTraveled=%fm, minDistanceThreshold=%im, timeElapsed=%ims, " - "minTimeInterval=%ims)\n", - localPosition.timestamp, smartPosition.distanceTraveled, smartPosition.distanceThreshold, - msSinceLastSend, minimumTimeThreshold); - sendOurPosition(NODENUM_BROADCAST, requestReplies); - - // Set the current coords as our last ones, after we've compared distance with current and decided to send - lastGpsLatitude = node->position.latitude_i; - lastGpsLongitude = node->position.longitude_i; - - /* Update lastGpsSend to now. This means if the device is stationary, then - getPref_position_broadcast_secs will still apply. - */ - lastGpsSend = now; - } + /* Update lastGpsSend to now. This means if the device is stationary, then + getPref_position_broadcast_secs will still apply. + */ + lastGpsSend = now; } } } - return 5000; // to save power only wake for our callback occasionally + return RUNONCE_INTERVAL; // to save power only wake for our callback occasionally } struct SmartPosition PositionModule::getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition) @@ -264,6 +267,23 @@ struct SmartPosition PositionModule::getDistanceTraveledSinceLastSend(meshtastic float distanceTraveledSinceLastSend = GeoCoord::latLongToMeter( lastGpsLatitude * 1e-7, lastGpsLongitude * 1e-7, currentPosition.latitude_i * 1e-7, currentPosition.longitude_i * 1e-7); +#ifdef GPS_EXTRAVERBOSE + LOG_DEBUG("--------LAST POSITION------------------------------------\n"); + LOG_DEBUG("lastGpsLatitude=%i, lastGpsLatitude=%i\n", lastGpsLatitude, lastGpsLongitude); + + LOG_DEBUG("--------CURRENT POSITION---------------------------------\n"); + LOG_DEBUG("currentPosition.latitude_i=%i, currentPosition.longitude_i=%i\n", lastGpsLatitude, lastGpsLongitude); + + LOG_DEBUG("--------SMART POSITION-----------------------------------\n"); + LOG_DEBUG("hasTraveledOverThreshold=%i, distanceTraveled=%d, distanceThreshold=% u\n", + abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold, abs(distanceTraveledSinceLastSend), + distanceTravelThreshold); + + if (abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold) { + LOG_DEBUG("\n\n\nSMART SEEEEEEEEENDING\n\n\n"); + } +#endif + return SmartPosition{.distanceTraveled = abs(distanceTraveledSinceLastSend), .distanceThreshold = distanceTravelThreshold, .hasTraveledOverThreshold = abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold};