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 1/3] 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 b8c70292c6..b9c7586e4b 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 9ccd28aba4..547d7f59e2 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 524f8035f6..833e058d84 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 9d0468e703..532aad519b 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 2/3] 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 87cda5c4b0..025e6007ba 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 532aad519b..da3e43dcb7 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 3/3] 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 791a4194b1..f369f873f6 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);