diff options
Diffstat (limited to 'fw/esp32/components/eos/power.c')
-rw-r--r-- | fw/esp32/components/eos/power.c | 448 |
1 files changed, 175 insertions, 273 deletions
diff --git a/fw/esp32/components/eos/power.c b/fw/esp32/components/eos/power.c index b98c0ec..27c44a5 100644 --- a/fw/esp32/components/eos/power.c +++ b/fw/esp32/components/eos/power.c @@ -4,37 +4,30 @@ #include <freertos/task.h> #include <freertos/queue.h> #include <driver/gpio.h> +#include <driver/rtc_io.h> +#include <driver/uart.h> + +#include <esp_system.h> #include <esp_sleep.h> -#include <esp_timer.h> #include <esp_pm.h> #include <esp_log.h> -#include <esp32/rom/rtc.h> #include "eos.h" #include "net.h" +#include "app.h" #include "cell.h" #include "power.h" -#define POWER_GPIO_BTN 0 -#define POWER_GPIO_NET 5 -#define POWER_GPIO_UART 35 - -#define POWER_ETYPE_BTN 1 -#define POWER_ETYPE_SLEEP1 2 -#define POWER_ETYPE_SLEEP2 3 -#define POWER_ETYPE_WAKE 4 -#define POWER_ETYPE_NETRDY 5 +#define PWR_ETYPE_SLEEP_REQ 1 +#define PWR_ETYPE_SLEEP_RDY 2 +#define PWR_ETYPE_WAKE 3 typedef struct { uint8_t type; - union { - uint8_t source; - uint8_t level; - }; + uint8_t mode; + uint32_t dev; } power_event_t; -static esp_timer_handle_t timer; - static esp_pm_lock_handle_t power_lock_cpu_freq; static esp_pm_lock_handle_t power_lock_apb_freq; static esp_pm_lock_handle_t power_lock_no_sleep; @@ -43,232 +36,119 @@ static const char *TAG = "EOS POWER"; static QueueHandle_t power_queue; -static volatile int init_done = 0; -static volatile int wake_done = 0; - -static void IRAM_ATTR btn_handler(void *arg) { - power_event_t evt; - - evt.type = POWER_ETYPE_BTN; - evt.level = gpio_get_level(POWER_GPIO_BTN); - xQueueSendFromISR(power_queue, &evt, NULL); -} - -static void IRAM_ATTR btn_wake_handler(void *arg) { - power_event_t evt; - - gpio_intr_disable(POWER_GPIO_BTN); - - evt.type = POWER_ETYPE_WAKE; - evt.source = EOS_PWR_WAKE_BTN; - xQueueSendFromISR(power_queue, &evt, NULL); - -} - static void IRAM_ATTR net_wake_handler(void *arg) { power_event_t evt; - gpio_intr_disable(POWER_GPIO_NET); - - evt.type = POWER_ETYPE_WAKE; - evt.source = EOS_PWR_WAKE_NET; + evt.type = PWR_ETYPE_WAKE; + evt.dev = EOS_PWR_DEV_NET; xQueueSendFromISR(power_queue, &evt, NULL); } -static void IRAM_ATTR uart_wake_handler(void *arg) { +static void IRAM_ATTR app_wake_handler(void *arg) { power_event_t evt; - gpio_intr_disable(POWER_GPIO_UART); - - evt.type = POWER_ETYPE_WAKE; - evt.source = EOS_PWR_WAKE_UART; + evt.type = PWR_ETYPE_WAKE; + evt.dev = EOS_PWR_DEV_APP; xQueueSendFromISR(power_queue, &evt, NULL); } -static void timer_handler(void *arg) { +static void IRAM_ATTR modem_wake_handler(void *arg) { power_event_t evt; - evt.type = POWER_ETYPE_SLEEP2; + evt.type = PWR_ETYPE_WAKE; + evt.dev = EOS_PWR_DEV_MODEM; xQueueSendFromISR(power_queue, &evt, NULL); } -static void power_sleep_stage1(int modem_wake_en) { - gpio_config_t io_conf = {}; - - eos_modem_sleep(); - eos_net_sleep(); - - io_conf.intr_type = GPIO_INTR_DISABLE; - io_conf.mode = GPIO_MODE_INPUT; - io_conf.pin_bit_mask = ((uint64_t)1 << POWER_GPIO_NET); - io_conf.pull_up_en = 0; - io_conf.pull_down_en = 0; - gpio_config(&io_conf); - - gpio_isr_handler_add(POWER_GPIO_BTN, btn_wake_handler, NULL); - gpio_isr_handler_add(POWER_GPIO_NET, net_wake_handler, NULL); - if (modem_wake_en) { - gpio_isr_handler_add(POWER_GPIO_UART, uart_wake_handler, NULL); - } - - esp_sleep_enable_gpio_wakeup(); - gpio_wakeup_enable(POWER_GPIO_BTN, GPIO_INTR_LOW_LEVEL); - gpio_wakeup_enable(POWER_GPIO_NET, GPIO_INTR_LOW_LEVEL); - if (modem_wake_en) { - gpio_wakeup_enable(POWER_GPIO_UART, GPIO_INTR_LOW_LEVEL); - } - - esp_timer_start_once(timer, 10 * 1000000); - - esp_pm_lock_release(power_lock_cpu_freq); - esp_pm_lock_release(power_lock_apb_freq); - esp_pm_lock_release(power_lock_no_sleep); -} - -static void power_sleep_stage2(int modem_wake_en, uint8_t mode) { - switch (mode) { - case EOS_PWR_SMODE_LIGHT: { - ESP_LOGI(TAG, "LIGHT SLEEP"); - - esp_light_sleep_start(); - break; - } - - case EOS_PWR_SMODE_DEEP: { - esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); - - gpio_deep_sleep_hold_en(); - esp_sleep_enable_ext0_wakeup(POWER_GPIO_BTN, 0); - if (modem_wake_en) { - esp_sleep_enable_ext1_wakeup((uint64_t)1 << POWER_GPIO_UART, ESP_EXT1_WAKEUP_ALL_LOW); - } - - ESP_LOGI(TAG, "DEEP SLEEP"); - - eos_modem_deep_sleep(); - esp_deep_sleep_start(); - break; - } - } -} - -static void power_wake_stage1(uint8_t source, uint8_t mode) { - if (mode == EOS_PWR_SMODE_LIGHT) { - gpio_config_t io_conf = {}; - - esp_pm_lock_acquire(power_lock_cpu_freq); - esp_pm_lock_acquire(power_lock_apb_freq); - esp_pm_lock_acquire(power_lock_no_sleep); - - gpio_wakeup_disable(POWER_GPIO_BTN); - gpio_wakeup_disable(POWER_GPIO_NET); - gpio_wakeup_disable(POWER_GPIO_UART); - esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); - - gpio_isr_handler_remove(POWER_GPIO_NET); - io_conf.intr_type = GPIO_INTR_DISABLE; - io_conf.mode = GPIO_MODE_DISABLE; - io_conf.pin_bit_mask = ((uint64_t)1 << POWER_GPIO_NET); - io_conf.pull_up_en = 0; - io_conf.pull_down_en = 0; - gpio_config(&io_conf); - } - - gpio_intr_disable(POWER_GPIO_BTN); - if ((source != EOS_PWR_WAKE_BTN) && (source != EOS_PWR_WAKE_NET)) { - gpio_set_level(POWER_GPIO_BTN, 0); - gpio_set_direction(POWER_GPIO_BTN, GPIO_MODE_OUTPUT); - vTaskDelay(200 / portTICK_PERIOD_MS); - gpio_set_direction(POWER_GPIO_BTN, GPIO_MODE_INPUT); - } - - eos_net_wake(source, mode); -} - -static void power_wake_stage2(uint8_t source, uint8_t mode) { - eos_modem_wake(source, mode); - - gpio_set_intr_type(POWER_GPIO_BTN, GPIO_INTR_ANYEDGE); - gpio_isr_handler_add(POWER_GPIO_BTN, btn_handler, NULL); - - ESP_LOGI(TAG, "WAKE"); - wake_done = 1; -} - static void power_event_task(void *pvParameters) { power_event_t evt; - uint8_t source; - uint8_t wakeup_cause; uint8_t mode; - int sleep1, sleep2; - int modem_wake_en; + uint32_t sleep_req, sleep_rdy; + int sys_sleep; mode = 0; - source = 0; - wakeup_cause = eos_power_wakeup_cause(); - if (wakeup_cause != EOS_PWR_WAKE_RST) { - mode = EOS_PWR_SMODE_DEEP; - sleep1 = 1; - } else { - sleep1 = 0; - } - sleep2 = 0; - modem_wake_en = 0; - + sys_sleep = 0; + sleep_req = 0; + sleep_rdy = 0; while (1) { if (xQueueReceive(power_queue, &evt, portMAX_DELAY)) { switch (evt.type) { - case POWER_ETYPE_SLEEP1: { - if (!sleep1) { - modem_wake_en = eos_modem_present(); - mode = EOS_PWR_SMODE_LIGHT; - power_sleep_stage1(modem_wake_en); - sleep1 = 1; - sleep2 = 1; + case PWR_ETYPE_SLEEP_REQ: { + if (evt.mode) mode = evt.mode; + if ((evt.dev & EOS_PWR_DEV_NET) && !(sleep_req & EOS_PWR_DEV_NET)) { + eos_net_sleep_req(); } - break; - } - - case POWER_ETYPE_SLEEP2: { - if (sleep2) { - mode = EOS_PWR_SMODE_DEEP; - power_sleep_stage2(modem_wake_en, mode); - sleep2 = 0; + if ((evt.dev & EOS_PWR_DEV_APP) && !(sleep_req & EOS_PWR_DEV_APP)) { + eos_app_sleep_req(); } - break; - } - - case POWER_ETYPE_WAKE: { - if (sleep1) { - source = evt.source; - power_wake_stage1(source, mode); - if (sleep2) { - esp_timer_stop(timer); - sleep2 = 0; - } + if ((evt.dev & EOS_PWR_DEV_MODEM) && !(sleep_req & EOS_PWR_DEV_MODEM)) { + eos_modem_sleep_req(); + } + sleep_req |= evt.dev; + if (sleep_rdy == EOS_PWR_DEV_ALL) { + eos_power_sleep_rdy(0); } break; } - case POWER_ETYPE_NETRDY: { - power_wake_stage2(source, mode); - sleep1 = 0; - source = 0; + case PWR_ETYPE_SLEEP_RDY: { + gpio_config_t io_conf = { + .mode = GPIO_MODE_INPUT, + .intr_type = GPIO_INTR_NEGEDGE, + .pull_up_en = 1, + .pull_down_en = 0, + }; + + if (evt.dev & EOS_PWR_DEV_NET) { + io_conf.pin_bit_mask = BIT64(EOS_PWR_GPIO_NET); + gpio_config(&io_conf); + gpio_isr_handler_add(EOS_PWR_GPIO_NET, net_wake_handler, NULL); + } + if (evt.dev & EOS_PWR_DEV_APP) { + io_conf.pin_bit_mask = BIT64(EOS_PWR_GPIO_APP); + gpio_config(&io_conf); + gpio_isr_handler_add(EOS_PWR_GPIO_APP, app_wake_handler, NULL); + } + if (evt.dev & EOS_PWR_DEV_MODEM) { + io_conf.pin_bit_mask = BIT64(EOS_PWR_GPIO_MODEM); + gpio_config(&io_conf); + gpio_isr_handler_add(EOS_PWR_GPIO_MODEM, modem_wake_handler, NULL); + } + sleep_rdy |= evt.dev; + if (!sys_sleep && mode && (sleep_rdy == EOS_PWR_DEV_ALL)) { + sys_sleep = 1; + eos_power_sys_sleep(mode); + } break; } - case POWER_ETYPE_BTN: { - unsigned char *buf; - - buf = eos_net_alloc(); - buf[0] = EOS_PWR_MTYPE_BUTTON; - buf[1] = evt.level; - eos_net_send(EOS_NET_MTYPE_POWER, buf, 2); + case PWR_ETYPE_WAKE: { + ESP_LOGI(TAG, "WAKE:0x%.8lX", evt.dev); + if (sys_sleep) { + eos_power_sys_wake(mode); + sys_sleep = 0; + mode = 0; + } + if ((evt.dev & EOS_PWR_DEV_NET) && (sleep_rdy & EOS_PWR_DEV_NET)) { + gpio_isr_handler_remove(EOS_PWR_GPIO_NET); + gpio_reset_pin(EOS_PWR_GPIO_NET); + eos_net_wake(); + } + if ((evt.dev & EOS_PWR_DEV_APP) && (sleep_rdy & EOS_PWR_DEV_APP)) { + gpio_isr_handler_remove(EOS_PWR_GPIO_APP); + gpio_reset_pin(EOS_PWR_GPIO_APP); + eos_app_wake(); + } + if ((evt.dev & EOS_PWR_DEV_MODEM) && (sleep_rdy & EOS_PWR_DEV_MODEM)) { + gpio_isr_handler_remove(EOS_PWR_GPIO_MODEM); + gpio_reset_pin(EOS_PWR_GPIO_MODEM); + eos_modem_wake(); + } + sleep_req &= ~evt.dev; + sleep_rdy &= ~evt.dev; + ESP_LOGI(TAG, "WAKE DONE:0x%.8lX", evt.dev); break; } - - default: - break; } } } @@ -276,35 +156,9 @@ static void power_event_task(void *pvParameters) { } void eos_power_init(void) { - esp_err_t ret; - gpio_config_t io_conf = {}; - esp_timer_create_args_t timer_args = {}; - esp_pm_config_esp32_t pwr_conf; - uint8_t wakeup_cause; - - io_conf.intr_type = GPIO_INTR_ANYEDGE; - io_conf.mode = GPIO_MODE_INPUT; - io_conf.pin_bit_mask = ((uint64_t)1 << POWER_GPIO_BTN); - io_conf.pull_up_en = 1; - io_conf.pull_down_en = 0; - gpio_config(&io_conf); - gpio_isr_handler_add(POWER_GPIO_BTN, btn_handler, NULL); - - timer_args.callback = timer_handler, - timer_args.arg = NULL; - timer_args.name = "sleep"; - - ret = esp_timer_create(&timer_args, &timer); - assert(ret == ESP_OK); - /* - ret = esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); - assert(ret == ESP_OK); - ret = esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_ON); - assert(ret == ESP_OK); - ret = esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON); - assert(ret == ESP_OK); - */ + esp_err_t ret; + esp_pm_config_t pwr_conf; ret = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, NULL, &power_lock_cpu_freq); assert(ret == ESP_OK); @@ -326,70 +180,118 @@ void eos_power_init(void) { ret = esp_pm_configure(&pwr_conf); assert(ret == ESP_OK); + */ - power_queue = xQueueCreate(4, sizeof(power_event_t)); - xTaskCreate(power_event_task, "power_event", EOS_TASK_SSIZE_PWR, NULL, EOS_TASK_PRIORITY_PWR, NULL); - - wakeup_cause = eos_power_wakeup_cause(); - if (wakeup_cause != EOS_PWR_WAKE_RST) { - eos_power_wake(wakeup_cause); + if (esp_reset_reason() == ESP_RST_DEEPSLEEP) { + rtc_gpio_deinit(EOS_PWR_GPIO_NET); + rtc_gpio_deinit(EOS_PWR_GPIO_APP); + rtc_gpio_deinit(EOS_PWR_GPIO_MODEM); + eos_power_sys_wake(EOS_PWR_SMODE_DEEP); } - init_done = 1; + power_queue = xQueueCreate(4, sizeof(power_event_t)); + assert(power_queue != NULL); + ESP_LOGI(TAG, "INIT"); } -void eos_power_wait4init(void) { - while (!init_done); -} +void eos_power_run(void) { + BaseType_t rv; -void eos_power_wait4wake(void) { - if (eos_power_wakeup_cause() == EOS_PWR_WAKE_RST) return; - while (!wake_done); -} + rv = xTaskCreate(power_event_task, "power_event", EOS_TASK_SSIZE_PWR, NULL, EOS_TASK_PRIORITY_PWR, NULL); + assert(rv == pdPASS); -uint8_t eos_power_wakeup_cause(void) { - esp_reset_reason_t reset_cause = esp_reset_reason(); - esp_sleep_wakeup_cause_t wakeup_cause = esp_sleep_get_wakeup_cause(); + ESP_LOGI(TAG, "RUN"); +} - if (reset_cause == ESP_RST_DEEPSLEEP) { - switch (wakeup_cause) { - case ESP_SLEEP_WAKEUP_EXT0: - return EOS_PWR_WAKE_BTN; +void eos_power_sys_sleep(uint8_t mode) { + switch (mode) { + case EOS_PWR_SMODE_TICKLESS: { + esp_pm_lock_release(power_lock_cpu_freq); + esp_pm_lock_release(power_lock_apb_freq); + esp_pm_lock_release(power_lock_no_sleep); + break; + } - case ESP_SLEEP_WAKEUP_EXT1: - return EOS_PWR_WAKE_UART; + case EOS_PWR_SMODE_LIGHT: + case EOS_PWR_SMODE_DEEP: { + esp_err_t ret; + + /* in case of missing modem */ + rtc_gpio_pullup_en(EOS_PWR_GPIO_MODEM); + esp_sleep_enable_ext1_wakeup_io(EOS_PWR_DEV_ALL, ESP_EXT1_WAKEUP_ANY_LOW); + if (mode == EOS_PWR_SMODE_DEEP) { + gpio_deep_sleep_hold_en(); + esp_deep_sleep_start(); + } else { + ESP_LOGI(TAG, "LIGHT SLEEP"); + uart_wait_tx_idle_polling(UART_NUM_0); + ret = esp_light_sleep_start(); + ESP_LOGI(TAG, "LIGHT WAKE: %d", ret); + eos_power_wake(eos_power_wakeup_source()); + } + break; + } + } +} - default: - return EOS_PWR_WAKE_UNDEF; +void eos_power_sys_wake(uint8_t mode) { + switch (mode) { + case EOS_PWR_SMODE_TICKLESS: { + esp_pm_lock_acquire(power_lock_cpu_freq); + esp_pm_lock_acquire(power_lock_apb_freq); + esp_pm_lock_acquire(power_lock_no_sleep); + break; + } + case EOS_PWR_SMODE_LIGHT: + case EOS_PWR_SMODE_DEEP: { + rtc_gpio_pullup_dis(EOS_PWR_GPIO_MODEM); + esp_sleep_disable_ext1_wakeup_io(0); + if (mode == EOS_PWR_SMODE_DEEP) { + gpio_deep_sleep_hold_dis(); + } + break; } + } +} + +uint32_t eos_power_wakeup_source(void) { + esp_sleep_wakeup_cause_t wakeup_cause; + uint32_t dev; + + dev = EOS_PWR_DEV_NONE; + wakeup_cause = esp_sleep_get_wakeup_cause(); + if (wakeup_cause == ESP_SLEEP_WAKEUP_EXT1) { + dev = esp_sleep_get_ext1_wakeup_status(); + return dev; } else { - return EOS_PWR_WAKE_RST; + ESP_LOGE(TAG, "BAD WAKEUP CAUSE"); } + return dev; } -void eos_power_sleep(void) { +void eos_power_sleep_req(uint8_t mode, uint32_t dev) { power_event_t evt; - evt.type = POWER_ETYPE_SLEEP1; - evt.source = 0; + evt.type = PWR_ETYPE_SLEEP_REQ; + evt.mode = mode; + evt.dev = dev; xQueueSend(power_queue, &evt, portMAX_DELAY); } -void eos_power_wake(uint8_t source) { +void eos_power_sleep_rdy(uint32_t dev) { power_event_t evt; - evt.type = POWER_ETYPE_WAKE; - evt.source = source; - + evt.type = PWR_ETYPE_SLEEP_RDY; + evt.dev = dev; xQueueSend(power_queue, &evt, portMAX_DELAY); } -void eos_power_net_ready(void) { +void eos_power_wake(uint32_t dev) { power_event_t evt; - evt.type = POWER_ETYPE_NETRDY; - evt.source = 0; - + ESP_LOGI(TAG, "WAKE SENT"); + evt.type = PWR_ETYPE_WAKE; + evt.dev = dev; xQueueSend(power_queue, &evt, portMAX_DELAY); } |