From a05e45f84bd45ef50097213336b0dc91eec801a9 Mon Sep 17 00:00:00 2001 From: geeksville Date: Tue, 9 Jun 2020 15:47:05 -0700 Subject: [PATCH 1/5] make txQueue private --- src/mesh/RadioInterface.cpp | 2 +- src/mesh/RadioInterface.h | 1 - src/mesh/RadioLibInterface.h | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index c7edf74de..43d9a6696 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -24,7 +24,7 @@ separated by 2.16 MHz with respect to the adjacent channels. Channel zero starts // 1kb was too small #define RADIO_STACK_SIZE 4096 -RadioInterface::RadioInterface() : txQueue(MAX_TX_QUEUE) +RadioInterface::RadioInterface() { assert(sizeof(PacketHeader) == 4 || sizeof(PacketHeader) == 16); // make sure the compiler did what we expected diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 64222a76a..0617592ac 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -59,7 +59,6 @@ class RadioInterface : protected NotifiedWorkerThread protected: MeshPacket *sendingPacket = NULL; // The packet we are currently sending - PointerQueue txQueue; uint32_t lastTxStart = 0L; /** diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index 1a0e5f450..6619337ba 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -29,6 +29,8 @@ class RadioLibInterface : public RadioInterface, private PeriodicTask */ uint32_t rxBad = 0, rxGood = 0, txGood = 0; + PointerQueue txQueue = PointerQueue(MAX_TX_QUEUE); + protected: float bw = 125; uint8_t sf = 9; From 00d55c9daa715efc78f1a2aaa42d03d5f6c3b727 Mon Sep 17 00:00:00 2001 From: geeksville Date: Tue, 9 Jun 2020 18:20:06 -0700 Subject: [PATCH 2/5] require min app version 172 --- src/mesh/NodeDB.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 86b5bda84..37233a3a0 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -124,7 +124,7 @@ void NodeDB::init() // default to no GPS, until one has been found by probing myNodeInfo.has_gps = false; myNodeInfo.message_timeout_msec = FLOOD_EXPIRE_TIME; - myNodeInfo.min_app_version = 167; + myNodeInfo.min_app_version = 172; generatePacketId(); // FIXME - ugly way to init current_packet_id; // Init our blank owner info to reasonable defaults From 21a90a42e56842a3b185b1dc6552e61460cd3791 Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 10 Jun 2020 14:02:53 -0700 Subject: [PATCH 3/5] move flutter ideas into own project --- docs/software/nrf52-TODO.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/software/nrf52-TODO.md b/docs/software/nrf52-TODO.md index 500180d03..55b781d23 100644 --- a/docs/software/nrf52-TODO.md +++ b/docs/software/nrf52-TODO.md @@ -59,8 +59,6 @@ Needed to be fully functional at least at the same level of the ESP32 boards. At Nice ideas worth considering someday... -- Use flego to me an iOS/linux app? https://felgo.com/doc/qt/qtbluetooth-index/ or -- Use flutter to make an iOS/linux app? https://github.com/Polidea/FlutterBleLib - enable monitor mode debugging (need to use real jlink): https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/monitor-mode-debugging-with-j-link-and-gdbeclipse - Improve efficiency of PeriodicTimer by only checking the next queued timer event, and carefully sorting based on schedule - make a Mfg Controller and device under test classes as examples of custom app code for third party devs. Make a post about this. Use a custom payload type code. Have device under test send a broadcast with max hopcount of 0 for the 'mfgcontroller' payload type. mfg controller will read SNR and reply. DOT will declare failure/success and switch to the regular app screen. From ddfdae64bf479d4bf5a5328923ad07298811a5a4 Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 10 Jun 2020 14:11:43 -0700 Subject: [PATCH 4/5] Fix #167 while in light sleep, allow loop() to still run occasionally --- src/PowerFSM.cpp | 65 ++++++++++++++++++---------------- src/mesh/RadioLibInterface.cpp | 8 +++-- src/sleep.cpp | 4 +-- src/sleep.h | 3 ++ 4 files changed, 46 insertions(+), 34 deletions(-) diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index 1e9adbec9..8f67b148c 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -26,60 +26,65 @@ static void sdsEnter() #include "error.h" +static uint32_t secsSlept; + static void lsEnter() { DEBUG_MSG("lsEnter begin, ls_secs=%u\n", radioConfig.preferences.ls_secs); screen.setOn(false); + secsSlept = 0; // How long have we been sleeping this time DEBUG_MSG("lsEnter end\n"); } static void lsIdle() { - DEBUG_MSG("lsIdle begin ls_secs=%u\n", radioConfig.preferences.ls_secs); + // DEBUG_MSG("lsIdle begin ls_secs=%u\n", radioConfig.preferences.ls_secs); #ifndef NO_ESP32 - uint32_t secsSlept = 0; esp_sleep_source_t wakeCause = ESP_SLEEP_WAKEUP_UNDEFINED; - bool reached_ls_secs = false; - while (!reached_ls_secs) { + // Do we have more sleeping to do? + if (secsSlept < radioConfig.preferences.ls_secs) { // Briefly come out of sleep long enough to blink the led once every few seconds - uint32_t sleepTime = 5; + uint32_t sleepTime = 30; - setLed(false); // Never leave led on while in light sleep - wakeCause = doLightSleep(sleepTime * 1000LL); - if (wakeCause != ESP_SLEEP_WAKEUP_TIMER) - break; + // If some other service would stall sleep, don't let sleep happen yet + if (doPreflightSleep()) { + setLed(false); // Never leave led on while in light sleep + wakeCause = doLightSleep(sleepTime * 1000LL); - setLed(true); // briefly turn on led - doLightSleep(1); - if (wakeCause != ESP_SLEEP_WAKEUP_TIMER) - break; + if (wakeCause == ESP_SLEEP_WAKEUP_TIMER) { + // Normal case: timer expired, we should just go back to sleep ASAP - secsSlept += sleepTime; - reached_ls_secs = secsSlept >= radioConfig.preferences.ls_secs; - } - setLed(false); + setLed(true); // briefly turn on led + wakeCause = doLightSleep(1); // leave led on for 1ms - if (reached_ls_secs) { - // stay in LS mode but let loop check whatever it wants - DEBUG_MSG("reached ls_secs, servicing loop()\n"); - } else { - DEBUG_MSG("wakeCause %d\n", wakeCause); + secsSlept += sleepTime; + // DEBUG_MSG("sleeping, flash led!\n"); + } else { + // We woke for some other reason (button press, uart, device interrupt) + DEBUG_MSG("wakeCause %d\n", wakeCause); #ifdef BUTTON_PIN - bool pressed = !digitalRead(BUTTON_PIN); + bool pressed = !digitalRead(BUTTON_PIN); #else - bool pressed = false; + bool pressed = false; #endif - if (pressed) // If we woke because of press, instead generate a PRESS event. - { - powerFSM.trigger(EVENT_PRESS); - } else { - // Otherwise let the NB state handle the IRQ (and that state will handle stuff like IRQs etc) - powerFSM.trigger(EVENT_WAKE_TIMER); + if (pressed) // If we woke because of press, instead generate a PRESS event. + { + powerFSM.trigger(EVENT_PRESS); + } else { + // Otherwise let the NB state handle the IRQ (and that state will handle stuff like IRQs etc) + powerFSM.trigger(EVENT_WAKE_TIMER); + } + } } + } else { + // Time to stop sleeping! + setLed(false); + DEBUG_MSG("reached ls_secs, servicing loop()\n"); + powerFSM.trigger(EVENT_WAKE_TIMER); } #endif } diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 53f99aae9..5239f8f60 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -134,7 +134,7 @@ bool RadioLibInterface::canSleep() { bool res = txQueue.isEmpty(); if (!res) // only print debug messages if we are vetoing sleep - DEBUG_MSG("radio wait to sleep, txEmpty=%d\n", txQueue.isEmpty()); + DEBUG_MSG("radio wait to sleep, txEmpty=%d\n", res); return res; } @@ -173,11 +173,13 @@ void RadioLibInterface::loop() case ISR_TX: handleTransmitInterrupt(); startReceive(); + // DEBUG_MSG("tx complete - starting timer\n"); startTransmitTimer(); break; case ISR_RX: handleReceiveInterrupt(); startReceive(); + // DEBUG_MSG("rx complete - starting timer\n"); startTransmitTimer(); break; case TRANSMIT_DELAY_COMPLETED: @@ -192,6 +194,8 @@ void RadioLibInterface::loop() assert(txp); startSend(txp); } + } else { + // DEBUG_MSG("done with txqueue\n"); } break; default: @@ -216,7 +220,7 @@ void RadioLibInterface::startTransmitTimer(bool withDelay) uint32_t delay = !withDelay ? 1 : random(MIN_TX_WAIT_MSEC, MAX_TX_WAIT_MSEC); // See documentation for loop() wrt these values // DEBUG_MSG("xmit timer %d\n", delay); - + // DEBUG_MSG("delaying %u\n", delay); setPeriod(delay); } } diff --git a/src/sleep.cpp b/src/sleep.cpp index 18462de79..ceb21404c 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -111,8 +111,8 @@ void initDeepSleep() #endif } -/// return true if sleep is allowed -static bool doPreflightSleep() + +bool doPreflightSleep() { if (preflightSleep.notifyObservers(NULL) != 0) return false; // vetoed diff --git a/src/sleep.h b/src/sleep.h index b3446882a..66eafa611 100644 --- a/src/sleep.h +++ b/src/sleep.h @@ -19,6 +19,9 @@ void initDeepSleep(); void setCPUFast(bool on); void setLed(bool ledOn); +/** return true if sleep is allowed right now */ +bool doPreflightSleep(); + extern int bootCount; // is bluetooth sw currently running? From 8ccd59a7d8df2410c991fac1ea16f8f298b94166 Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 10 Jun 2020 14:36:11 -0700 Subject: [PATCH 5/5] Fix #115: wake from light sleep if a character arrives on the serial port Note - we do this not by using the uart wake feature, but by the lower power GPIO edge feature. Recommend sending "Z" 0x5A - because that has many edges. Send the character 4 times to make sure the device is awake --- src/PowerFSM.cpp | 5 +++++ src/configuration.h | 3 +++ src/sleep.cpp | 13 ++++++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index 8f67b148c..c495cd27f 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -62,8 +62,13 @@ static void lsIdle() secsSlept += sleepTime; // DEBUG_MSG("sleeping, flash led!\n"); + } + if (wakeCause == ESP_SLEEP_WAKEUP_UART) { + // Not currently used (because uart triggers in hw have problems) + powerFSM.trigger(EVENT_SERIAL_CONNECTED); } else { // We woke for some other reason (button press, uart, device interrupt) + //uint64_t status = esp_sleep_get_ext1_wakeup_status(); DEBUG_MSG("wakeCause %d\n", wakeCause); #ifdef BUTTON_PIN diff --git a/src/configuration.h b/src/configuration.h index bc64d3187..4759dfc73 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -258,7 +258,10 @@ along with this program. If not, see . #ifdef NO_ESP32 #define USE_SEGGER +#else +#define SERIAL0_RX_GPIO 3 // Always GPIO3 on ESP32 #endif + #ifdef USE_SEGGER #include "SEGGER_RTT.h" #define DEBUG_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__) diff --git a/src/sleep.cpp b/src/sleep.cpp index ceb21404c..8cb0f6798 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -14,6 +14,7 @@ #include "esp_pm.h" #include "rom/rtc.h" #include +#include #include "BluetoothUtil.h" @@ -111,7 +112,6 @@ void initDeepSleep() #endif } - bool doPreflightSleep() { if (preflightSleep.notifyObservers(NULL) != 0) @@ -257,6 +257,17 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r gpio_pullup_en((gpio_num_t)BUTTON_PIN); #endif +#ifdef SERIAL0_RX_GPIO + // We treat the serial port as a GPIO for a fast/low power way of waking, if we see a rising edge that means + // someone started to send something + + // Alas - doesn't work reliably, instead need to use the uart specific version (which burns a little power) + // FIXME: gpio 3 is RXD for serialport 0 on ESP32 + // Send a few Z characters to wake the port + gpio_wakeup_enable((gpio_num_t)SERIAL0_RX_GPIO, GPIO_INTR_LOW_LEVEL); + // uart_set_wakeup_threshold(UART_NUM_0, 3); + // esp_sleep_enable_uart_wakeup(0); +#endif #ifdef BUTTON_PIN gpio_wakeup_enable((gpio_num_t)BUTTON_PIN, GPIO_INTR_LOW_LEVEL); // when user presses, this button goes low #endif