|
@@ -7,7 +7,11 @@
|
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
|
+#include "freertos/FreeRTOS.h"
|
|
|
+#include "freertos/timers.h"
|
|
|
#include "esp_log.h"
|
|
|
+#include "esp_sleep.h"
|
|
|
+#include "driver/rtc_io.h"
|
|
|
#include "driver/gpio.h"
|
|
|
#include "driver/ledc.h"
|
|
|
#include "driver/i2c.h"
|
|
@@ -20,6 +24,8 @@
|
|
|
#include "globdefs.h"
|
|
|
#include "accessors.h"
|
|
|
#include "messaging.h"
|
|
|
+#include "buttons.h"
|
|
|
+#include "services.h"
|
|
|
|
|
|
extern void battery_svc_init(void);
|
|
|
extern void monitor_svc_init(void);
|
|
@@ -30,11 +36,19 @@ int i2c_system_speed = 400000;
|
|
|
int spi_system_host = SPI_SYSTEM_HOST;
|
|
|
int spi_system_dc_gpio = -1;
|
|
|
int rmt_system_base_channel = RMT_CHANNEL_0;
|
|
|
+
|
|
|
pwm_system_t pwm_system = {
|
|
|
.timer = LEDC_TIMER_0,
|
|
|
.base_channel = LEDC_CHANNEL_0,
|
|
|
.max = (1 << LEDC_TIMER_13_BIT),
|
|
|
- };
|
|
|
+};
|
|
|
+
|
|
|
+static EXT_RAM_ATTR struct {
|
|
|
+ uint64_t wake_gpio, wake_level;
|
|
|
+ uint32_t delay;
|
|
|
+} sleep_config;
|
|
|
+
|
|
|
+static EXT_RAM_ATTR void (*sleep_hooks[16])(void);
|
|
|
|
|
|
static const char *TAG = "services";
|
|
|
|
|
@@ -60,6 +74,9 @@ void set_chip_power_gpio(int gpio, char *value) {
|
|
|
if (parsed) ESP_LOGI(TAG, "set GPIO %u to %s", gpio, value);
|
|
|
}
|
|
|
|
|
|
+/****************************************************************************************
|
|
|
+ *
|
|
|
+ */
|
|
|
void set_exp_power_gpio(int gpio, char *value) {
|
|
|
bool parsed = true;
|
|
|
|
|
@@ -75,8 +92,113 @@ void set_exp_power_gpio(int gpio, char *value) {
|
|
|
} else parsed = false;
|
|
|
|
|
|
if (parsed) ESP_LOGI(TAG, "set expanded GPIO %u to %s", gpio, value);
|
|
|
- }
|
|
|
-
|
|
|
+}
|
|
|
+
|
|
|
+/****************************************************************************************
|
|
|
+ *
|
|
|
+ */
|
|
|
+static void sleep_gpio_handler(void *id, button_event_e event, button_press_e mode, bool long_press) {
|
|
|
+ if (event == BUTTON_PRESSED) services_sleep_activate(SLEEP_ONGPIO);
|
|
|
+}
|
|
|
+
|
|
|
+/****************************************************************************************
|
|
|
+ *
|
|
|
+ */
|
|
|
+static void sleep_init(void) {
|
|
|
+ char *config = config_alloc_get(NVS_TYPE_STR, "sleep_config");
|
|
|
+ char *p;
|
|
|
+
|
|
|
+ // do we want delay sleep
|
|
|
+ PARSE_PARAM(config, "delay", '=', sleep_config.delay);
|
|
|
+ sleep_config.delay *= 60*1000;
|
|
|
+ if (sleep_config.delay) {
|
|
|
+ ESP_LOGI(TAG, "Sleep inactivity of %d minute(s)", sleep_config.delay / (60*1000));
|
|
|
+ }
|
|
|
+
|
|
|
+ // get the wake criteria
|
|
|
+ if ((p = strcasestr(config, "wake"))) {
|
|
|
+ char list[32] = "", item[8];
|
|
|
+ sscanf(p, "%*[^=]=%31[^,]", list);
|
|
|
+ p = list - 1;
|
|
|
+ while (p++ && sscanf(p, "%7[^|]", item)) {
|
|
|
+ int level = 0, gpio = atoi(item);
|
|
|
+ if (!rtc_gpio_is_valid_gpio(gpio)) {
|
|
|
+ ESP_LOGE(TAG, "invalid wake GPIO %d (not in RTC domain)", gpio);
|
|
|
+ } else {
|
|
|
+ sleep_config.wake_gpio |= 1LL << gpio;
|
|
|
+ }
|
|
|
+ if (sscanf(item, "%*[^:]:%d", &level)) sleep_config.wake_level |= level << gpio;
|
|
|
+ p = strchr(p, '|');
|
|
|
+ }
|
|
|
+
|
|
|
+ // when moving to esp-idf more recent than 4.4.x, multiple gpio wake-up with level specific can be done
|
|
|
+ if (sleep_config.wake_gpio) {
|
|
|
+ ESP_LOGI(TAG, "Sleep wake-up gpio bitmap 0x%llx (active 0x%llx)", sleep_config.wake_gpio, sleep_config.wake_level);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // then get the gpio that activate sleep (we could check that we have a valid wake)
|
|
|
+ if ((p = strcasestr(config, "sleep"))) {
|
|
|
+ int gpio, level = 0;
|
|
|
+ char sleep[8] = "";
|
|
|
+ sscanf(p, "%*[^=]=%7[^,]", sleep);
|
|
|
+ gpio = atoi(sleep);
|
|
|
+ if ((p = strchr(sleep, ':')) != NULL) level = atoi(p + 1);
|
|
|
+ ESP_LOGI(TAG, "Sleep activation gpio %d (active %d)", gpio, level);
|
|
|
+ button_create(NULL, gpio, level ? BUTTON_HIGH : BUTTON_LOW, true, 0, sleep_gpio_handler, 0, -1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/****************************************************************************************
|
|
|
+ *
|
|
|
+ */
|
|
|
+void services_sleep_callback(uint32_t elapsed) {
|
|
|
+ if (sleep_config.delay && elapsed >= sleep_config.delay) {
|
|
|
+ services_sleep_activate(SLEEP_ONTIMER);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/****************************************************************************************
|
|
|
+ *
|
|
|
+ */
|
|
|
+void services_sleep_activate(sleep_cause_e cause) {
|
|
|
+ // call all sleep hooks that might want to do something
|
|
|
+ for (void (**hook)(void) = sleep_hooks; *hook; hook++) (*hook)();
|
|
|
+
|
|
|
+ // isolate all possible GPIOs, except the wake-up ones
|
|
|
+ esp_sleep_config_gpio_isolate();
|
|
|
+ for (int i = 0; i < GPIO_NUM_MAX; i++) {
|
|
|
+ if (!rtc_gpio_is_valid_gpio(i) || ((1LL << i) & sleep_config.wake_gpio)) continue;
|
|
|
+ rtc_gpio_isolate(i);
|
|
|
+ }
|
|
|
+
|
|
|
+ // is there just one GPIO
|
|
|
+ if (sleep_config.wake_gpio & (sleep_config.wake_gpio - 1)) {
|
|
|
+ ESP_LOGI(TAG, "going to sleep cause %d, wake-up on multiple GPIO, any '1' wakes up 0x%llx", cause, sleep_config.wake_gpio);
|
|
|
+ esp_sleep_enable_ext1_wakeup(sleep_config.wake_gpio, ESP_EXT1_WAKEUP_ANY_HIGH);
|
|
|
+ } else {
|
|
|
+ int gpio = __builtin_ctz(sleep_config.wake_gpio);
|
|
|
+ int level = (sleep_config.wake_level >> gpio) & 0x01;
|
|
|
+ ESP_LOGI(TAG, "going to sleep cause %d, wake-up on GPIO %d level %d", cause, gpio, level);
|
|
|
+ esp_sleep_enable_ext0_wakeup(gpio, level);
|
|
|
+ }
|
|
|
+
|
|
|
+ // we need to use a timer in case the same button is used for sleep and wake-up and it's "pressed" vs "released" selected
|
|
|
+ if (cause == SLEEP_ONKEY) xTimerStart(xTimerCreate("sleepTimer", pdMS_TO_TICKS(1000), pdFALSE, NULL, (void (*)(void*)) esp_deep_sleep_start), 0);
|
|
|
+ else esp_deep_sleep_start();
|
|
|
+}
|
|
|
+
|
|
|
+/****************************************************************************************
|
|
|
+ *
|
|
|
+ */
|
|
|
+void services_sleep_sethook(void (*hook)(void)) {
|
|
|
+ for (int i = 0; i < sizeof(sleep_hooks)/sizeof(void(*)(void)); i++) {
|
|
|
+ if (!sleep_hooks[i]) {
|
|
|
+ sleep_hooks[i] = hook;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
/****************************************************************************************
|
|
|
*
|
|
@@ -147,5 +269,6 @@ void services_init(void) {
|
|
|
|
|
|
led_svc_init();
|
|
|
battery_svc_init();
|
|
|
- monitor_svc_init();
|
|
|
+ monitor_svc_init();
|
|
|
+ sleep_init();
|
|
|
}
|