diff --git a/docs/software/power.md b/docs/software/power.md index cd0d2c913..e98e5bd0d 100644 --- a/docs/software/power.md +++ b/docs/software/power.md @@ -32,11 +32,15 @@ From lower to higher power consumption. onEntry: setBluetoothOn(true) onExit: -- full on (ON) - Everything is on +- serial API usage (SERIAL) - Screen is on, device doesn't sleep, bluetooth off + onEntry: setBluetooth off, screen on + onExit: + +- full on (ON) - Everything is on, can eventually timeout and lower to a lower power state onEntry: setBluetoothOn(true), screen.setOn(true) onExit: screen.setOn(false) -- serial API usage (SERIAL) - Screen is on, device doesn't sleep, bluetooth off +- has power (POWER) - Screen is on, device doesn't sleep, bluetooth on, will stay in this state as long as we have power onEntry: setBluetooth off, screen on onExit: @@ -56,9 +60,11 @@ From lower to higher power consumption. - While in NB/DARK/ON: If we receive EVENT_NODEDB_UPDATED we transition to ON (so the new screen can be shown) - While in DARK: While the phone talks to us over BLE (EVENT_CONTACT_FROM_PHONE) reset any sleep timers and stay in DARK (needed for bluetooth sw update and nice user experience if the user is reading/replying to texts) - while in LS/NB/DARK: if SERIAL_CONNECTED, go to serial +- while in any state: if we have AC power, go to POWER ### events that decrease cpu activity +- While in POWER: if lose AC go to ON - While in SERIAL: if SERIAL_DISCONNECTED, go to NB - While in ON: If PRESS event occurs, reset screen_on_secs timer and tell the screen to handle the pess - While in ON: If it has been more than screen_on_secs since a press, lower to DARK diff --git a/src/Power.cpp b/src/Power.cpp index 1145c51c4..7d032b666 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -119,6 +119,7 @@ void Power::readPowerStatus() const PowerStatus powerStatus = PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVBUSPlug() ? OptTrue : OptFalse, batteryLevel->isChargeing() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent); + DEBUG_MSG("Read power stat %d\n", powerStatus.getHasUSB()); newStatus.notifyObservers(&powerStatus); // If we have a battery at all and it is less than 10% full, force deep sleep @@ -237,9 +238,11 @@ void Power::loop() } 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"); diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index 128947bcd..f72e5842a 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -4,8 +4,8 @@ #include "MeshService.h" #include "NodeDB.h" #include "configuration.h" -#include "main.h" #include "graphics/Screen.h" +#include "main.h" #include "sleep.h" #include "target_specific.h" @@ -123,6 +123,12 @@ static void serialEnter() screen.setOn(true); } +static void powerEnter() +{ + screen.setOn(true); + setBluetoothEnable(true); +} + static void onEnter() { screen.setOn(true); @@ -155,16 +161,20 @@ 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"); Fsm powerFSM(&stateBOOT); void PowerFSM_setup() { - powerFSM.add_timed_transition(&stateBOOT, &stateON, 3 * 1000, NULL, "boot timeout"); + // If we already have AC power go to POWER state after init, otherwise go to ON + bool hasPower = powerStatus && powerStatus->getHasUSB(); + DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower); + powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout"); powerFSM.add_transition(&stateLS, &stateDARK, EVENT_WAKE_TIMER, wakeForPing, "Wake timer"); - // Note we don't really use this transition, because when we wake from light sleep we _always_ transition to NB and then it - // handles things powerFSM.add_transition(&stateLS, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet"); + // Note we don't really use this transition, because when we wake from light sleep we _always_ transition to NB and then + // it handles things powerFSM.add_transition(&stateLS, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet"); powerFSM.add_transition(&stateNB, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet, resetting win wake"); @@ -172,7 +182,10 @@ void PowerFSM_setup() powerFSM.add_transition(&stateLS, &stateON, EVENT_PRESS, NULL, "Press"); powerFSM.add_transition(&stateNB, &stateON, EVENT_PRESS, NULL, "Press"); powerFSM.add_transition(&stateDARK, &stateON, EVENT_PRESS, NULL, "Press"); + powerFSM.add_transition(&statePOWER, &statePOWER, EVENT_PRESS, screenPress, "Press"); powerFSM.add_transition(&stateON, &stateON, EVENT_PRESS, screenPress, "Press"); // reenter On to restart our timers + powerFSM.add_transition(&stateSERIAL, &stateSERIAL, EVENT_PRESS, screenPress, + "Press"); // Allow button to work while in serial API // Handle critically low power battery by forcing deep sleep powerFSM.add_transition(&stateBOOT, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); @@ -199,6 +212,14 @@ void PowerFSM_setup() powerFSM.add_transition(&stateDARK, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API"); powerFSM.add_transition(&stateON, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API"); + powerFSM.add_transition(&stateLS, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect"); + powerFSM.add_transition(&stateNB, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect"); + powerFSM.add_transition(&stateDARK, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect"); + powerFSM.add_transition(&stateON, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect"); + + powerFSM.add_transition(&statePOWER, &stateON, EVENT_POWER_DISCONNECTED, NULL, "power disconnected"); + powerFSM.add_transition(&stateSERIAL, &stateON, EVENT_POWER_DISCONNECTED, NULL, "power disconnected"); + powerFSM.add_transition(&stateSERIAL, &stateNB, EVENT_SERIAL_DISCONNECTED, NULL, "serial disconnect"); powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone"); diff --git a/src/PowerFSM.h b/src/PowerFSM.h index c89ad9148..4a219f570 100644 --- a/src/PowerFSM.h +++ b/src/PowerFSM.h @@ -13,9 +13,11 @@ #define EVENT_BLUETOOTH_PAIR 7 #define EVENT_NODEDB_UPDATED 8 // NodeDB has a big enough change that we think you should turn on the screen #define EVENT_CONTACT_FROM_PHONE 9 // the phone just talked to us over bluetooth -#define EVENT_LOW_BATTERY 10 // Battery is critically low, go to sleep +#define EVENT_LOW_BATTERY 10 // Battery is critically low, go to sleep #define EVENT_SERIAL_CONNECTED 11 #define EVENT_SERIAL_DISCONNECTED 12 +#define EVENT_POWER_CONNECTED 13 +#define EVENT_POWER_DISCONNECTED 14 extern Fsm powerFSM; diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp index 683886ed5..f246b607c 100644 --- a/src/SerialConsole.cpp +++ b/src/SerialConsole.cpp @@ -40,6 +40,8 @@ void SerialConsole::onConnectionChanged(bool connected) if (connected) { // To prevent user confusion, turn off bluetooth while using the serial port api powerFSM.trigger(EVENT_SERIAL_CONNECTED); } else { + // FIXME, we get no notice of serial going away, we should instead automatically generate this event if we haven't + // received a packet in a while powerFSM.trigger(EVENT_SERIAL_DISCONNECTED); } } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 207ae7b12..dc188809d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -213,9 +213,9 @@ void setup() // Currently only the tbeam has a PMU power = new Power(); - power->setup(); power->setStatusHandler(powerStatus); powerStatus->observe(&power->newStatus); + power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration #ifdef NRF52_SERIES nrf52Setup();