mirror of
https://github.com/meshtastic/firmware.git
synced 2025-04-24 17:32:18 +00:00
begin cleanup of sleep code for new state machine
This commit is contained in:
parent
4fa6b64c3d
commit
045529d91f
6
TODO.md
6
TODO.md
@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
# High priority
|
# High priority
|
||||||
|
|
||||||
Items to complete before the first alpha release.
|
Items to complete before the first alpha release.
|
||||||
|
|
||||||
|
* implement sleep state machine
|
||||||
* have gps implement canSleep(), print nmea for debugging and discard buffers on the way into sleep
|
* have gps implement canSleep(), print nmea for debugging and discard buffers on the way into sleep
|
||||||
* implement CustomRF95::canSleep
|
* implement CustomRF95::canSleep
|
||||||
* make gps prevent light sleep if we are waiting for data
|
* make gps prevent light sleep if we are waiting for data
|
||||||
@ -13,10 +13,9 @@ for it (because it will redownload the nodedb when it comes back)
|
|||||||
* don't enter light sleep while the screen is on
|
* don't enter light sleep while the screen is on
|
||||||
* any time we wake from light sleep, briefly blink the led
|
* any time we wake from light sleep, briefly blink the led
|
||||||
|
|
||||||
* turn light sleep on agressively (while lora is on but BLE off)
|
* turn light sleep on aggressively (while lora is on but BLE off)
|
||||||
* retest BLE software update for both board types
|
* retest BLE software update for both board types
|
||||||
* default to enter deep sleep if no LORA received for two hours (indicates user has probably left the meshS)
|
* default to enter deep sleep if no LORA received for two hours (indicates user has probably left the meshS)
|
||||||
* article writeup for hackaday?
|
|
||||||
* send note about Adafruit Clue
|
* send note about Adafruit Clue
|
||||||
* send note to the guy who designed the cases
|
* send note to the guy who designed the cases
|
||||||
* update the prebuilt bins for different regulatory regions
|
* update the prebuilt bins for different regulatory regions
|
||||||
@ -48,6 +47,7 @@ Items to complete before the first beta release.
|
|||||||
* use std::map<NodeInfo*, std::string> in node db
|
* use std::map<NodeInfo*, std::string> in node db
|
||||||
* make a HAM build: yep - that's a great idea. I'll add it to the TODO. should be pretty painless - just a new frequency list, a bool to say 'never do encryption' and use hte callsign as that node's unique id. -from Girts
|
* make a HAM build: yep - that's a great idea. I'll add it to the TODO. should be pretty painless - just a new frequency list, a bool to say 'never do encryption' and use hte callsign as that node's unique id. -from Girts
|
||||||
* add frequency hopping
|
* add frequency hopping
|
||||||
|
* publish update articles on the web
|
||||||
|
|
||||||
# Pre-beta priority
|
# Pre-beta priority
|
||||||
|
|
||||||
|
@ -2,21 +2,36 @@ This is a mini design doc for various core behaviors...
|
|||||||
|
|
||||||
# Rules for sleep
|
# Rules for sleep
|
||||||
|
|
||||||
## Terms
|
## States
|
||||||
|
|
||||||
From lower to higher power consumption.
|
From lower to higher power consumption.
|
||||||
|
|
||||||
* Super-deep-sleep (SDS) - everything is off, CPU, radio, bluetooth, GPS. Only wakes due to timer or button press
|
* Super-deep-sleep (SDS) - everything is off, CPU, radio, bluetooth, GPS. Only wakes due to timer or button press
|
||||||
|
|
||||||
* deep-sleep (DS) - CPU is off, radio is on, bluetooth and GPS is off. Note: This mode is never used currently, because it only saves 1.5mA vs light-sleep
|
* deep-sleep (DS) - CPU is off, radio is on, bluetooth and GPS is off. Note: This mode is never used currently, because it only saves 1.5mA vs light-sleep
|
||||||
|
onEntry: setBluetoothOn(false), call doDeepSleep
|
||||||
|
onExit: (standard bootup code, starts in DARK)
|
||||||
|
|
||||||
* light-sleep (LS) - CPU is suspended (RAM stays alive), radio is on, bluetooth is off, GPS is off. Note: currently GPS is not turned
|
* light-sleep (LS) - CPU is suspended (RAM stays alive), radio is on, bluetooth is off, GPS is off. Note: currently GPS is not turned
|
||||||
off during light sleep, but there is a TODO item to fix this.
|
off during light sleep, but there is a TODO item to fix this.
|
||||||
* No bluetooth (NB) - CPU is running, radio is on, GPS is on but bluetooth is off, screen is off. Note: We might not need this mode
|
onEntry: setBluetoothOn(false), setGPSPower(false), call doLightSleep
|
||||||
|
onExit: start trying to get gps lock: gps.startLock(), once lock arrives service.sendPosition(BROADCAST)
|
||||||
|
|
||||||
|
* No bluetooth (NB) - CPU is running, radio is on, GPS is on but bluetooth is off, screen is off.
|
||||||
|
onEntry: setGPSPower(true), setBluetoothOn(false)
|
||||||
|
onExit:
|
||||||
|
|
||||||
* running dark (DARK) - Everything is on except screen
|
* running dark (DARK) - Everything is on except screen
|
||||||
|
onEntry: setBluetoothOn(true)
|
||||||
|
onExit:
|
||||||
|
|
||||||
* full on (ON) - Everything is on
|
* full on (ON) - Everything is on
|
||||||
|
onEntry: setBluetoothOn(true), screen.setOn(true)
|
||||||
|
onExit: screen.setOn(false)
|
||||||
|
|
||||||
## Behavior
|
## Behavior
|
||||||
|
|
||||||
### things that increase CPU activity
|
### events that increase CPU activity
|
||||||
|
|
||||||
* While in LS: Once every position_broadcast_secs (default 15 mins) - the unit will wake into DARK mode and broadcast a "networkPing" (our position) and stay alive for wait_bluetooth_secs (default 30 seconds). This allows other nodes to have a record of our last known position if we go away and allows a paired phone to hear from us and download messages.
|
* While in LS: Once every position_broadcast_secs (default 15 mins) - the unit will wake into DARK mode and broadcast a "networkPing" (our position) and stay alive for wait_bluetooth_secs (default 30 seconds). This allows other nodes to have a record of our last known position if we go away and allows a paired phone to hear from us and download messages.
|
||||||
* While in LS: Every send_owner_interval (defaults to 4, i.e. one hour), when we wake to send our position we _also_ broadcast our owner. This lets new nodes on the network find out about us or correct duplicate node number assignments.
|
* While in LS: Every send_owner_interval (defaults to 4, i.e. one hour), when we wake to send our position we _also_ broadcast our owner. This lets new nodes on the network find out about us or correct duplicate node number assignments.
|
||||||
@ -24,10 +39,11 @@ off during light sleep, but there is a TODO item to fix this.
|
|||||||
* While in LS/NB/DARK: If we receive text messages, we go to full ON mode for screen_on_secs (same as if user pressed a button)
|
* While in LS/NB/DARK: If we receive text messages, we go to full ON mode for screen_on_secs (same as if user pressed a button)
|
||||||
* While in LS: if we receive packets on the radio we will wake and handle them and stay awake in NB mode for min_wake_secs (default 10 seconds) - if we don't have packets we need to deliver to our phone. If we do have packets the phone would want we instead stay in DARK mode for wait_bluetooth secs.
|
* While in LS: if we receive packets on the radio we will wake and handle them and stay awake in NB mode for min_wake_secs (default 10 seconds) - if we don't have packets we need to deliver to our phone. If we do have packets the phone would want we instead stay in DARK mode for wait_bluetooth secs.
|
||||||
|
|
||||||
### Things that decrease cpu activity
|
### events that decrease cpu activity
|
||||||
|
|
||||||
* If time since last contact by our phone exceeds phone_timeout_secs (15 minutes) and we are in DARK mode, we transition down into NB mode
|
* While in ON: If it has been more than screen_on_secs since a press, lower to DARK
|
||||||
* If nothing above is forcing us to stay in a higher mode (wait_bluetooth_secs, screen_on_secs, or min_wake_secs) we will lower down
|
* While in DARK: If time since last contact by our phone exceeds phone_timeout_secs (15 minutes), we transition down into NB mode
|
||||||
|
* While in DARK or NB: If nothing above is forcing us to stay in a higher mode (wait_bluetooth_secs, min_wake_secs) we will lower down
|
||||||
into either LS or SDS levels. If either phone_sds_timeout_secs (default 1 hr) or mesh_sds_timeout_secs (default 1 hr) are exceeded we will lower into SDS mode for sds_secs (or a button press). Otherwise we will lower into LS mode for ls_secs (default 1 hr) (or until an interrupt, button press)
|
into either LS or SDS levels. If either phone_sds_timeout_secs (default 1 hr) or mesh_sds_timeout_secs (default 1 hr) are exceeded we will lower into SDS mode for sds_secs (or a button press). Otherwise we will lower into LS mode for ls_secs (default 1 hr) (or until an interrupt, button press)
|
||||||
|
|
||||||
TODO: Eventually these scheduled intervals should be synchronized to the GPS clock, so that we can consider leaving the lora receiver off to save even more power.
|
TODO: Eventually these scheduled intervals should be synchronized to the GPS clock, so that we can consider leaving the lora receiver off to save even more power.
|
||||||
|
@ -64,6 +64,7 @@ lib_deps =
|
|||||||
OneButton
|
OneButton
|
||||||
CRC32 ; explicitly needed because dependency is missing in the ble ota update lib
|
CRC32 ; explicitly needed because dependency is missing in the ble ota update lib
|
||||||
Wire ; explicitly needed here because the AXP202 library forgets to add it
|
Wire ; explicitly needed here because the AXP202 library forgets to add it
|
||||||
|
https://github.com/geeksville/arduino-fsm.git
|
||||||
|
|
||||||
;[env:tbeam]
|
;[env:tbeam]
|
||||||
;board = ttgo-t-beam
|
;board = ttgo-t-beam
|
||||||
|
@ -173,7 +173,7 @@ uint32_t sendOwnerCb()
|
|||||||
{
|
{
|
||||||
service.sendOurOwner();
|
service.sendOurOwner();
|
||||||
|
|
||||||
return radioConfig.preferences.send_owner_secs * 1000;
|
return radioConfig.preferences.send_owner_interval * radioConfig.preferences.position_broadcast_secs * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
Periodic sendOwnerPeriod(sendOwnerCb);
|
Periodic sendOwnerPeriod(sendOwnerCb);
|
||||||
|
@ -49,8 +49,13 @@ void NodeDB::init()
|
|||||||
devicestate.node_db_count = 0;
|
devicestate.node_db_count = 0;
|
||||||
devicestate.receive_queue_count = 0;
|
devicestate.receive_queue_count = 0;
|
||||||
|
|
||||||
radioConfig.preferences.send_owner_secs = 60 * 60; // default to once an hour
|
radioConfig.preferences.send_owner_interval = 4; // per sw-design.md
|
||||||
radioConfig.preferences.position_broadcast_secs = 15 * 60; // default to once every 15 mins
|
radioConfig.preferences.position_broadcast_secs = 20; // 15 * 60;
|
||||||
|
radioConfig.preferences.wait_bluetooth_secs = 10; // 30;
|
||||||
|
radioConfig.preferences.screen_on_secs = 30;
|
||||||
|
radioConfig.preferences.mesh_sds_timeout_secs = 60 * 60;
|
||||||
|
radioConfig.preferences.phone_sds_timeout_sec = 60 * 60;
|
||||||
|
radioConfig.preferences.sds_secs = 60 * 60;
|
||||||
|
|
||||||
#ifdef GPS_RX_PIN
|
#ifdef GPS_RX_PIN
|
||||||
// some hardware defaults to have a built in GPS
|
// some hardware defaults to have a built in GPS
|
||||||
@ -244,7 +249,8 @@ void NodeDB::updateFrom(const MeshPacket &mp)
|
|||||||
|
|
||||||
switch (p.which_variant)
|
switch (p.which_variant)
|
||||||
{
|
{
|
||||||
case SubPacket_position_tag: {
|
case SubPacket_position_tag:
|
||||||
|
{
|
||||||
// we carefully preserve the old time, because we always trust our local timestamps more
|
// we carefully preserve the old time, because we always trust our local timestamps more
|
||||||
uint32_t oldtime = info->position.time;
|
uint32_t oldtime = info->position.time;
|
||||||
info->position = p.variant.position;
|
info->position = p.variant.position;
|
||||||
|
@ -57,11 +57,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#define DEBUG_PORT Serial // Serial debug port
|
#define DEBUG_PORT Serial // Serial debug port
|
||||||
#define SERIAL_BAUD 115200 // Serial debug baud rate
|
#define SERIAL_BAUD 115200 // Serial debug baud rate
|
||||||
#define SLEEP_MSECS (30 * 24 * 60 * 60 * 1000LL) // Sleep for these many millis (or a button press or a lora msg?)
|
|
||||||
|
|
||||||
#define MESSAGE_TO_SLEEP_DELAY 5000 // Time after message before going to sleep
|
|
||||||
|
|
||||||
#define LOGO_DELAY 2000 // Time to show logo on first boot
|
|
||||||
#define REQUIRE_RADIO true // If true, we will fail to start if the radio is not found
|
#define REQUIRE_RADIO true // If true, we will fail to start if the radio is not found
|
||||||
|
|
||||||
// If not defined, we will wait for lock forever
|
// If not defined, we will wait for lock forever
|
||||||
|
4
src/main.h
Normal file
4
src/main.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern bool axp192_found;
|
||||||
|
extern bool ssd1306_found;
|
241
src/main.ino
241
src/main.ino
@ -36,6 +36,7 @@
|
|||||||
#include "esp32/pm.h"
|
#include "esp32/pm.h"
|
||||||
#include "esp_pm.h"
|
#include "esp_pm.h"
|
||||||
#include "MeshRadio.h"
|
#include "MeshRadio.h"
|
||||||
|
#include "sleep.h"
|
||||||
|
|
||||||
#ifdef T_BEAM_V10
|
#ifdef T_BEAM_V10
|
||||||
#include "axp20x.h"
|
#include "axp20x.h"
|
||||||
@ -48,11 +49,6 @@ bool isUSBPowered = false;
|
|||||||
bool ssd1306_found = false;
|
bool ssd1306_found = false;
|
||||||
bool axp192_found = false;
|
bool axp192_found = false;
|
||||||
|
|
||||||
bool packetSent, packetQueued;
|
|
||||||
|
|
||||||
// deep sleep support
|
|
||||||
RTC_DATA_ATTR int bootCount = 0;
|
|
||||||
esp_sleep_source_t wakeCause; // the reason we booted this time
|
|
||||||
|
|
||||||
#define xstr(s) str(s)
|
#define xstr(s) str(s)
|
||||||
#define str(s) #s
|
#define str(s) #s
|
||||||
@ -61,224 +57,6 @@ esp_sleep_source_t wakeCause; // the reason we booted this time
|
|||||||
// Application
|
// Application
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
|
||||||
* Control CPU core speed (80MHz vs 240MHz)
|
|
||||||
*
|
|
||||||
* We leave CPU at full speed during init, but once loop is called switch to low speed (for a 50% power savings)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void setCPUFast(bool on)
|
|
||||||
{
|
|
||||||
setCpuFrequencyMhz(on ? 240 : 80);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setLed(bool ledOn)
|
|
||||||
{
|
|
||||||
#ifdef LED_PIN
|
|
||||||
// toggle the led so we can get some rough sense of how often loop is pausing
|
|
||||||
digitalWrite(LED_PIN, ledOn);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef T_BEAM_V10
|
|
||||||
if (axp192_found)
|
|
||||||
{
|
|
||||||
// blink the axp led
|
|
||||||
axp.setChgLEDMode(ledOn ? AXP20X_LED_LOW_LEVEL : AXP20X_LED_OFF);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void setGPSPower(bool on)
|
|
||||||
{
|
|
||||||
#ifdef T_BEAM_V10
|
|
||||||
if (axp192_found)
|
|
||||||
axp.setPowerOutPut(AXP192_LDO3, on ? AXP202_ON : AXP202_OFF); // GPS main power
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void doDeepSleep(uint64_t msecToWake)
|
|
||||||
{
|
|
||||||
DEBUG_MSG("Entering deep sleep for %llu seconds\n", msecToWake / 1000);
|
|
||||||
|
|
||||||
// not using wifi yet, but once we are this is needed to shutoff the radio hw
|
|
||||||
// esp_wifi_stop();
|
|
||||||
|
|
||||||
BLEDevice::deinit(false); // We are required to shutdown bluetooth before deep or light sleep
|
|
||||||
|
|
||||||
screen_off(); // datasheet says this will draw only 10ua
|
|
||||||
|
|
||||||
// Put radio in sleep mode (will still draw power but only 0.2uA)
|
|
||||||
service.radio.rf95.sleep();
|
|
||||||
|
|
||||||
nodeDB.saveToDisk();
|
|
||||||
|
|
||||||
#ifdef RESET_OLED
|
|
||||||
digitalWrite(RESET_OLED, 1); // put the display in reset before killing its power
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef VEXT_ENABLE
|
|
||||||
digitalWrite(VEXT_ENABLE, 1); // turn off the display power
|
|
||||||
#endif
|
|
||||||
|
|
||||||
setLed(false);
|
|
||||||
|
|
||||||
#ifdef T_BEAM_V10
|
|
||||||
if (axp192_found)
|
|
||||||
{
|
|
||||||
// No need to turn this off if the power draw in sleep mode really is just 0.2uA and turning it off would
|
|
||||||
// leave floating input for the IRQ line
|
|
||||||
|
|
||||||
// If we want to leave the radio receving in would be 11.5mA current draw, but most of the time it is just waiting
|
|
||||||
// in its sequencer (true?) so the average power draw should be much lower even if we were listinging for packets
|
|
||||||
// all the time.
|
|
||||||
|
|
||||||
// axp.setPowerOutPut(AXP192_LDO2, AXP202_OFF); // LORA radio
|
|
||||||
|
|
||||||
setGPSPower(false);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
Some ESP32 IOs have internal pullups or pulldowns, which are enabled by default.
|
|
||||||
If an external circuit drives this pin in deep sleep mode, current consumption may
|
|
||||||
increase due to current flowing through these pullups and pulldowns.
|
|
||||||
|
|
||||||
To isolate a pin, preventing extra current draw, call rtc_gpio_isolate() function.
|
|
||||||
For example, on ESP32-WROVER module, GPIO12 is pulled up externally.
|
|
||||||
GPIO12 also has an internal pulldown in the ESP32 chip. This means that in deep sleep,
|
|
||||||
some current will flow through these external and internal resistors, increasing deep
|
|
||||||
sleep current above the minimal possible value.
|
|
||||||
|
|
||||||
Note: we don't isolate pins that are used for the LORA, LED, i2c, spi or the wake button
|
|
||||||
*/
|
|
||||||
static const uint8_t rtcGpios[] = {/* 0, */ 2,
|
|
||||||
/* 4, */
|
|
||||||
#ifndef USE_JTAG
|
|
||||||
12, 13, /* 14, */ /* 15, */
|
|
||||||
#endif
|
|
||||||
/* 25, */ 26, /* 27, */
|
|
||||||
32, 33, 34, 35, 36, 37, /* 38, */ 39};
|
|
||||||
|
|
||||||
for (int i = 0; i < sizeof(rtcGpios); i++)
|
|
||||||
rtc_gpio_isolate((gpio_num_t)rtcGpios[i]);
|
|
||||||
|
|
||||||
// FIXME, disable internal rtc pullups/pulldowns on the non isolated pins. for inputs that we aren't using
|
|
||||||
// to detect wake and in normal operation the external part drives them hard.
|
|
||||||
|
|
||||||
// We want RTC peripherals to stay on
|
|
||||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
|
||||||
|
|
||||||
#ifdef BUTTON_PIN
|
|
||||||
// Only GPIOs which are have RTC functionality can be used in this bit map: 0,2,4,12-15,25-27,32-39.
|
|
||||||
uint64_t gpioMask = (1ULL << BUTTON_PIN);
|
|
||||||
|
|
||||||
// Not needed because both of the current boards have external pullups
|
|
||||||
// FIXME change polarity in hw so we can wake on ANY_HIGH instead - that would allow us to use all three buttons (instead of just the first)
|
|
||||||
// gpio_pullup_en((gpio_num_t)BUTTON_PIN);
|
|
||||||
|
|
||||||
esp_sleep_enable_ext1_wakeup(gpioMask, ESP_EXT1_WAKEUP_ALL_LOW);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
esp_sleep_enable_timer_wakeup(msecToWake * 1000ULL); // call expects usecs
|
|
||||||
esp_deep_sleep_start(); // TBD mA sleep current (battery)
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "esp_bt_main.h"
|
|
||||||
|
|
||||||
bool bluetoothOn = true; // we turn it on during setup() so default on
|
|
||||||
|
|
||||||
void setBluetoothEnable(bool on)
|
|
||||||
{
|
|
||||||
if (on != bluetoothOn)
|
|
||||||
{
|
|
||||||
DEBUG_MSG("Setting bluetooth enable=%d\n", on);
|
|
||||||
|
|
||||||
bluetoothOn = on;
|
|
||||||
if (on)
|
|
||||||
{
|
|
||||||
if (esp_bt_controller_enable(ESP_BT_MODE_BTDM) != ESP_OK)
|
|
||||||
DEBUG_MSG("error reenabling bt controller\n");
|
|
||||||
if (esp_bluedroid_enable() != ESP_OK)
|
|
||||||
DEBUG_MSG("error reenabling bluedroid\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (esp_bluedroid_disable() != ESP_OK)
|
|
||||||
DEBUG_MSG("error disabling bluedroid\n");
|
|
||||||
if (esp_bt_controller_disable() != ESP_OK)
|
|
||||||
DEBUG_MSG("error disabling bt controller\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* enter light sleep (preserves ram but stops everything about CPU).
|
|
||||||
*
|
|
||||||
* Returns (after restoring hw state) when the user presses a button or we get a LoRa interrupt
|
|
||||||
*/
|
|
||||||
void doLightSleep(uint32_t sleepMsec = 20 * 1000) // FIXME, use a more reasonable default
|
|
||||||
{
|
|
||||||
DEBUG_MSG("Enter light sleep\n");
|
|
||||||
uint64_t sleepUsec = sleepMsec * 1000LL;
|
|
||||||
|
|
||||||
gps.prepareSleep(); // abandon in-process parsing
|
|
||||||
setLed(false); // Never leave led on while in light sleep
|
|
||||||
|
|
||||||
// NOTE! ESP docs say we must disable bluetooth and wifi before light sleep
|
|
||||||
|
|
||||||
// We want RTC peripherals to stay on
|
|
||||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
|
||||||
|
|
||||||
gpio_wakeup_enable((gpio_num_t)BUTTON_PIN, GPIO_INTR_LOW_LEVEL); // when user presses, this button goes low
|
|
||||||
gpio_wakeup_enable((gpio_num_t)DIO0_GPIO, GPIO_INTR_HIGH_LEVEL); // RF95 interrupt, active high
|
|
||||||
#ifdef PMU_IRQ
|
|
||||||
gpio_wakeup_enable((gpio_num_t)PMU_IRQ, GPIO_INTR_HIGH_LEVEL); // pmu irq
|
|
||||||
#endif
|
|
||||||
esp_sleep_enable_gpio_wakeup();
|
|
||||||
esp_sleep_enable_timer_wakeup(sleepUsec);
|
|
||||||
esp_light_sleep_start();
|
|
||||||
DEBUG_MSG("Exit light sleep\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* enable modem sleep mode as needed and available. Should lower our CPU current draw to an average of about 20mA.
|
|
||||||
*
|
|
||||||
* per https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/power_management.html
|
|
||||||
*
|
|
||||||
* supposedly according to https://github.com/espressif/arduino-esp32/issues/475 this is already done in arduino
|
|
||||||
*/
|
|
||||||
void enableModemSleep()
|
|
||||||
{
|
|
||||||
static esp_pm_config_esp32_t config; // filled with zeros because bss
|
|
||||||
|
|
||||||
config.max_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
|
|
||||||
config.min_freq_mhz = 10; // 10Mhz is minimum recommended
|
|
||||||
config.light_sleep_enable = false;
|
|
||||||
DEBUG_MSG("Sleep request result %x\n", esp_pm_configure(&config));
|
|
||||||
}
|
|
||||||
|
|
||||||
void sleep()
|
|
||||||
{
|
|
||||||
#ifdef SLEEP_MSECS
|
|
||||||
|
|
||||||
// If the user has a screen, tell them we are about to sleep
|
|
||||||
if (ssd1306_found)
|
|
||||||
{
|
|
||||||
// Show the going to sleep message on the screen
|
|
||||||
char buffer[20];
|
|
||||||
snprintf(buffer, sizeof(buffer), "Sleeping in %3.1fs\n", (MESSAGE_TO_SLEEP_DELAY / 1000.0));
|
|
||||||
screen_print(buffer);
|
|
||||||
|
|
||||||
// Wait for MESSAGE_TO_SLEEP_DELAY millis to sleep
|
|
||||||
delay(MESSAGE_TO_SLEEP_DELAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We sleep for the interval between messages minus the current millis
|
|
||||||
// this way we distribute the messages evenly every SEND_INTERVAL millis
|
|
||||||
doDeepSleep(SLEEP_MSECS);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void scanI2Cdevice(void)
|
void scanI2Cdevice(void)
|
||||||
{
|
{
|
||||||
@ -409,21 +187,6 @@ void axp192Init()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform power on init that we do on each wake from deep sleep
|
|
||||||
void initDeepSleep()
|
|
||||||
{
|
|
||||||
bootCount++;
|
|
||||||
wakeCause = esp_sleep_get_wakeup_cause();
|
|
||||||
/*
|
|
||||||
Not using yet because we are using wake on all buttons being low
|
|
||||||
|
|
||||||
wakeButtons = esp_sleep_get_ext1_wakeup_status(); // If one of these buttons is set it was the reason we woke
|
|
||||||
if (wakeCause == ESP_SLEEP_WAKEUP_EXT1 && !wakeButtons) // we must have been using the 'all buttons rule for waking' to support busted boards, assume button one was pressed
|
|
||||||
wakeButtons = ((uint64_t)1) << buttons.gpios[0];
|
|
||||||
*/
|
|
||||||
|
|
||||||
DEBUG_MSG("booted, wake cause %d (boot count %d)\n", wakeCause, bootCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *getDeviceName()
|
const char *getDeviceName()
|
||||||
{
|
{
|
||||||
@ -617,7 +380,7 @@ void loop()
|
|||||||
// !isUSBPowered <- doesn't work yet because the axp192 isn't letting the battery fully charge when we are awake - FIXME
|
// !isUSBPowered <- doesn't work yet because the axp192 isn't letting the battery fully charge when we are awake - FIXME
|
||||||
if (millis() - lastPressMs > MINWAKE_MSECS)
|
if (millis() - lastPressMs > MINWAKE_MSECS)
|
||||||
{
|
{
|
||||||
sleep();
|
doDeepSleep(radioConfig.preferences.sds_secs);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -33,8 +33,8 @@ typedef enum _ChannelSettings_ModemConfig {
|
|||||||
|
|
||||||
typedef enum _DeviceState_Version {
|
typedef enum _DeviceState_Version {
|
||||||
DeviceState_Version_Unset = 0,
|
DeviceState_Version_Unset = 0,
|
||||||
DeviceState_Version_Minimum = 15,
|
DeviceState_Version_Minimum = 16,
|
||||||
DeviceState_Version_Current = 15
|
DeviceState_Version_Current = 16
|
||||||
} DeviceState_Version;
|
} DeviceState_Version;
|
||||||
|
|
||||||
/* Struct definitions */
|
/* Struct definitions */
|
||||||
@ -69,8 +69,15 @@ typedef struct _Position {
|
|||||||
|
|
||||||
typedef struct _RadioConfig_UserPreferences {
|
typedef struct _RadioConfig_UserPreferences {
|
||||||
uint32_t position_broadcast_secs;
|
uint32_t position_broadcast_secs;
|
||||||
uint32_t send_owner_secs;
|
uint32_t send_owner_interval;
|
||||||
uint32_t num_missed_to_fail;
|
uint32_t num_missed_to_fail;
|
||||||
|
uint32_t wait_bluetooth_secs;
|
||||||
|
uint32_t screen_on_secs;
|
||||||
|
uint32_t phone_timeout_secs;
|
||||||
|
uint32_t phone_sds_timeout_sec;
|
||||||
|
uint32_t mesh_sds_timeout_secs;
|
||||||
|
uint32_t sds_secs;
|
||||||
|
uint32_t ls_secs;
|
||||||
bool keep_all_packets;
|
bool keep_all_packets;
|
||||||
bool promiscuous_mode;
|
bool promiscuous_mode;
|
||||||
} RadioConfig_UserPreferences;
|
} RadioConfig_UserPreferences;
|
||||||
@ -175,7 +182,7 @@ typedef struct _ToRadio {
|
|||||||
#define MeshPacket_init_default {0, 0, false, SubPacket_init_default, 0}
|
#define MeshPacket_init_default {0, 0, false, SubPacket_init_default, 0}
|
||||||
#define ChannelSettings_init_default {0, 0, _ChannelSettings_ModemConfig_MIN, {0}, ""}
|
#define ChannelSettings_init_default {0, 0, _ChannelSettings_ModemConfig_MIN, {0}, ""}
|
||||||
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default}
|
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default}
|
||||||
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0}
|
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
|
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
|
||||||
#define MyNodeInfo_init_default {0, 0, 0}
|
#define MyNodeInfo_init_default {0, 0, 0}
|
||||||
#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default}, _DeviceState_Version_MIN, false, MeshPacket_init_default}
|
#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default}, _DeviceState_Version_MIN, false, MeshPacket_init_default}
|
||||||
@ -188,7 +195,7 @@ typedef struct _ToRadio {
|
|||||||
#define MeshPacket_init_zero {0, 0, false, SubPacket_init_zero, 0}
|
#define MeshPacket_init_zero {0, 0, false, SubPacket_init_zero, 0}
|
||||||
#define ChannelSettings_init_zero {0, 0, _ChannelSettings_ModemConfig_MIN, {0}, ""}
|
#define ChannelSettings_init_zero {0, 0, _ChannelSettings_ModemConfig_MIN, {0}, ""}
|
||||||
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero}
|
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero}
|
||||||
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0}
|
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
|
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
|
||||||
#define MyNodeInfo_init_zero {0, 0, 0}
|
#define MyNodeInfo_init_zero {0, 0, 0}
|
||||||
#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero}, _DeviceState_Version_MIN, false, MeshPacket_init_zero}
|
#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero, MeshPacket_init_zero}, _DeviceState_Version_MIN, false, MeshPacket_init_zero}
|
||||||
@ -213,8 +220,15 @@ typedef struct _ToRadio {
|
|||||||
#define Position_from_hardware_tag 5
|
#define Position_from_hardware_tag 5
|
||||||
#define Position_time_tag 6
|
#define Position_time_tag 6
|
||||||
#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1
|
#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1
|
||||||
#define RadioConfig_UserPreferences_send_owner_secs_tag 2
|
#define RadioConfig_UserPreferences_send_owner_interval_tag 2
|
||||||
#define RadioConfig_UserPreferences_num_missed_to_fail_tag 3
|
#define RadioConfig_UserPreferences_num_missed_to_fail_tag 3
|
||||||
|
#define RadioConfig_UserPreferences_wait_bluetooth_secs_tag 4
|
||||||
|
#define RadioConfig_UserPreferences_screen_on_secs_tag 5
|
||||||
|
#define RadioConfig_UserPreferences_phone_timeout_secs_tag 6
|
||||||
|
#define RadioConfig_UserPreferences_phone_sds_timeout_sec_tag 7
|
||||||
|
#define RadioConfig_UserPreferences_mesh_sds_timeout_secs_tag 8
|
||||||
|
#define RadioConfig_UserPreferences_sds_secs_tag 9
|
||||||
|
#define RadioConfig_UserPreferences_ls_secs_tag 10
|
||||||
#define RadioConfig_UserPreferences_keep_all_packets_tag 100
|
#define RadioConfig_UserPreferences_keep_all_packets_tag 100
|
||||||
#define RadioConfig_UserPreferences_promiscuous_mode_tag 101
|
#define RadioConfig_UserPreferences_promiscuous_mode_tag 101
|
||||||
#define User_id_tag 1
|
#define User_id_tag 1
|
||||||
@ -311,8 +325,15 @@ X(a, STATIC, OPTIONAL, MESSAGE, channel_settings, 2)
|
|||||||
|
|
||||||
#define RadioConfig_UserPreferences_FIELDLIST(X, a) \
|
#define RadioConfig_UserPreferences_FIELDLIST(X, a) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, position_broadcast_secs, 1) \
|
X(a, STATIC, SINGULAR, UINT32, position_broadcast_secs, 1) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, send_owner_secs, 2) \
|
X(a, STATIC, SINGULAR, UINT32, send_owner_interval, 2) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, num_missed_to_fail, 3) \
|
X(a, STATIC, SINGULAR, UINT32, num_missed_to_fail, 3) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, wait_bluetooth_secs, 4) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, screen_on_secs, 5) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, phone_timeout_secs, 6) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, phone_sds_timeout_sec, 7) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, mesh_sds_timeout_secs, 8) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, sds_secs, 9) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, ls_secs, 10) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, keep_all_packets, 100) \
|
X(a, STATIC, SINGULAR, BOOL, keep_all_packets, 100) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, promiscuous_mode, 101)
|
X(a, STATIC, SINGULAR, BOOL, promiscuous_mode, 101)
|
||||||
#define RadioConfig_UserPreferences_CALLBACK NULL
|
#define RadioConfig_UserPreferences_CALLBACK NULL
|
||||||
@ -402,11 +423,11 @@ extern const pb_msgdesc_t ToRadio_msg;
|
|||||||
#define SubPacket_size 261
|
#define SubPacket_size 261
|
||||||
#define MeshPacket_size 292
|
#define MeshPacket_size 292
|
||||||
#define ChannelSettings_size 50
|
#define ChannelSettings_size 50
|
||||||
#define RadioConfig_size 78
|
#define RadioConfig_size 120
|
||||||
#define RadioConfig_UserPreferences_size 24
|
#define RadioConfig_UserPreferences_size 66
|
||||||
#define NodeInfo_size 157
|
#define NodeInfo_size 157
|
||||||
#define MyNodeInfo_size 24
|
#define MyNodeInfo_size 24
|
||||||
#define DeviceState_size 15037
|
#define DeviceState_size 15079
|
||||||
#define FromRadio_size 301
|
#define FromRadio_size 301
|
||||||
#define ToRadio_size 295
|
#define ToRadio_size 295
|
||||||
|
|
||||||
|
252
src/sleep.cpp
Normal file
252
src/sleep.cpp
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
#include "configuration.h"
|
||||||
|
#include "rom/rtc.h"
|
||||||
|
#include <driver/rtc_io.h>
|
||||||
|
#include <TinyGPS++.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include "BluetoothUtil.h"
|
||||||
|
#include "MeshBluetoothService.h"
|
||||||
|
#include "MeshService.h"
|
||||||
|
#include "GPS.h"
|
||||||
|
#include "screen.h"
|
||||||
|
#include "NodeDB.h"
|
||||||
|
#include "Periodic.h"
|
||||||
|
#include "esp32/pm.h"
|
||||||
|
#include "esp_pm.h"
|
||||||
|
#include "MeshRadio.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
#ifdef T_BEAM_V10
|
||||||
|
#include "axp20x.h"
|
||||||
|
extern AXP20X_Class axp;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// deep sleep support
|
||||||
|
RTC_DATA_ATTR int bootCount = 0;
|
||||||
|
esp_sleep_source_t wakeCause; // the reason we booted this time
|
||||||
|
|
||||||
|
#define xstr(s) str(s)
|
||||||
|
#define str(s) #s
|
||||||
|
|
||||||
|
#include "esp_bt_main.h"
|
||||||
|
|
||||||
|
bool bluetoothOn = true; // we turn it on during setup() so default on
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Application
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control CPU core speed (80MHz vs 240MHz)
|
||||||
|
*
|
||||||
|
* We leave CPU at full speed during init, but once loop is called switch to low speed (for a 50% power savings)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void setCPUFast(bool on)
|
||||||
|
{
|
||||||
|
setCpuFrequencyMhz(on ? 240 : 80);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLed(bool ledOn)
|
||||||
|
{
|
||||||
|
#ifdef LED_PIN
|
||||||
|
// toggle the led so we can get some rough sense of how often loop is pausing
|
||||||
|
digitalWrite(LED_PIN, ledOn);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef T_BEAM_V10
|
||||||
|
if (axp192_found)
|
||||||
|
{
|
||||||
|
// blink the axp led
|
||||||
|
axp.setChgLEDMode(ledOn ? AXP20X_LED_LOW_LEVEL : AXP20X_LED_OFF);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void setGPSPower(bool on)
|
||||||
|
{
|
||||||
|
#ifdef T_BEAM_V10
|
||||||
|
if (axp192_found)
|
||||||
|
axp.setPowerOutPut(AXP192_LDO3, on ? AXP202_ON : AXP202_OFF); // GPS main power
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform power on init that we do on each wake from deep sleep
|
||||||
|
void initDeepSleep()
|
||||||
|
{
|
||||||
|
bootCount++;
|
||||||
|
wakeCause = esp_sleep_get_wakeup_cause();
|
||||||
|
/*
|
||||||
|
Not using yet because we are using wake on all buttons being low
|
||||||
|
|
||||||
|
wakeButtons = esp_sleep_get_ext1_wakeup_status(); // If one of these buttons is set it was the reason we woke
|
||||||
|
if (wakeCause == ESP_SLEEP_WAKEUP_EXT1 && !wakeButtons) // we must have been using the 'all buttons rule for waking' to support busted boards, assume button one was pressed
|
||||||
|
wakeButtons = ((uint64_t)1) << buttons.gpios[0];
|
||||||
|
*/
|
||||||
|
|
||||||
|
DEBUG_MSG("booted, wake cause %d (boot count %d)\n", wakeCause, bootCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void doDeepSleep(uint64_t msecToWake)
|
||||||
|
{
|
||||||
|
DEBUG_MSG("Entering deep sleep for %llu seconds\n", msecToWake / 1000);
|
||||||
|
|
||||||
|
// not using wifi yet, but once we are this is needed to shutoff the radio hw
|
||||||
|
// esp_wifi_stop();
|
||||||
|
|
||||||
|
BLEDevice::deinit(false); // We are required to shutdown bluetooth before deep or light sleep
|
||||||
|
|
||||||
|
screen_off(); // datasheet says this will draw only 10ua
|
||||||
|
|
||||||
|
// Put radio in sleep mode (will still draw power but only 0.2uA)
|
||||||
|
service.radio.rf95.sleep();
|
||||||
|
|
||||||
|
nodeDB.saveToDisk();
|
||||||
|
|
||||||
|
#ifdef RESET_OLED
|
||||||
|
digitalWrite(RESET_OLED, 1); // put the display in reset before killing its power
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VEXT_ENABLE
|
||||||
|
digitalWrite(VEXT_ENABLE, 1); // turn off the display power
|
||||||
|
#endif
|
||||||
|
|
||||||
|
setLed(false);
|
||||||
|
|
||||||
|
#ifdef T_BEAM_V10
|
||||||
|
if (axp192_found)
|
||||||
|
{
|
||||||
|
// No need to turn this off if the power draw in sleep mode really is just 0.2uA and turning it off would
|
||||||
|
// leave floating input for the IRQ line
|
||||||
|
|
||||||
|
// If we want to leave the radio receving in would be 11.5mA current draw, but most of the time it is just waiting
|
||||||
|
// in its sequencer (true?) so the average power draw should be much lower even if we were listinging for packets
|
||||||
|
// all the time.
|
||||||
|
|
||||||
|
// axp.setPowerOutPut(AXP192_LDO2, AXP202_OFF); // LORA radio
|
||||||
|
|
||||||
|
setGPSPower(false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Some ESP32 IOs have internal pullups or pulldowns, which are enabled by default.
|
||||||
|
If an external circuit drives this pin in deep sleep mode, current consumption may
|
||||||
|
increase due to current flowing through these pullups and pulldowns.
|
||||||
|
|
||||||
|
To isolate a pin, preventing extra current draw, call rtc_gpio_isolate() function.
|
||||||
|
For example, on ESP32-WROVER module, GPIO12 is pulled up externally.
|
||||||
|
GPIO12 also has an internal pulldown in the ESP32 chip. This means that in deep sleep,
|
||||||
|
some current will flow through these external and internal resistors, increasing deep
|
||||||
|
sleep current above the minimal possible value.
|
||||||
|
|
||||||
|
Note: we don't isolate pins that are used for the LORA, LED, i2c, spi or the wake button
|
||||||
|
*/
|
||||||
|
static const uint8_t rtcGpios[] = {/* 0, */ 2,
|
||||||
|
/* 4, */
|
||||||
|
#ifndef USE_JTAG
|
||||||
|
12, 13, /* 14, */ /* 15, */
|
||||||
|
#endif
|
||||||
|
/* 25, */ 26, /* 27, */
|
||||||
|
32, 33, 34, 35, 36, 37, /* 38, */ 39};
|
||||||
|
|
||||||
|
for (int i = 0; i < sizeof(rtcGpios); i++)
|
||||||
|
rtc_gpio_isolate((gpio_num_t)rtcGpios[i]);
|
||||||
|
|
||||||
|
// FIXME, disable internal rtc pullups/pulldowns on the non isolated pins. for inputs that we aren't using
|
||||||
|
// to detect wake and in normal operation the external part drives them hard.
|
||||||
|
|
||||||
|
// We want RTC peripherals to stay on
|
||||||
|
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||||
|
|
||||||
|
#ifdef BUTTON_PIN
|
||||||
|
// Only GPIOs which are have RTC functionality can be used in this bit map: 0,2,4,12-15,25-27,32-39.
|
||||||
|
uint64_t gpioMask = (1ULL << BUTTON_PIN);
|
||||||
|
|
||||||
|
// Not needed because both of the current boards have external pullups
|
||||||
|
// FIXME change polarity in hw so we can wake on ANY_HIGH instead - that would allow us to use all three buttons (instead of just the first)
|
||||||
|
// gpio_pullup_en((gpio_num_t)BUTTON_PIN);
|
||||||
|
|
||||||
|
esp_sleep_enable_ext1_wakeup(gpioMask, ESP_EXT1_WAKEUP_ALL_LOW);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
esp_sleep_enable_timer_wakeup(msecToWake * 1000ULL); // call expects usecs
|
||||||
|
esp_deep_sleep_start(); // TBD mA sleep current (battery)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void setBluetoothEnable(bool on)
|
||||||
|
{
|
||||||
|
if (on != bluetoothOn)
|
||||||
|
{
|
||||||
|
DEBUG_MSG("Setting bluetooth enable=%d\n", on);
|
||||||
|
|
||||||
|
bluetoothOn = on;
|
||||||
|
if (on)
|
||||||
|
{
|
||||||
|
if (esp_bt_controller_enable(ESP_BT_MODE_BTDM) != ESP_OK)
|
||||||
|
DEBUG_MSG("error reenabling bt controller\n");
|
||||||
|
if (esp_bluedroid_enable() != ESP_OK)
|
||||||
|
DEBUG_MSG("error reenabling bluedroid\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (esp_bluedroid_disable() != ESP_OK)
|
||||||
|
DEBUG_MSG("error disabling bluedroid\n");
|
||||||
|
if (esp_bt_controller_disable() != ESP_OK)
|
||||||
|
DEBUG_MSG("error disabling bt controller\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enter light sleep (preserves ram but stops everything about CPU).
|
||||||
|
*
|
||||||
|
* Returns (after restoring hw state) when the user presses a button or we get a LoRa interrupt
|
||||||
|
*/
|
||||||
|
void doLightSleep(uint64_t sleepMsec) // FIXME, use a more reasonable default
|
||||||
|
{
|
||||||
|
DEBUG_MSG("Enter light sleep\n");
|
||||||
|
uint64_t sleepUsec = sleepMsec * 1000LL;
|
||||||
|
|
||||||
|
setBluetoothEnable(false); // has to be off before calling light sleep
|
||||||
|
gps.prepareSleep(); // abandon in-process parsing
|
||||||
|
setLed(false); // Never leave led on while in light sleep
|
||||||
|
|
||||||
|
// NOTE! ESP docs say we must disable bluetooth and wifi before light sleep
|
||||||
|
|
||||||
|
// We want RTC peripherals to stay on
|
||||||
|
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||||
|
|
||||||
|
gpio_wakeup_enable((gpio_num_t)BUTTON_PIN, GPIO_INTR_LOW_LEVEL); // when user presses, this button goes low
|
||||||
|
gpio_wakeup_enable((gpio_num_t)DIO0_GPIO, GPIO_INTR_HIGH_LEVEL); // RF95 interrupt, active high
|
||||||
|
#ifdef PMU_IRQ
|
||||||
|
gpio_wakeup_enable((gpio_num_t)PMU_IRQ, GPIO_INTR_HIGH_LEVEL); // pmu irq
|
||||||
|
#endif
|
||||||
|
esp_sleep_enable_gpio_wakeup();
|
||||||
|
esp_sleep_enable_timer_wakeup(sleepUsec);
|
||||||
|
esp_light_sleep_start();
|
||||||
|
DEBUG_MSG("Exit light sleep\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// not legal on the stock android ESP build
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enable modem sleep mode as needed and available. Should lower our CPU current draw to an average of about 20mA.
|
||||||
|
*
|
||||||
|
* per https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/power_management.html
|
||||||
|
*
|
||||||
|
* supposedly according to https://github.com/espressif/arduino-esp32/issues/475 this is already done in arduino
|
||||||
|
*/
|
||||||
|
void enableModemSleep()
|
||||||
|
{
|
||||||
|
static esp_pm_config_esp32_t config; // filled with zeros because bss
|
||||||
|
|
||||||
|
config.max_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
|
||||||
|
config.min_freq_mhz = 10; // 10Mhz is minimum recommended
|
||||||
|
config.light_sleep_enable = false;
|
||||||
|
DEBUG_MSG("Sleep request result %x\n", esp_pm_configure(&config));
|
||||||
|
}
|
||||||
|
#endif
|
17
src/sleep.h
Normal file
17
src/sleep.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void doDeepSleep(uint64_t msecToWake);
|
||||||
|
void doLightSleep(uint64_t msecToWake);
|
||||||
|
void setBluetoothEnable(bool on);
|
||||||
|
|
||||||
|
// Perform power on init that we do on each wake from deep sleep
|
||||||
|
void initDeepSleep();
|
||||||
|
|
||||||
|
void setCPUFast(bool on);
|
||||||
|
void setLed(bool ledOn);
|
||||||
|
|
||||||
|
extern int bootCount;
|
||||||
|
extern esp_sleep_source_t wakeCause;
|
||||||
|
|
||||||
|
// is bluetooth sw currently running?
|
||||||
|
extern bool bluetoothOn;
|
Loading…
Reference in New Issue
Block a user