diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index e4cf8fae..39299219 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -37,6 +37,14 @@ static void sdsEnter() doDeepSleep(getPref_sds_secs() * 1000LL); } +extern Power *power; + +static void shutdownEnter() +{ + DEBUG_MSG("Enter state: SHUTDOWN\n"); + power->shutdown(); +} + #include "error.h" static uint32_t secsSlept; @@ -217,6 +225,7 @@ static void bootEnter() { DEBUG_MSG("Enter state: BOOT\n"); } +State stateSHUTDOWN(shutdownEnter, NULL, NULL, "SHUTDOWN"); State stateSDS(sdsEnter, NULL, NULL, "SDS"); State stateLS(lsEnter, lsIdle, lsExit, "LS"); State stateNB(nbEnter, NULL, NULL, "NB"); @@ -260,6 +269,14 @@ void PowerFSM_setup() powerFSM.add_transition(&stateON, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); powerFSM.add_transition(&stateSERIAL, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); + // Handle being told to power off + powerFSM.add_transition(&stateBOOT, &stateSHUTDOWN, EVENT_SHUTDOWN, NULL, "Shutdown"); + powerFSM.add_transition(&stateLS, &stateSHUTDOWN, EVENT_SHUTDOWN, NULL, "Shutdown"); + powerFSM.add_transition(&stateNB, &stateSHUTDOWN, EVENT_SHUTDOWN, NULL, "Shutdown"); + powerFSM.add_transition(&stateDARK, &stateSHUTDOWN, EVENT_SHUTDOWN, NULL, "Shutdown"); + powerFSM.add_transition(&stateON, &stateSHUTDOWN, EVENT_SHUTDOWN, NULL, "Shutdown"); + powerFSM.add_transition(&stateSERIAL, &stateSHUTDOWN, EVENT_SHUTDOWN, NULL, "Shutdown"); + powerFSM.add_transition(&stateDARK, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing"); powerFSM.add_transition(&stateON, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing"); diff --git a/src/PowerFSM.h b/src/PowerFSM.h index 5541385a..2515534b 100644 --- a/src/PowerFSM.h +++ b/src/PowerFSM.h @@ -19,6 +19,7 @@ #define EVENT_POWER_CONNECTED 13 #define EVENT_POWER_DISCONNECTED 14 #define EVENT_FIRMWARE_UPDATE 15 // We just received a new firmware update packet from the phone +#define EVENT_SHUTDOWN 16 //force a full shutdown now (not just sleep) extern Fsm powerFSM; extern State statePOWER, stateSERIAL; diff --git a/src/main.cpp b/src/main.cpp index 4429391d..eafd1956 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -134,6 +134,8 @@ static int32_t ledBlinker() return powerStatus->getIsCharging() ? 1000 : (ledOn ? 1 : 1000); } +uint32_t timeLastPowered = 0; + /// Wrapper to convert our powerFSM stuff into a 'thread' class PowerFSMThread : public OSThread { @@ -151,6 +153,13 @@ class PowerFSMThread : public OSThread auto state = powerFSM.getState(); canSleep = (state != &statePOWER) && (state != &stateSERIAL); + if (powerStatus->getHasUSB()) { + timeLastPowered = millis(); + } else if (radioConfig.preferences.on_battery_shutdown_after_secs > 0 && + millis() > timeLastPowered + (1000 * radioConfig.preferences.on_battery_shutdown_after_secs)) { //shutdown after 30 minutes unpowered + powerFSM.trigger(EVENT_SHUTDOWN); + } + return 10; } }; diff --git a/src/mesh/generated/radioconfig.pb.h b/src/mesh/generated/radioconfig.pb.h index 4cbb693b..ae13b867 100644 --- a/src/mesh/generated/radioconfig.pb.h +++ b/src/mesh/generated/radioconfig.pb.h @@ -151,6 +151,7 @@ typedef struct _RadioConfig_UserPreferences { uint32_t position_flags; bool is_always_powered; uint32_t auto_screen_carousel_secs; + uint32_t on_battery_shutdown_after_secs; } RadioConfig_UserPreferences; typedef struct _RadioConfig { @@ -195,9 +196,9 @@ extern "C" { /* Initializer values for message structs */ #define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default} -#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, 0, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, "", 0, _GpsCoordinateFormat_MIN, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0, 0, 0, 0, 0} +#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, 0, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, "", 0, _GpsCoordinateFormat_MIN, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0, 0, 0, 0, 0, 0} #define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero} -#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, 0, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, "", 0, _GpsCoordinateFormat_MIN, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0, 0, 0, 0, 0} +#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, 0, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, "", 0, _GpsCoordinateFormat_MIN, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0, 0, 0, 0, 0, 0} /* Field tags (for use in manual encoding/decoding) */ #define RadioConfig_UserPreferences_position_broadcast_secs_tag 1 @@ -264,6 +265,7 @@ extern "C" { #define RadioConfig_UserPreferences_position_flags_tag 150 #define RadioConfig_UserPreferences_is_always_powered_tag 151 #define RadioConfig_UserPreferences_auto_screen_carousel_secs_tag 152 +#define RadioConfig_UserPreferences_on_battery_shutdown_after_secs_tag 153 #define RadioConfig_preferences_tag 1 /* Struct field encoding specification for nanopb */ @@ -337,7 +339,8 @@ X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 148) \ X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_heartbeat, 149) \ X(a, STATIC, SINGULAR, UINT32, position_flags, 150) \ X(a, STATIC, SINGULAR, BOOL, is_always_powered, 151) \ -X(a, STATIC, SINGULAR, UINT32, auto_screen_carousel_secs, 152) +X(a, STATIC, SINGULAR, UINT32, auto_screen_carousel_secs, 152) \ +X(a, STATIC, SINGULAR, UINT32, on_battery_shutdown_after_secs, 153) #define RadioConfig_UserPreferences_CALLBACK NULL #define RadioConfig_UserPreferences_DEFAULT NULL @@ -349,8 +352,8 @@ extern const pb_msgdesc_t RadioConfig_UserPreferences_msg; #define RadioConfig_UserPreferences_fields &RadioConfig_UserPreferences_msg /* Maximum encoded size of messages (where known) */ -#define RadioConfig_size 444 -#define RadioConfig_UserPreferences_size 441 +#define RadioConfig_size 451 +#define RadioConfig_UserPreferences_size 448 #ifdef __cplusplus } /* extern "C" */