meshtastic-firmware/src/PowerFSM.cpp

196 wiersze
6.9 KiB
C++
Czysty Zwykły widok Historia

2020-02-22 20:01:59 +00:00
#include "PowerFSM.h"
#include "GPS.h"
2020-02-22 20:01:59 +00:00
#include "MeshService.h"
#include "NodeDB.h"
#include "configuration.h"
#include "main.h"
#include "screen.h"
#include "sleep.h"
2020-02-22 20:01:59 +00:00
static void sdsEnter()
{
/*
// Don't deepsleep if we have USB power or if the user as pressed a button recently
// !isUSBPowered <- doesn't work yet because the axp192 isn't letting the battery fully charge when we are awake - FIXME
if (millis() - lastPressMs > radioConfig.preferences.mesh_sds_timeout_secs)
{
doDeepSleep(radioConfig.preferences.sds_secs);
}
*/
doDeepSleep(radioConfig.preferences.sds_secs * 1000LL);
}
#include "error.h"
2020-02-22 20:01:59 +00:00
static void lsEnter()
{
DEBUG_MSG("lsEnter begin, ls_secs=%u\n", radioConfig.preferences.ls_secs);
screen.setOn(false);
uint32_t now = millis();
while (!service.radio.rf95.canSleep()) {
2020-02-22 22:45:58 +00:00
delay(10); // 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
recordCriticalError(ErrSleepEnterWait);
break;
}
}
2020-02-22 21:14:10 +00:00
gps.prepareSleep(); // abandon in-process parsing
// if (!isUSBPowered) // FIXME - temp hack until we can put gps in sleep mode, if we have AC when we go to sleep then
// leave GPS on
2020-03-14 03:30:48 +00:00
// setGPSPower(false); // kill GPS power
2020-03-14 05:38:58 +00:00
DEBUG_MSG("lsEnter end\n");
2020-02-22 20:01:59 +00:00
}
static void lsIdle()
{
2020-03-14 05:38:58 +00:00
DEBUG_MSG("lsIdle begin ls_secs=%u\n", radioConfig.preferences.ls_secs);
uint32_t secsSlept = 0;
esp_sleep_source_t wakeCause = ESP_SLEEP_WAKEUP_UNDEFINED;
bool reached_ls_secs = false;
while (!reached_ls_secs) {
// Briefly come out of sleep long enough to blink the led once every few seconds
uint32_t sleepTime = 5;
setLed(false); // Never leave led on while in light sleep
wakeCause = doLightSleep(sleepTime * 1000LL);
if (wakeCause != ESP_SLEEP_WAKEUP_TIMER)
break;
setLed(true); // briefly turn on led
doLightSleep(1);
if (wakeCause != ESP_SLEEP_WAKEUP_TIMER)
break;
2020-02-23 02:02:44 +00:00
secsSlept += sleepTime;
reached_ls_secs = secsSlept >= radioConfig.preferences.ls_secs;
}
setLed(false);
if (reached_ls_secs) {
// stay in LS mode but let loop check whatever it wants
DEBUG_MSG("reached ls_secs, servicing loop()\n");
} else {
2020-03-14 05:38:58 +00:00
DEBUG_MSG("wakeCause %d\n", wakeCause);
if (!digitalRead(BUTTON_PIN)) // 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);
}
}
2020-02-22 20:01:59 +00:00
}
static void lsExit()
{
2020-03-14 03:30:48 +00:00
// setGPSPower(true); // restore GPS power
2020-02-22 21:14:10 +00:00
gps.startLock();
2020-02-22 20:01:59 +00:00
}
static void nbEnter()
{
screen.setOn(false);
2020-02-22 20:01:59 +00:00
setBluetoothEnable(false);
2020-02-22 22:45:58 +00:00
// FIXME - check if we already have packets for phone and immediately trigger EVENT_PACKETS_FOR_PHONE
2020-02-22 20:01:59 +00:00
}
static void darkEnter()
{
2020-02-22 21:14:10 +00:00
screen.setOn(false);
2020-02-22 20:01:59 +00:00
}
static void onEnter()
{
screen.setOn(true);
setBluetoothEnable(true);
static uint32_t lastPingMs;
uint32_t now = millis();
if (now - lastPingMs > 60 * 1000) { // if more than a minute since our last press, ask other nodes to update their state
service.sendNetworkPing(NODENUM_BROADCAST, true);
lastPingMs = now;
}
2020-02-22 20:01:59 +00:00
}
static void wakeForPing() {}
2020-02-22 20:01:59 +00:00
static void screenPress()
{
screen.onPress();
}
static void bootEnter() {}
2020-02-22 21:14:10 +00:00
State stateSDS(sdsEnter, NULL, NULL, "SDS");
State stateLS(lsEnter, lsIdle, lsExit, "LS");
State stateNB(nbEnter, NULL, NULL, "NB");
State stateDARK(darkEnter, NULL, NULL, "DARK");
State stateBOOT(bootEnter, NULL, NULL, "BOOT");
State stateON(onEnter, NULL, NULL, "ON");
Fsm powerFSM(&stateBOOT);
2020-02-22 20:01:59 +00:00
void PowerFSM_setup()
{
powerFSM.add_timed_transition(&stateBOOT, &stateON, 3 * 1000, NULL, "boot timeout");
2020-02-22 21:14:10 +00:00
powerFSM.add_transition(&stateLS, &stateDARK, EVENT_WAKE_TIMER, wakeForPing, "Wake timer");
2020-02-22 22:45:58 +00:00
// 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");
2020-02-22 22:45:58 +00:00
powerFSM.add_transition(&stateNB, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet, resetting win wake");
2020-02-22 21:14:10 +00:00
// Handle press events
powerFSM.add_transition(&stateLS, &stateON, EVENT_PRESS, NULL, "Press");
2020-02-22 21:14:10 +00:00
powerFSM.add_transition(&stateNB, &stateON, EVENT_PRESS, NULL, "Press");
powerFSM.add_transition(&stateDARK, &stateON, EVENT_PRESS, NULL, "Press");
powerFSM.add_transition(&stateON, &stateON, EVENT_PRESS, screenPress, "Press"); // reenter On to restart our timers
2020-02-22 20:01:59 +00:00
powerFSM.add_transition(&stateDARK, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
powerFSM.add_transition(&stateON, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
2020-02-23 02:02:44 +00:00
powerFSM.add_transition(&stateNB, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
powerFSM.add_transition(&stateDARK, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
powerFSM.add_transition(&stateON, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
2020-02-22 21:14:10 +00:00
powerFSM.add_transition(&stateLS, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
powerFSM.add_transition(&stateNB, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
powerFSM.add_transition(&stateDARK, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
powerFSM.add_transition(&stateON, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text"); // restarts the sleep timer
2020-02-22 20:01:59 +00:00
powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone");
2020-02-22 21:14:10 +00:00
powerFSM.add_transition(&stateNB, &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Packet for phone");
2020-02-22 20:01:59 +00:00
powerFSM.add_timed_transition(&stateON, &stateDARK, radioConfig.preferences.screen_on_secs * 1000, NULL, "Screen-on timeout");
2020-02-22 20:01:59 +00:00
powerFSM.add_timed_transition(&stateDARK, &stateNB, radioConfig.preferences.phone_timeout_secs * 1000, NULL, "Phone timeout");
powerFSM.add_timed_transition(&stateNB, &stateLS, radioConfig.preferences.min_wake_secs * 1000, NULL, "Min wake timeout");
powerFSM.add_timed_transition(&stateDARK, &stateLS, radioConfig.preferences.wait_bluetooth_secs * 1000, NULL,
"Bluetooth timeout");
2020-02-22 20:01:59 +00:00
powerFSM.add_timed_transition(&stateLS, &stateSDS, radioConfig.preferences.mesh_sds_timeout_secs * 1000, NULL,
"mesh timeout");
// removing for now, because some users don't even have phones
// powerFSM.add_timed_transition(&stateLS, &stateSDS, radioConfig.preferences.phone_sds_timeout_sec * 1000, NULL, "phone
// timeout");
2020-02-22 21:14:10 +00:00
powerFSM.run_machine(); // run one interation of the state machine, so we run our on enter tasks for the initial DARK state
}