summaryrefslogtreecommitdiffstats
path: root/main/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/main.c')
-rw-r--r--main/main.c421
1 files changed, 251 insertions, 170 deletions
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 <freertos/event_groups.h>
#include <freertos/task.h>
#include <freertos/queue.h>
+#include <freertos/semphr.h>
#include <esp_log.h>
-#include <esp_log.h>
#include <esp_netif.h>
#include <esp_system.h>
-#include <esp_wifi.h>
#include <esp_tls.h>
#include <esp_http_client.h>
+#include <esp_sleep.h>
+#include <esp_wifi.h>
#include <nvs_flash.h>
#include <sys/param.h>
#include <driver/gpio.h>
+#include <driver/rtc_io.h>
#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");
}