From 9a414d9c77327f6030c050d2e0dbb8877241ae78 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 12 Oct 2020 08:13:32 +0800 Subject: [PATCH 1/5] fix my breakage of screen waking --- src/graphics/Screen.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 96e18ac5b..e4007aeac 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -202,7 +202,7 @@ class Screen : public concurrency::OSThread return true; // claim success if our display is not in use else { bool success = cmdQueue.enqueue(cmd, 0); - setInterval(0); // handle ASAP + enabled = true; // handle ASAP (we are the registered reader for cmdQueue, but might have been disabled) return success; } } From a8e4bbbe656c950b5478fb46772c70f5c7e86957 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 12 Oct 2020 08:25:17 +0800 Subject: [PATCH 2/5] fix my breaking of button press behavior --- platformio.ini | 2 +- src/concurrency/InterruptableDelay.cpp | 22 ++--- src/main.cpp | 106 +++++++++++++++---------- 3 files changed, 72 insertions(+), 58 deletions(-) diff --git a/platformio.ini b/platformio.ini index dbdf1051f..8109bf0e7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -60,7 +60,7 @@ debug_tool = jlink lib_deps = https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306 - 1260 ; OneButton library for non-blocking button debounce + https://github.com/geeksville/OneButton.git ; OneButton library for non-blocking button debounce 1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib https://github.com/meshtastic/arduino-fsm.git#2f106146071fc7bc620e1e8d4b88dc4e0266ce39 https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad diff --git a/src/concurrency/InterruptableDelay.cpp b/src/concurrency/InterruptableDelay.cpp index e7538235e..80743cc22 100644 --- a/src/concurrency/InterruptableDelay.cpp +++ b/src/concurrency/InterruptableDelay.cpp @@ -4,30 +4,22 @@ namespace concurrency { -InterruptableDelay::InterruptableDelay() -{ -} +InterruptableDelay::InterruptableDelay() {} -InterruptableDelay::~InterruptableDelay() -{ -} +InterruptableDelay::~InterruptableDelay() {} /** * Returns false if we were interrupted */ bool InterruptableDelay::delay(uint32_t msec) { - if (msec) { - // DEBUG_MSG("delay %u ", msec); + // DEBUG_MSG("delay %u ", msec); - // sem take will return false if we timed out (i.e. were not interrupted) - bool r = semaphore.take(msec); + // sem take will return false if we timed out (i.e. were not interrupted) + bool r = semaphore.take(msec); - // DEBUG_MSG("interrupt=%d\n", r); - return !r; - } else { - return true; - } + // DEBUG_MSG("interrupt=%d\n", r); + return !r; } void InterruptableDelay::interrupt() diff --git a/src/main.cpp b/src/main.cpp index 175fbc607..21805e601 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -129,30 +129,11 @@ class PowerFSMThread : public OSThread /// If we are in power state we force the CPU to wake every 10ms to check for serial characters (we don't yet wake /// cpu for serial rx - FIXME) canSleep = (powerFSM.getState() != &statePOWER); - + return 10; } }; -static Periodic *ledPeriodic; -static OSThread *powerFSMthread; - -// Prepare for button presses -#ifdef BUTTON_PIN -OneButton userButton; -#endif -#ifdef BUTTON_PIN_ALT -OneButton userButtonAlt; -#endif -void userButtonPressed() -{ - powerFSM.trigger(EVENT_PRESS); -} -void userButtonPressedLong() -{ - screen->adjustBrightness(); -} - /** * Watch a GPIO and if we get an IRQ, wake the main thread. * Use to add wake on button press @@ -168,6 +149,65 @@ void wakeOnIrq(int irq, int mode) FALLING); } +class ButtonThread : public OSThread +{ +// Prepare for button presses +#ifdef BUTTON_PIN + OneButton userButton; +#endif +#ifdef BUTTON_PIN_ALT + OneButton userButtonAlt; +#endif + + public: + // callback returns the period for the next callback invocation (or 0 if we should no longer be called) + ButtonThread() : OSThread("Button") + { +#ifdef BUTTON_PIN + userButton = OneButton(BUTTON_PIN, true, true); + userButton.attachClick(userButtonPressed); + userButton.attachDuringLongPress(userButtonPressedLong); + wakeOnIrq(BUTTON_PIN, FALLING); +#endif +#ifdef BUTTON_PIN_ALT + userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true); + userButtonAlt.attachClick(userButtonPressed); + userButton.attachDuringLongPress(userButtonPressedLong); + wakeOnIrq(BUTTON_PIN_ALT, FALLING); +#endif + } + + protected: + /// If the button is pressed we suppress CPU sleep until release + int32_t runOnce() + { + canSleep = true; // Assume we should not keep the board awake + +#ifdef BUTTON_PIN + userButton.tick(); + canSleep &= userButton.isIdle(); +#endif +#ifdef BUTTON_PIN_ALT + userButtonAlt.tick(); + canSleep &= userButton.isIdle(); +#endif + // if(!canSleep) DEBUG_MSG("Supressing sleep!\n"); + + return 5; + } + + private: + static void userButtonPressed() + { + // DEBUG_MSG("press!\n"); + powerFSM.trigger(EVENT_PRESS); + } + static void userButtonPressedLong() { screen->adjustBrightness(); } +}; + +static Periodic *ledPeriodic; +static OSThread *powerFSMthread, *buttonThread; + RadioInterface *rIf = NULL; void setup() @@ -210,18 +250,7 @@ void setup() #endif // Buttons & LED -#ifdef BUTTON_PIN - userButton = OneButton(BUTTON_PIN, true, true); - userButton.attachClick(userButtonPressed); - userButton.attachDuringLongPress(userButtonPressedLong); - wakeOnIrq(BUTTON_PIN, FALLING); -#endif -#ifdef BUTTON_PIN_ALT - userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true); - userButtonAlt.attachClick(userButtonPressed); - userButton.attachDuringLongPress(userButtonPressedLong); - wakeOnIrq(BUTTON_PIN_ALT, FALLING); -#endif + buttonThread = new ButtonThread(); #ifdef LED_PIN pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, 1 ^ LED_INVERTED); // turn on for now @@ -410,13 +439,6 @@ void loop() esp32Loop(); #endif -#ifdef BUTTON_PIN - userButton.tick(); -#endif -#ifdef BUTTON_PIN_ALT - userButtonAlt.tick(); -#endif - // For debugging // if (rIf) ((RadioLibInterface *)rIf)->isActivelyReceiving(); @@ -437,9 +459,9 @@ void loop() /* if (mainController.nextThread && delayMsec) DEBUG_MSG("Next %s in %ld\n", mainController.nextThread->ThreadName.c_str(), - mainController.nextThread->tillRun(millis())); - */ - + mainController.nextThread->tillRun(millis())); */ + // We want to sleep as long as possible here - because it saves power mainDelay.delay(delayMsec); + // if (didWake) DEBUG_MSG("wake!\n"); } From 45a36f5571bf7d26aa60113c38b9bbd4bbeb5083 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 12 Oct 2020 09:27:07 +0800 Subject: [PATCH 3/5] fix POWER state entry/exit based on loss of USB power (tx @mc-hamster) --- src/Power.cpp | 61 ++++++++++++++++++++++++------------------------ src/PowerFSM.cpp | 11 ++++++++- src/PowerFSM.h | 2 +- src/main.cpp | 3 ++- 4 files changed, 43 insertions(+), 34 deletions(-) diff --git a/src/Power.cpp b/src/Power.cpp index 162047fa3..731bf7c7c 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -138,39 +138,38 @@ int32_t Power::runOnce() { readPowerStatus(); -#ifdef PMU_IRQ - if (pmu_irq) { - pmu_irq = false; - axp.readIRQ(); + // WE no longer use the IRQ line to wake the CPU (due to false wakes from sleep), but we do poll + // the IRQ status by reading the registers over I2C + axp.readIRQ(); - DEBUG_MSG("pmu irq!\n"); - - if (axp.isChargingIRQ()) { - DEBUG_MSG("Battery start charging\n"); - } - if (axp.isChargingDoneIRQ()) { - DEBUG_MSG("Battery fully charged\n"); - } - if (axp.isVbusRemoveIRQ()) { - DEBUG_MSG("USB unplugged\n"); - powerFSM.trigger(EVENT_POWER_DISCONNECTED); - } - if (axp.isVbusPlugInIRQ()) { - DEBUG_MSG("USB plugged In\n"); - powerFSM.trigger(EVENT_POWER_CONNECTED); - } - if (axp.isBattPlugInIRQ()) { - DEBUG_MSG("Battery inserted\n"); - } - if (axp.isBattRemoveIRQ()) { - DEBUG_MSG("Battery removed\n"); - } - if (axp.isPEKShortPressIRQ()) { - DEBUG_MSG("PEK short button press\n"); - } - axp.clearIRQ(); + if (axp.isVbusRemoveIRQ()) { + DEBUG_MSG("USB unplugged\n"); + powerFSM.trigger(EVENT_POWER_DISCONNECTED); } -#endif + if (axp.isVbusPlugInIRQ()) { + DEBUG_MSG("USB plugged In\n"); + powerFSM.trigger(EVENT_POWER_CONNECTED); + } + /* + Other things we could check if we cared... + + if (axp.isChargingIRQ()) { + DEBUG_MSG("Battery start charging\n"); + } + if (axp.isChargingDoneIRQ()) { + DEBUG_MSG("Battery fully charged\n"); + } + if (axp.isBattPlugInIRQ()) { + DEBUG_MSG("Battery inserted\n"); + } + if (axp.isBattRemoveIRQ()) { + DEBUG_MSG("Battery removed\n"); + } + if (axp.isPEKShortPressIRQ()) { + DEBUG_MSG("PEK short button press\n"); + } + */ + axp.clearIRQ(); // Only read once every 20 seconds once the power status for the app has been initialized return (statusHandler && statusHandler->isInitialized()) ? (1000 * 20) : RUN_SAME; diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index ede68258c..454a8bdfd 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -118,12 +118,21 @@ static void serialEnter() { setBluetoothEnable(false); screen->setOn(true); + screen->print("Using API...\n"); } static void powerEnter() { screen->setOn(true); setBluetoothEnable(true); + screen->print("Powered...\n"); +} + +static void powerExit() +{ + screen->setOn(true); + setBluetoothEnable(true); + screen->print("Unpowered...\n"); } static void onEnter() @@ -156,7 +165,7 @@ State stateDARK(darkEnter, NULL, NULL, "DARK"); State stateSERIAL(serialEnter, NULL, NULL, "SERIAL"); State stateBOOT(bootEnter, NULL, NULL, "BOOT"); State stateON(onEnter, NULL, NULL, "ON"); -State statePOWER(powerEnter, NULL, NULL, "POWER"); +State statePOWER(powerEnter, NULL, powerExit, "POWER"); Fsm powerFSM(&stateBOOT); void PowerFSM_setup() diff --git a/src/PowerFSM.h b/src/PowerFSM.h index d996acbd3..4af62040c 100644 --- a/src/PowerFSM.h +++ b/src/PowerFSM.h @@ -20,6 +20,6 @@ #define EVENT_POWER_DISCONNECTED 14 extern Fsm powerFSM; -extern State statePOWER; +extern State statePOWER, stateSERIAL; void PowerFSM_setup(); diff --git a/src/main.cpp b/src/main.cpp index 21805e601..f082c8f7a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -128,7 +128,8 @@ class PowerFSMThread : public OSThread /// If we are in power state we force the CPU to wake every 10ms to check for serial characters (we don't yet wake /// cpu for serial rx - FIXME) - canSleep = (powerFSM.getState() != &statePOWER); + auto state = powerFSM.getState(); + canSleep = (state != &statePOWER) && (state != &stateSERIAL); return 10; } From 66a7f896c8fccdc2312ba29d61e2c27bdba0548f Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 12 Oct 2020 09:27:48 +0800 Subject: [PATCH 4/5] 1.1.4 --- bin/version.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/version.sh b/bin/version.sh index feeef0162..ef346111c 100644 --- a/bin/version.sh +++ b/bin/version.sh @@ -1,3 +1,3 @@ -export VERSION=1.1.3 \ No newline at end of file +export VERSION=1.1.4 \ No newline at end of file From a9de8b9bb33b35fdcf08d4f1ce34457b43950c05 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 12 Oct 2020 09:33:15 +0800 Subject: [PATCH 5/5] oops - only read axp on boards that have it --- src/Power.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Power.cpp b/src/Power.cpp index 731bf7c7c..12a638119 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -138,6 +138,7 @@ int32_t Power::runOnce() { readPowerStatus(); +#ifdef TBEAM_V10 // WE no longer use the IRQ line to wake the CPU (due to false wakes from sleep), but we do poll // the IRQ status by reading the registers over I2C axp.readIRQ(); @@ -170,6 +171,7 @@ int32_t Power::runOnce() } */ axp.clearIRQ(); +#endif // Only read once every 20 seconds once the power status for the app has been initialized return (statusHandler && statusHandler->isInitialized()) ? (1000 * 20) : RUN_SAME;