From 7fc10707d654aa154c28f16a06742fb5f0260b92 Mon Sep 17 00:00:00 2001 From: Sadeep Madurange Date: Fri, 6 Oct 2023 23:22:42 +0800 Subject: Improve python script, SPI with DMA, deep sleep. --- main/main.c | 421 ++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 251 insertions(+), 170 deletions(-) (limited to 'main/main.c') diff --git a/main/main.c b/main/main.c index a679855..577ac00 100644 --- a/main/main.c +++ b/main/main.c @@ -2,107 +2,158 @@ #include #include #include +#include -#include #include #include #include -#include #include #include +#include +#include #include #include #include +#include #include "epd.h" -#include "util.h" +#include "wifi.h" #define PAGE_LEN 3 #define PAGE_SIZE 48000 +#define IO_SLEEP_PIN GPIO_NUM_15 #define IO_PAGE_PREV GPIO_NUM_21 #define IO_PAGE_NEXT GPIO_NUM_22 #define IO_INTR_FLAG_DEFAULT 0 -#define WIFI_SSID CONFIG_ESP_WIFI_SSID -#define WIFI_PASSWORD CONFIG_ESP_WIFI_PASSWORD -#define WIFI_MAX_RETRY CONFIG_ESP_MAXIMUM_RETRY +#define EBM_ARCH_URL CONFIG_EBM_ARCH_URL -#define WIFI_CONNECTED_BIT BIT0 -#define WIFI_ERROR_BIT BIT1 - -#define HTTP_URL_BASE CONFIG_HTTP_BASE_URL -#define HTTP_URL_SUFFIX ".ebm" +#define MUTEX_TIMEOUT ((TickType_t) 5000 / portTICK_PERIOD_MS) extern const char git_srht_cert_pem_start[] asm("_binary_git_srht_cert_pem_start"); extern const char git_srht_cert_pem_end[] asm("_binary_git_srht_cert_pem_end"); static const char* TAG = "app"; -static size_t page_num = 0; -static uint8_t *pages[PAGE_LEN]; +static SemaphoreHandle_t mutex; -static int http_get_page(size_t page_n, char buf[PAGE_SIZE]) -{ - int rc; - char *url; - esp_http_client_handle_t client; +static RTC_NOINIT_ATTR size_t c_page_num; +static RTC_NOINIT_ATTR size_t n_page_num; +static RTC_NOINIT_ATTR size_t p_page_num; - rc = 0; - url = NULL; - client = NULL; +static uint8_t *pages[PAGE_LEN]; - int url_len = strlen(HTTP_URL_BASE) + - snprintf(NULL, 0,"%02d", page_n) + - strlen(HTTP_URL_SUFFIX) + 1; +static QueueHandle_t http_evt_queue; +static esp_http_client_handle_t http_client; - if ((url = malloc(sizeof(char) * url_len)) == NULL) { - ESP_LOGE(TAG, "malloc() failed for URL"); - goto exit; +struct http_user_data { + char *res_buf; + int *res_len; +}; + +static esp_err_t http_evt_handler(esp_http_client_event_t *evt) +{ + static int read_len; + + switch(evt->event_id) { + case HTTP_EVENT_ON_HEADER: + ESP_LOGI(TAG, "received header, key=%s, value=%s", + evt->header_key, + evt->header_value); + break; + case HTTP_EVENT_ON_DATA: + int copy_len = 0; + struct http_user_data *user_data = (struct http_user_data *) evt->user_data; + + if (user_data && user_data->res_buf) { + copy_len = MIN(evt->data_len, (PAGE_SIZE - read_len)); + if (copy_len) { + memcpy(user_data->res_buf + read_len, evt->data, copy_len); + read_len += copy_len; + ESP_LOGD(TAG, "download progress = %d", read_len); + *user_data->res_len = read_len; + } + } + break; + case HTTP_EVENT_ON_FINISH: + read_len = 0; + break; + case HTTP_EVENT_DISCONNECTED: + int mbedtls_err = 0; + esp_err_t err = esp_tls_get_and_clear_last_error((esp_tls_error_handle_t) evt->data, + &mbedtls_err, + NULL); + if (err != 0) { + ESP_LOGE(TAG, "disconnected, last esp error code: 0x%x", err); + ESP_LOGI(TAG, "disconnected, last mbedtls failure: 0x%x", mbedtls_err); + } + read_len = 0; + break; + default: + break; } + return ESP_OK; +} - snprintf(url, url_len, "%s%02d%s", HTTP_URL_BASE, page_n, - HTTP_URL_SUFFIX); +static int http_get_page(size_t page_n, char buf[PAGE_SIZE]) +{ + struct http_user_data user_data; + + int res_len = 0; + int r0 = ((page_n - 1) * PAGE_SIZE); + int rn = page_n * PAGE_SIZE - 1; + int rh_buflen = snprintf(NULL, 0, "bytes=%d-%d", r0, rn) + 1; - ESP_LOGI(TAG, "downloading, URL = %s", url); + char *rh_buf = malloc(sizeof(char) * rh_buflen); - esp_http_client_config_t config = { - .url = url, - .timeout_ms = 5000, - .disable_auto_redirect = true, - .max_authorization_retries = -1, - .cert_pem = git_srht_cert_pem_start - }; + if (rh_buf) { + snprintf(rh_buf, rh_buflen, "bytes=%d-%d", r0, rn); + esp_http_client_set_header(http_client, "Range", rh_buf); - client = esp_http_client_init(&config); + user_data.res_len = &res_len; + user_data.res_buf = buf; + esp_http_client_set_user_data(http_client, &user_data); - esp_err_t err = esp_http_client_open(client, 0); - if (err != ESP_OK) { - ESP_LOGE(TAG, "HTTP connection error: %s", esp_err_to_name(err)); - goto exit; - } + esp_http_client_perform(http_client); - esp_http_client_fetch_headers(client); - - int read_len = esp_http_client_read(client, buf, PAGE_SIZE); - if (read_len <= 0) { - ESP_LOGE(TAG, "HTTP response read error"); - goto exit; - } + ESP_LOGI(TAG, "HTTP status = %d, content length = %d", + esp_http_client_get_status_code(http_client), + res_len); - ESP_LOGI(TAG, "HTTP response status = %d, content length = %" PRId64, - esp_http_client_get_status_code(client), - esp_http_client_get_content_length(client)); + free(rh_buf); + } - rc = read_len == PAGE_SIZE; + return res_len == PAGE_SIZE; +} -exit: - free(url); - esp_http_client_close(client); - esp_http_client_cleanup(client); +struct page_info { + size_t page_num; + uint8_t *page_buf; +}; - return rc; +static void http_task(void* arg) +{ + struct page_info pg; + + for (;;) { + if (xQueueReceive(http_evt_queue, &pg, portMAX_DELAY)) { + if (http_get_page(pg.page_num, (char *) pg.page_buf)) { + if (xSemaphoreTake(mutex, MUTEX_TIMEOUT) == pdTRUE) { + if (pg.page_num > c_page_num) + n_page_num = pg.page_num; + else if (pg.page_num < c_page_num) + p_page_num = pg.page_num; + xSemaphoreGive(mutex); + } else { + ESP_LOGE(TAG, "failed to acquire mutex"); + } + } else { + ESP_LOGE(TAG, "page fetch error"); + } + } + } } static QueueHandle_t gpio_evt_queue = NULL; @@ -110,30 +161,72 @@ static QueueHandle_t gpio_evt_queue = NULL; static void gpio_task(void* arg) { uint32_t io_num; + struct page_info pg; - for(;;) { - if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) { + for (;;) { + if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) { if (io_num == IO_PAGE_NEXT) { - page_num++; - epd_draw(pages[page_num % PAGE_LEN]); - if(!http_get_page(page_num + 2, - (char *) pages[(page_num + 1) % PAGE_LEN])) { - page_num--; + if (xSemaphoreTake(mutex, MUTEX_TIMEOUT) == pdTRUE) { + if (c_page_num < n_page_num) { + c_page_num++; + + pg.page_num = c_page_num + 2; + pg.page_buf = pages[(c_page_num + 1) % PAGE_LEN]; + + xSemaphoreGive(mutex); + + xQueueSend(http_evt_queue, &pg, portMAX_DELAY); + + epd_draw_async(pages[c_page_num % PAGE_LEN], PAGE_SIZE); + epd_draw_await(); + } else { + xSemaphoreGive(mutex); + ESP_LOGI(TAG, "page not ready"); + } + } else { + ESP_LOGE(TAG, "failed to acquire mutex"); } - } - else if (io_num == IO_PAGE_PREV && page_num > 0) { - page_num--; - epd_draw(pages[page_num % PAGE_LEN]); - if(!http_get_page(page_num + 1, - (char *) pages[(page_num - 1) % PAGE_LEN])) { - page_num++; + } else if (io_num == IO_PAGE_PREV && c_page_num > 0) { + if (xSemaphoreTake(mutex, MUTEX_TIMEOUT) == pdTRUE) { + if (c_page_num > p_page_num) { + c_page_num--; + + pg.page_num = c_page_num + 1; + pg.page_buf = pages[(c_page_num - 1) % PAGE_LEN]; + + xSemaphoreGive(mutex); + + xQueueSend(http_evt_queue, &pg, portMAX_DELAY); + + epd_draw_async(pages[c_page_num % PAGE_LEN], PAGE_SIZE); + epd_draw_await(); + } else { + xSemaphoreGive(mutex); + ESP_LOGI(TAG, "page not ready"); + } + } else { + ESP_LOGE(TAG, "failed to acquire mutex"); } + } else if (io_num == IO_SLEEP_PIN) { + epd_clear(); + epd_sleep(); + + esp_wifi_stop(); + + rtc_gpio_init(IO_SLEEP_PIN); + rtc_gpio_pullup_dis(IO_SLEEP_PIN); + rtc_gpio_pulldown_en(IO_SLEEP_PIN); + + esp_sleep_enable_ext0_wakeup(IO_SLEEP_PIN, 1); + + esp_deep_sleep_start(); + } else { + vTaskDelay((TickType_t) 500 / portTICK_PERIOD_MS); } - else - delay_ms(500); gpio_intr_enable(IO_PAGE_NEXT); gpio_intr_enable(IO_PAGE_PREV); + gpio_intr_enable(IO_SLEEP_PIN); } } } @@ -142,131 +235,119 @@ static void gpio_isr_handler(void *arg) { gpio_intr_disable(IO_PAGE_PREV); gpio_intr_disable(IO_PAGE_NEXT); + gpio_intr_disable(IO_SLEEP_PIN); uint32_t gpio_num = (uint32_t) arg; - xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL); + if (gpio_num != IO_SLEEP_PIN) + xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL); + else + xQueueSendToFrontFromISR(gpio_evt_queue, &gpio_num, NULL); } -static int wifi_retry_num = 0; -static EventGroupHandle_t wifi_evt_group; - -static void wifi_evt_handler(void *arg, - esp_event_base_t eb, int32_t id, - void *data) +void app_main(void) { - if (eb == WIFI_EVENT && id == WIFI_EVENT_STA_DISCONNECTED) { - if (wifi_retry_num < WIFI_MAX_RETRY) { - esp_wifi_connect(); - wifi_retry_num++; - ESP_LOGI(TAG, "trying to connect to AP..."); - } else { - ESP_LOGE(TAG,"connection to AP failed"); - xEventGroupSetBits(wifi_evt_group, WIFI_ERROR_BIT); - } - } else if (eb == IP_EVENT && id == IP_EVENT_STA_GOT_IP) { - ip_event_got_ip_t* evt = (ip_event_got_ip_t*) data; - ESP_LOGI(TAG, "connected to AP with ip:" IPSTR, IP2STR(&evt->ip_info.ip)); - wifi_retry_num = 0; - xEventGroupSetBits(wifi_evt_group, WIFI_CONNECTED_BIT); + if (esp_reset_reason() != ESP_RST_DEEPSLEEP) { + p_page_num = 0; + c_page_num = 0; + n_page_num = 0; } -} - -static inline void wifi_connect(void) -{ - wifi_evt_group = xEventGroupCreate(); - esp_netif_create_default_wifi_sta(); - - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK(esp_wifi_init(&cfg)); - - esp_event_handler_instance_t any_id; - ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, - ESP_EVENT_ANY_ID, - &wifi_evt_handler, - NULL, - &any_id)); - - esp_event_handler_instance_t got_ip; - ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, - IP_EVENT_STA_GOT_IP, - &wifi_evt_handler, - NULL, - &got_ip)); - - wifi_config_t wifi_config = { - .sta = { - .ssid = WIFI_SSID, - .password = WIFI_PASSWORD, - .threshold.authmode = WIFI_AUTH_WPA2_PSK - }, - }; - - ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); - ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); - - ESP_ERROR_CHECK(esp_wifi_start()); - ESP_ERROR_CHECK(esp_wifi_connect()); - - xEventGroupWaitBits(wifi_evt_group, - WIFI_CONNECTED_BIT | WIFI_ERROR_BIT, - pdFALSE, - pdFALSE, - portMAX_DELAY); - ESP_LOGI(TAG, "wifi station initialized"); -} - -void app_main(void) -{ - esp_err_t rc = nvs_flash_init(); - if (rc == ESP_ERR_NVS_NO_FREE_PAGES || rc == ESP_ERR_NVS_NEW_VERSION_FOUND) { - ESP_ERROR_CHECK(nvs_flash_erase()); - ESP_ERROR_CHECK(nvs_flash_init()); + mutex = xSemaphoreCreateMutex(); + if (mutex == NULL) { + ESP_LOGE(TAG, "xSemaphoreCreateMutex() failed"); + return; } ESP_ERROR_CHECK(esp_event_loop_create_default()); - ESP_ERROR_CHECK(esp_netif_init()); + + ESP_ERROR_CHECK(rtc_gpio_deinit(IO_SLEEP_PIN)); gpio_config_t io_cfg = { - .pin_bit_mask = ((1ULL << IO_PAGE_PREV) | (1ULL << IO_PAGE_NEXT)), + .pin_bit_mask = ((1ULL << IO_PAGE_PREV) | + (1ULL << IO_PAGE_NEXT | + (1ULL << IO_SLEEP_PIN))), .mode = GPIO_MODE_INPUT, .pull_up_en = true, .intr_type = GPIO_INTR_NEGEDGE }; ESP_ERROR_CHECK(gpio_config(&io_cfg)); + ESP_ERROR_CHECK(gpio_set_pull_mode(IO_SLEEP_PIN, GPIO_PULLDOWN_ONLY)); + ESP_ERROR_CHECK(gpio_set_intr_type(IO_SLEEP_PIN, GPIO_INTR_POSEDGE)); + + ESP_ERROR_CHECK(gpio_install_isr_service(IO_INTR_FLAG_DEFAULT)); + + ESP_ERROR_CHECK(gpio_isr_handler_add(IO_SLEEP_PIN, + gpio_isr_handler, + (void *) IO_SLEEP_PIN)); gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t)); - xTaskCreate(gpio_task, "gpio_task", 4096, NULL, 10, NULL); + xTaskCreatePinnedToCore(gpio_task, "gpio_task", 4096, NULL, 10, NULL, 0); + + esp_err_t rc = nvs_flash_init(); + if (rc == ESP_ERR_NVS_NO_FREE_PAGES || rc == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ESP_ERROR_CHECK(nvs_flash_init()); + } - ESP_ERROR_CHECK(gpio_set_direction(IO_PAGE_PREV, GPIO_MODE_INPUT)); - ESP_ERROR_CHECK(gpio_set_direction(IO_PAGE_NEXT, GPIO_MODE_INPUT)); + ESP_ERROR_CHECK(esp_netif_init()); wifi_connect(); - epd_init(); - epd_clear(); - delay_ms(500); + pages[0] = heap_caps_malloc(sizeof(uint8_t) * PAGE_SIZE, MALLOC_CAP_DMA); + pages[1] = heap_caps_malloc(sizeof(uint8_t) * PAGE_SIZE, MALLOC_CAP_DMA); + pages[2] = heap_caps_malloc(sizeof(uint8_t) * PAGE_SIZE, MALLOC_CAP_DMA); - pages[0] = malloc(sizeof(uint8_t) * PAGE_SIZE); - pages[1] = malloc(sizeof(uint8_t) * PAGE_SIZE); - pages[2] = malloc(sizeof(uint8_t) * PAGE_SIZE); + int http_rc; if (pages[0] && pages[1] && pages[2]) { - if (http_get_page(page_num + 1, - (char *) pages[page_num % PAGE_LEN])) { - epd_draw(pages[page_num % PAGE_LEN]); - if (!http_get_page(page_num + 2, - (char *) pages[(page_num + 1) % PAGE_LEN])) { - page_num = -1; - } + epd_init(); + + esp_http_client_config_t http_client_cfg = { + .url = EBM_ARCH_URL, + .is_async = false, + .timeout_ms = 5000, + .disable_auto_redirect = true, + .event_handler = http_evt_handler, + .cert_pem = git_srht_cert_pem_start + }; + + http_client = esp_http_client_init(&http_client_cfg); + esp_http_client_set_header(http_client, "Accept", "application/octet-stream"); + + char *c_page_buf = (char *) pages[c_page_num % PAGE_LEN]; + http_rc = http_get_page(c_page_num + 1, c_page_buf); + if (!http_rc) { + ESP_LOGE(TAG, "failed to download the first page"); + return; + } - gpio_install_isr_service(IO_INTR_FLAG_DEFAULT); - gpio_isr_handler_add(IO_PAGE_PREV, gpio_isr_handler, (void *) IO_PAGE_PREV); - gpio_isr_handler_add(IO_PAGE_NEXT, gpio_isr_handler, (void *) IO_PAGE_NEXT); + epd_draw_async(pages[c_page_num % PAGE_LEN], PAGE_SIZE); - ESP_LOGI(TAG, "GPIO for user input initialized"); + if (c_page_num > 0) { + char *p_page_buf = (char *) pages[(c_page_num - 1) % PAGE_LEN]; + http_rc = http_get_page(c_page_num, p_page_buf); + p_page_num = http_rc ? c_page_num - 1 : c_page_num; } + + char *n_page_buf = (char *) pages[(c_page_num) + 1 % PAGE_LEN]; + http_rc = http_get_page(c_page_num + 2, n_page_buf); + n_page_num = http_rc ? c_page_num + 1 : c_page_num; + + epd_draw_await(); + + http_evt_queue = xQueueCreate(10, sizeof(struct page_info)); + xTaskCreatePinnedToCore(http_task, "http_task", 4096, NULL, 10, NULL, 1); + + ESP_ERROR_CHECK(gpio_isr_handler_add(IO_PAGE_PREV, + gpio_isr_handler, + (void *) IO_PAGE_PREV)); + + ESP_ERROR_CHECK(gpio_isr_handler_add(IO_PAGE_NEXT, + gpio_isr_handler, + (void *) IO_PAGE_NEXT)); + + ESP_LOGI(TAG, "enabled GPIO for user input"); } else { ESP_LOGE(TAG, "malloc() failed for pages"); } -- cgit v1.2.3