From 375ac3b0c7e9ed8b2d2d0fc4d0700a23c8865836 Mon Sep 17 00:00:00 2001
From: Uros Majstorovic <majstor@majstor.org>
Date: Sun, 24 May 2020 00:00:38 +0200
Subject: esp32 deep sleep implemented

---
 code/esp32/components/eos/cell_modem.c    |  36 ++++---
 code/esp32/components/eos/include/cell.h  |   4 +-
 code/esp32/components/eos/include/i2c.h   |   1 +
 code/esp32/components/eos/include/net.h   |   5 +-
 code/esp32/components/eos/include/power.h |   7 ++
 code/esp32/components/eos/net.c           |  17 ++-
 code/esp32/components/eos/power.c         | 166 +++++++++++++++++++++---------
 code/esp32/main/app_main.c                |   7 +-
 8 files changed, 171 insertions(+), 72 deletions(-)

(limited to 'code')

diff --git a/code/esp32/components/eos/cell_modem.c b/code/esp32/components/eos/cell_modem.c
index 589f1d8..5315861 100644
--- a/code/esp32/components/eos/cell_modem.c
+++ b/code/esp32/components/eos/cell_modem.c
@@ -9,6 +9,7 @@
 #include <netif/ppp/pppapi.h>
 #include <driver/uart.h>
 #include <driver/gpio.h>
+#include <esp_sleep.h>
 #include <esp_log.h>
 
 #include "eos.h"
@@ -44,7 +45,7 @@ static QueueHandle_t uart_queue;
 static char uart_buf[UART_SIZE_URC_BUF];
 static unsigned int uart_buf_len;
 
-static uint8_t uart_mode = EOS_CELL_UART_MODE_NONE;
+static uint8_t uart_mode = EOS_CELL_UART_MODE_ATCMD;
 static SemaphoreHandle_t uart_mutex;
 
 static char ppp_apn[64];
@@ -107,10 +108,11 @@ static void uart_data_read(uint8_t mode) {
 }
 
 static void uart_event_task(void *pvParameters) {
-    char mode = EOS_CELL_UART_MODE_NONE;
-    char _mode = EOS_CELL_UART_MODE_NONE;
+    char mode = EOS_CELL_UART_MODE_ATCMD;
+    char _mode = EOS_CELL_UART_MODE_ATCMD;
     uart_event_t event;
 
+    xSemaphoreTake(uart_mutex, portMAX_DELAY);
     while (1) {
         /* Waiting for UART event.
          */
@@ -196,10 +198,10 @@ static int modem_atcmd_init(void) {
     r = at_expect("^ATE0", NULL, 1000);
     r = at_expect("^OK", "^ERROR", 1000);
 
-    eos_modem_write("AT+CSCLK=1\r", 11);
-    r = at_expect("^OK", "^ERROR", 1000);
     eos_modem_write("AT+CFGRI=1\r", 11);
     r = at_expect("^OK", "^ERROR", 1000);
+    eos_modem_write("AT+CSCLK=1\r", 11);
+    r = at_expect("^OK", "^ERROR", 1000);
 
     buf = eos_net_alloc();
     buf[0] = EOS_CELL_MTYPE_READY;
@@ -700,7 +702,7 @@ void eos_modem_give(void) {
     xSemaphoreGive(mutex);
 }
 
-void eos_modem_sleep(void) {
+void eos_modem_sleep(uint8_t mode) {
     int r;
 
     xSemaphoreTake(mutex, portMAX_DELAY);
@@ -710,22 +712,30 @@ void eos_modem_sleep(void) {
         ESP_LOGE(TAG, "Obtaining mutex before sleep failed");
     }
     gpio_set_level(UART_GPIO_DTR, 1);
+    if (mode == EOS_PWR_SMODE_DEEP) {
+        gpio_hold_en(UART_GPIO_DTR);
+    }
 }
 
-void eos_modem_wake(uint8_t source) {
+void eos_modem_wake(uint8_t source, uint8_t mode) {
     if (source == EOS_PWR_WAKE_UART) {
         modem_event_t evt;
 
         evt.type = MODEM_ETYPE_RI;
         xQueueSend(modem_queue, &evt, portMAX_DELAY);
     }
-    gpio_set_intr_type(UART_GPIO_RI, GPIO_INTR_NEGEDGE);
-    gpio_isr_handler_add(UART_GPIO_RI, uart_ri_isr_handler, NULL);
 
-    gpio_set_level(UART_GPIO_DTR, 0);
-    modem_set_mode(uart_mode);
-    xSemaphoreGive(uart_mutex);
-    xSemaphoreGive(mutex);
+    if (mode != EOS_PWR_SMODE_DEEP) {
+        gpio_set_intr_type(UART_GPIO_RI, GPIO_INTR_NEGEDGE);
+        gpio_isr_handler_add(UART_GPIO_RI, uart_ri_isr_handler, NULL);
+        gpio_set_level(UART_GPIO_DTR, 0);
+
+        modem_set_mode(uart_mode);
+        xSemaphoreGive(uart_mutex);
+        xSemaphoreGive(mutex);
+    } else {
+        gpio_hold_dis(UART_GPIO_DTR);
+    }
 }
 
 void eos_ppp_set_apn(char *apn) {
diff --git a/code/esp32/components/eos/include/cell.h b/code/esp32/components/eos/include/cell.h
index 17847ce..23adecf 100644
--- a/code/esp32/components/eos/include/cell.h
+++ b/code/esp32/components/eos/include/cell.h
@@ -35,8 +35,8 @@ int eos_modem_set_mode(uint8_t mode);
 int eos_modem_take(uint32_t timeout);
 void eos_modem_give(void);
 
-void eos_modem_sleep(void);
-void eos_modem_wake(uint8_t source);
+void eos_modem_sleep(uint8_t mode);
+void eos_modem_wake(uint8_t source, uint8_t mode);
 
 void eos_ppp_set_apn(char *apn);
 void eos_ppp_set_auth(char *user, char *pass);
diff --git a/code/esp32/components/eos/include/i2c.h b/code/esp32/components/eos/include/i2c.h
index 995a77e..144f5e1 100644
--- a/code/esp32/components/eos/include/i2c.h
+++ b/code/esp32/components/eos/include/i2c.h
@@ -2,6 +2,7 @@
 #include <stdint.h>
 
 void eos_i2c_init(void);
+
 int eos_i2c_read(uint8_t addr, uint8_t reg, uint8_t *data, size_t len);
 uint8_t eos_i2c_read8(uint8_t addr, uint8_t reg);
 int eos_i2c_write(uint8_t addr, uint8_t reg, uint8_t *data, size_t len);
diff --git a/code/esp32/components/eos/include/net.h b/code/esp32/components/eos/include/net.h
index 818776e..54bad6d 100644
--- a/code/esp32/components/eos/include/net.h
+++ b/code/esp32/components/eos/include/net.h
@@ -25,9 +25,10 @@
 typedef void (*eos_net_fptr_t) (unsigned char, unsigned char *, uint16_t);
 
 void eos_net_init(void);
+
 unsigned char *eos_net_alloc(void);
 void eos_net_free(unsigned char *buf);
 int eos_net_send(unsigned char mtype, unsigned char *buffer, uint16_t len, uint8_t flags);
 void eos_net_set_handler(unsigned char mtype, eos_net_fptr_t handler);
-void eos_net_sleep_done(void);
-void eos_net_wake(uint8_t source);
+void eos_net_sleep_done(uint8_t mode);
+void eos_net_wake(uint8_t source, uint8_t mode);
diff --git a/code/esp32/components/eos/include/power.h b/code/esp32/components/eos/include/power.h
index 8a35a04..0a57b19 100644
--- a/code/esp32/components/eos/include/power.h
+++ b/code/esp32/components/eos/include/power.h
@@ -2,12 +2,19 @@
 
 #define EOS_PWR_MTYPE_BUTTON    0
 
+#define EOS_PWR_WAKE_RST        0
 #define EOS_PWR_WAKE_BTN        1
 #define EOS_PWR_WAKE_NET        2
 #define EOS_PWR_WAKE_MSG        3
 #define EOS_PWR_WAKE_UART       4
 
+#define EOS_PWR_SMODE_LIGHT     1
+#define EOS_PWR_SMODE_DEEP      2
+
 void eos_power_init(void);
+
+void eos_power_wait4init(void);
+uint8_t eos_power_wakeup_cause(void);
 void eos_power_sleep(void);
 void eos_power_wake(uint8_t source);
 void eos_power_net_ready(void);
\ No newline at end of file
diff --git a/code/esp32/components/eos/net.c b/code/esp32/components/eos/net.c
index 07434f7..9a4a024 100644
--- a/code/esp32/components/eos/net.c
+++ b/code/esp32/components/eos/net.c
@@ -27,7 +27,7 @@
 
 #define SPI_SIZE_BUF        (EOS_NET_SIZE_BUF + 8)
 
-static volatile char net_sleep;
+static volatile char net_sleep = 0;
 
 static EOSBufQ net_buf_q;
 static unsigned char *net_bufq_array[EOS_NET_SIZE_BUFQ];
@@ -94,6 +94,12 @@ static void net_xchg_task(void *pvParameters) {
     spi_tr.tx_buffer = buf_send;
     spi_tr.rx_buffer = buf_recv;
 
+    if (eos_power_wakeup_cause()) {
+        wake = 1;
+        repeat = 1;
+    }
+
+    eos_power_wait4init();
     while (1) {
         if (!repeat) {
             xSemaphoreTake(mutex, portMAX_DELAY);
@@ -127,7 +133,7 @@ static void net_xchg_task(void *pvParameters) {
         buf_recv[1] = 0;
         buf_recv[2] = 0;
         spi_slave_transmit(VSPI_HOST, &spi_tr, portMAX_DELAY);
-        // ESP_LOGD(TAG, "RECV:%d", buf_recv[0]);
+        ESP_LOGD(TAG, "RECV:%d", buf_recv[0]);
 
         if (wake) {
             eos_power_net_ready();
@@ -154,9 +160,9 @@ static void net_xchg_task(void *pvParameters) {
                 net_sleep = 0;
                 xSemaphoreGive(mutex);
 
+                spi_slave_initialize(VSPI_HOST, &spi_bus_cfg, &spi_slave_cfg, 1);
                 wake = 1;
                 repeat = 1;
-                spi_slave_initialize(VSPI_HOST, &spi_bus_cfg, &spi_slave_cfg, 1);
             }
             continue;
         }
@@ -258,15 +264,16 @@ void eos_net_set_handler(unsigned char mtype, eos_net_fptr_t handler) {
     mtype_handler[mtype-1] = handler;
 }
 
-void eos_net_sleep_done(void) {
+void eos_net_sleep_done(uint8_t mode) {
     gpio_set_level(SPI_GPIO_CTS, 1);
     vTaskDelay(200 / portTICK_PERIOD_MS);
     gpio_set_level(SPI_GPIO_CTS, 0);
 }
 
-void eos_net_wake(uint8_t source) {
+void eos_net_wake(uint8_t source, uint8_t mode) {
     int sleep;
 
+    if (mode == EOS_PWR_SMODE_DEEP) return;
     do {
         vTaskResume(net_xchg_task_handle);
         vTaskDelay(10 / portTICK_PERIOD_MS);
diff --git a/code/esp32/components/eos/power.c b/code/esp32/components/eos/power.c
index 77f2d05..f07e67b 100644
--- a/code/esp32/components/eos/power.c
+++ b/code/esp32/components/eos/power.c
@@ -13,14 +13,14 @@
 #include "cell.h"
 #include "power.h"
 
-#define POWER_GPIO_BTN        0
-#define POWER_GPIO_NET        5
-#define POWER_GPIO_UART       35
+#define POWER_GPIO_BTN      0
+#define POWER_GPIO_NET      5
+#define POWER_GPIO_UART     35
 
-#define POWER_ETYPE_BTN       1
-#define POWER_ETYPE_SLEEP     2
-#define POWER_ETYPE_WAKE      3
-#define POWER_ETYPE_NETRDY    4
+#define POWER_ETYPE_BTN     1
+#define POWER_ETYPE_SLEEP   2
+#define POWER_ETYPE_WAKE    3
+#define POWER_ETYPE_NETRDY  4
 
 typedef struct {
     uint8_t type;
@@ -38,6 +38,8 @@ static const char *TAG = "EOS POWER";
 
 static QueueHandle_t power_queue;
 
+static volatile int init_done = 0;
+
 static void IRAM_ATTR btn_handler(void *arg) {
     power_event_t evt;
 
@@ -77,51 +79,71 @@ static void IRAM_ATTR uart_wake_handler(void *arg) {
     xQueueSendFromISR(power_queue, &evt, NULL);
 }
 
-void power_sleep(void) {
+void power_sleep(uint8_t mode) {
     gpio_config_t io_conf;
 
-    eos_modem_sleep();
+    eos_modem_sleep(mode);
+    eos_net_sleep_done(mode);
 
-    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);
+    switch (mode) {
+        case EOS_PWR_SMODE_LIGHT:
+            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);
-    gpio_isr_handler_add(POWER_GPIO_UART, uart_wake_handler, NULL);
+            gpio_isr_handler_add(POWER_GPIO_BTN, btn_wake_handler, NULL);
+            gpio_isr_handler_add(POWER_GPIO_NET, net_wake_handler, NULL);
+            gpio_isr_handler_add(POWER_GPIO_UART, uart_wake_handler, NULL);
 
-    gpio_wakeup_enable(POWER_GPIO_BTN, GPIO_INTR_LOW_LEVEL);
-    gpio_wakeup_enable(POWER_GPIO_NET, GPIO_INTR_LOW_LEVEL);
-    gpio_wakeup_enable(POWER_GPIO_UART, GPIO_INTR_LOW_LEVEL);
+            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);
+            gpio_wakeup_enable(POWER_GPIO_UART, GPIO_INTR_LOW_LEVEL);
 
-    eos_net_sleep_done();
+            ESP_LOGD(TAG, "SLEEP");
 
-    ESP_LOGD(TAG, "SLEEP");
+            esp_pm_lock_release(power_lock_apb_freq);
+            esp_pm_lock_release(power_lock_no_sleep);
 
-    esp_pm_lock_release(power_lock_apb_freq);
-    esp_pm_lock_release(power_lock_no_sleep);
-}
+            break;
 
-void power_wake_stage1(uint8_t source) {
-    gpio_config_t io_conf;
+        case EOS_PWR_SMODE_DEEP:
+            gpio_deep_sleep_hold_en();
+            esp_sleep_enable_ext0_wakeup(POWER_GPIO_BTN, 0);
+            esp_sleep_enable_ext1_wakeup((uint64_t)1 << POWER_GPIO_UART, ESP_EXT1_WAKEUP_ALL_LOW);
 
-    esp_pm_lock_acquire(power_lock_apb_freq);
-    esp_pm_lock_acquire(power_lock_no_sleep);
+            ESP_LOGD(TAG, "SLEEP");
 
-    gpio_wakeup_disable(POWER_GPIO_BTN);
-    gpio_wakeup_disable(POWER_GPIO_NET);
-    gpio_wakeup_disable(POWER_GPIO_UART);
+            esp_deep_sleep_start();
+            break;
 
-    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);
+        default:
+            break;
+    }
+}
+
+void power_wake_stage1(uint8_t source, uint8_t mode) {
+    gpio_config_t io_conf;
+
+    if (mode == EOS_PWR_SMODE_LIGHT) {
+        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);
+
+        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)) {
@@ -130,11 +152,12 @@ void power_wake_stage1(uint8_t source) {
         vTaskDelay(200 / portTICK_PERIOD_MS);
         gpio_set_direction(POWER_GPIO_BTN, GPIO_MODE_INPUT);
     }
-    eos_net_wake(source);
+
+    eos_net_wake(source, mode);
 }
 
-void power_wake_stage2(uint8_t source) {
-    eos_modem_wake(source);
+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);
@@ -145,15 +168,28 @@ void power_wake_stage2(uint8_t source) {
 static void power_event_task(void *pvParameters) {
     unsigned char *buf;
     power_event_t evt;
-    uint8_t source = 0;
-    int sleep = 0;
+    uint8_t source;
+    uint8_t wakeup_cause;
+    uint8_t mode;
+    int sleep;
+
+    source = 0;
+    wakeup_cause = eos_power_wakeup_cause();
+    if (wakeup_cause) {
+        mode = EOS_PWR_SMODE_DEEP;
+        sleep = 1;
+    } else {
+        mode = EOS_PWR_SMODE_LIGHT;
+        sleep = 0;
+    }
 
     while (1) {
         if (xQueueReceive(power_queue, &evt, portMAX_DELAY)) {
             switch (evt.type) {
                 case POWER_ETYPE_SLEEP:
                     if (!sleep) {
-                        power_sleep();
+                        mode = EOS_PWR_SMODE_DEEP;
+                        power_sleep(mode);
                         sleep = 1;
                     }
                     break;
@@ -161,13 +197,13 @@ static void power_event_task(void *pvParameters) {
                 case POWER_ETYPE_WAKE:
                     if (sleep) {
                         source = evt.source;
-                        power_wake_stage1(source);
+                        power_wake_stage1(source, mode);
                     }
                     break;
 
                 case POWER_ETYPE_NETRDY:
                     if (sleep && source) {
-                        power_wake_stage2(source);
+                        power_wake_stage2(source, mode);
                         sleep = 0;
                         source = 0;
                     }
@@ -192,6 +228,7 @@ void eos_power_init(void) {
     esp_err_t ret;
     gpio_config_t io_conf;
     esp_pm_config_esp32_t pwr_conf;
+    uint8_t wakeup_cause;
 
     io_conf.intr_type = GPIO_INTR_ANYEDGE;
     io_conf.mode = GPIO_MODE_INPUT;
@@ -201,8 +238,14 @@ void eos_power_init(void) {
     gpio_config(&io_conf);
     gpio_isr_handler_add(POWER_GPIO_BTN, btn_handler, NULL);
 
-    ret = esp_sleep_enable_gpio_wakeup();
+    /*
+    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);
+    */
 
     ret = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, NULL, &power_lock_cpu_freq);
     assert(ret == ESP_OK);
@@ -227,9 +270,34 @@ void eos_power_init(void) {
 
     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_power_wake(wakeup_cause);
+
+    init_done = 1;
     ESP_LOGI(TAG, "INIT");
 }
 
+void eos_power_wait4init(void) {
+    while (!init_done);
+}
+
+uint8_t eos_power_wakeup_cause(void) {
+    esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
+
+    switch (cause) {
+        case ESP_SLEEP_WAKEUP_EXT0:
+            return EOS_PWR_WAKE_BTN;
+
+        case ESP_SLEEP_WAKEUP_EXT1:
+            return EOS_PWR_WAKE_UART;
+
+        default:
+        case ESP_SLEEP_WAKEUP_UNDEFINED:
+            return EOS_PWR_WAKE_RST;
+    }
+}
+
 void eos_power_sleep(void) {
     power_event_t evt;
 
diff --git a/code/esp32/main/app_main.c b/code/esp32/main/app_main.c
index bd2e3e1..b700a8e 100644
--- a/code/esp32/main/app_main.c
+++ b/code/esp32/main/app_main.c
@@ -1,5 +1,9 @@
+#include <freertos/FreeRTOS.h>
+#include <freertos/task.h>
+
 #include <tcpip_adapter.h>
 #include <driver/gpio.h>
+#include <esp_sleep.h>
 
 #include "i2c.h"
 #include "cell.h"
@@ -15,11 +19,12 @@
 void app_main() {
     tcpip_adapter_init();
 
+    eos_net_init();
+
     eos_pcm_init();
     gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
     eos_modem_init();
 
-    eos_net_init();
     eos_cell_init();
     eos_wifi_init();
     eos_sock_init();
-- 
cgit v1.2.3