#include #include #include #include #include #include #include #include #include #include #include #include "eos.h" #include "net.h" #include "app.h" #include "cell.h" #include "power.h" #define PWR_ETYPE_SLEEP_REQ 1 #define PWR_ETYPE_SLEEP_RDY 2 #define PWR_ETYPE_WAKE 3 typedef struct { uint8_t type; uint8_t mode; uint32_t dev; } power_event_t; 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; static const char *TAG = "EOS POWER"; static QueueHandle_t power_queue; static void IRAM_ATTR net_wake_handler(void *arg) { power_event_t evt; evt.type = PWR_ETYPE_WAKE; evt.dev = EOS_PWR_DEV_NET; xQueueSendFromISR(power_queue, &evt, NULL); } static void IRAM_ATTR app_wake_handler(void *arg) { power_event_t evt; evt.type = PWR_ETYPE_WAKE; evt.dev = EOS_PWR_DEV_APP; xQueueSendFromISR(power_queue, &evt, NULL); } static void IRAM_ATTR modem_wake_handler(void *arg) { power_event_t evt; evt.type = PWR_ETYPE_WAKE; evt.dev = EOS_PWR_DEV_MODEM; xQueueSendFromISR(power_queue, &evt, NULL); } static void power_event_task(void *pvParameters) { power_event_t evt; uint8_t mode; uint32_t sleep_req, sleep_rdy; int sys_sleep; mode = 0; sys_sleep = 0; sleep_req = 0; sleep_rdy = 0; while (1) { if (xQueueReceive(power_queue, &evt, portMAX_DELAY)) { switch (evt.type) { 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(); } if ((evt.dev & EOS_PWR_DEV_APP) && !(sleep_req & EOS_PWR_DEV_APP)) { eos_app_sleep_req(); } 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 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 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; } } } } vTaskDelete(NULL); } void eos_power_init(void) { /* 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); ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, NULL, &power_lock_apb_freq); assert(ret == ESP_OK); ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, NULL, &power_lock_no_sleep); assert(ret == ESP_OK); ret = esp_pm_lock_acquire(power_lock_cpu_freq); assert(ret == ESP_OK); ret = esp_pm_lock_acquire(power_lock_apb_freq); assert(ret == ESP_OK); ret = esp_pm_lock_acquire(power_lock_no_sleep); assert(ret == ESP_OK); pwr_conf.max_freq_mhz = 160; pwr_conf.min_freq_mhz = 80; pwr_conf.light_sleep_enable = 1; ret = esp_pm_configure(&pwr_conf); assert(ret == ESP_OK); */ 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); } power_queue = xQueueCreate(4, sizeof(power_event_t)); assert(power_queue != NULL); ESP_LOGI(TAG, "INIT"); } void eos_power_run(void) { BaseType_t rv; rv = xTaskCreate(power_event_task, "power_event", EOS_TASK_SSIZE_PWR, NULL, EOS_TASK_PRIORITY_PWR, NULL); assert(rv == pdPASS); ESP_LOGI(TAG, "RUN"); } 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 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; } } } 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 { ESP_LOGE(TAG, "BAD WAKEUP CAUSE"); } return dev; } void eos_power_sleep_req(uint8_t mode, uint32_t dev) { power_event_t evt; evt.type = PWR_ETYPE_SLEEP_REQ; evt.mode = mode; evt.dev = dev; xQueueSend(power_queue, &evt, portMAX_DELAY); } void eos_power_sleep_rdy(uint32_t dev) { power_event_t evt; evt.type = PWR_ETYPE_SLEEP_RDY; evt.dev = dev; xQueueSend(power_queue, &evt, portMAX_DELAY); } void eos_power_wake(uint32_t dev) { power_event_t evt; ESP_LOGI(TAG, "WAKE SENT"); evt.type = PWR_ETYPE_WAKE; evt.dev = dev; xQueueSend(power_queue, &evt, portMAX_DELAY); }