summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSadeep Madurange <sadeep@asciimx.com>2023-10-06 23:22:42 +0800
committerSadeep Madurange <sadeep@asciimx.com>2023-10-06 23:36:44 +0800
commit7fc10707d654aa154c28f16a06742fb5f0260b92 (patch)
tree410d7ab4de8c60f113abc19ecfb1606652db93ae
parent170d30bf548ea2e2196e14e413edf79563500e7f (diff)
downloadesp32-e-reader-7fc10707d654aa154c28f16a06742fb5f0260b92.tar.gz
Improve python script, SPI with DMA, deep sleep.
-rw-r--r--.gitignore1
-rw-r--r--main/CMakeLists.txt2
-rw-r--r--main/epd.c127
-rw-r--r--main/epd.h3
-rw-r--r--main/git_srht_cert.pem31
-rw-r--r--main/main.c421
-rw-r--r--main/util.c10
-rw-r--r--main/util.h6
-rw-r--r--main/wifi.c86
-rw-r--r--main/wifi.h6
-rw-r--r--pdftoebm.py79
11 files changed, 484 insertions, 288 deletions
diff --git a/.gitignore b/.gitignore
index 057d5de..302a0c1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ build/
**/__pycache__/
**/*.pdf
**/*.jpg
+**/Kconfig.projbuild
diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt
index 81b367e..0bfb5fc 100644
--- a/main/CMakeLists.txt
+++ b/main/CMakeLists.txt
@@ -1,3 +1,3 @@
-idf_component_register(SRCS "main.c" "epd.c" "util.c"
+idf_component_register(SRCS "main.c" "epd.c" "wifi.c"
EMBED_TXTFILES git_srht_cert.pem
INCLUDE_DIRS ".")
diff --git a/main/epd.c b/main/epd.c
index b59bf60..49e13c4 100644
--- a/main/epd.c
+++ b/main/epd.c
@@ -6,16 +6,16 @@
#include <driver/spi_master.h>
#include <driver/gpio.h>
+
#include <esp_log.h>
#include "epd.h"
-#include "util.h"
-#define EPD_SCREEN_WIDTH 800
-#define EPD_SCREEN_HEIGHT 480
+#define EPD_WIDTH 800
+#define EPD_HEIGHT 480
#define EPD_CS_PIN GPIO_NUM_5
-#define EPD_DC_PIN GPIO_NUM_15
+#define EPD_DC_PIN GPIO_NUM_16
#define EPD_RST_PIN GPIO_NUM_2
#define EPD_CLK_PIN GPIO_NUM_18
#define EPD_MOSI_PIN GPIO_NUM_23
@@ -25,11 +25,11 @@ static const char* TAG = "epd";
static spi_device_handle_t spi = NULL;
-static uint8_t VOLTAGE_FRAME[] = {
+static const uint8_t VOLTAGE_FRAME[] = {
0x6, 0x3F, 0x3F, 0x11, 0x24, 0x7, 0x17,
};
-static uint8_t LUT_VCOM[] = {
+static const uint8_t LUT_VCOM[] = {
0x0, 0xF, 0xF, 0x0, 0x0, 0x1,
0x0, 0xF, 0x1, 0xF, 0x1, 0x2,
0x0, 0xF, 0xF, 0x0, 0x0, 0x1,
@@ -39,7 +39,7 @@ static uint8_t LUT_VCOM[] = {
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
};
-static uint8_t LUT_WW[] = {
+static const uint8_t LUT_WW[] = {
0x10, 0xF, 0xF, 0x0, 0x0, 0x1,
0x84, 0xF, 0x1, 0xF, 0x1, 0x2,
0x20, 0xF, 0xF, 0x0, 0x0, 0x1,
@@ -49,7 +49,7 @@ static uint8_t LUT_WW[] = {
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
};
-static uint8_t LUT_BW[] = {
+static const uint8_t LUT_BW[] = {
0x10, 0xF, 0xF, 0x0, 0x0, 0x1,
0x84, 0xF, 0x1, 0xF, 0x1, 0x2,
0x20, 0xF, 0xF, 0x0, 0x0, 0x1,
@@ -59,7 +59,7 @@ static uint8_t LUT_BW[] = {
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
};
-static uint8_t LUT_WB[] = {
+static const uint8_t LUT_WB[] = {
0x80, 0xF, 0xF, 0x0, 0x0, 0x1,
0x84, 0xF, 0x1, 0xF, 0x1, 0x2,
0x40, 0xF, 0xF, 0x0, 0x0, 0x1,
@@ -69,7 +69,7 @@ static uint8_t LUT_WB[] = {
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
};
-static uint8_t LUT_BB[] = {
+static const uint8_t LUT_BB[] = {
0x80, 0xF, 0xF, 0x0, 0x0, 0x1,
0x84, 0xF, 0x1, 0xF, 0x1, 0x2,
0x40, 0xF, 0xF, 0x0, 0x0, 0x1,
@@ -91,10 +91,11 @@ static void send_cmd(uint8_t cmd)
memset(&t, 0, sizeof(t));
t.length = 8;
- t.tx_buffer = &cmd;
+ t.tx_data[0] = cmd;
t.user = (void*)0;
+ t.flags = SPI_TRANS_USE_TXDATA;
- ESP_ERROR_CHECK(spi_device_polling_transmit(spi, &t));
+ spi_device_polling_transmit(spi, &t);
}
static void send_data(uint8_t data)
@@ -103,10 +104,11 @@ static void send_data(uint8_t data)
memset(&t, 0, sizeof(t));
t.length = 8;
- t.tx_buffer = &data;
+ t.tx_data[0] = data;
t.user = (void*)1;
+ t.flags = SPI_TRANS_USE_TXDATA;
- ESP_ERROR_CHECK(spi_device_polling_transmit(spi, &t));
+ spi_device_polling_transmit(spi, &t);
}
static inline void wait_until_idle(void)
@@ -118,30 +120,29 @@ static inline void wait_until_idle(void)
do {
send_cmd(0x71);
busy = gpio_get_level(EPD_BUSY_PIN);
- } while(busy == 0);
+ } while (busy == 0);
ESP_LOGI(TAG, "ready");
- delay_ms(20);
+ vTaskDelay((TickType_t) 20 / portTICK_PERIOD_MS);
}
static inline void reset(void)
{
- ESP_ERROR_CHECK(gpio_set_level(EPD_RST_PIN, 1));
- delay_ms(200);
+ gpio_set_level(EPD_RST_PIN, 1);
+ vTaskDelay((TickType_t) 200 / portTICK_PERIOD_MS);
- ESP_ERROR_CHECK(gpio_set_level(EPD_RST_PIN, 0));
- delay_ms(2);
+ gpio_set_level(EPD_RST_PIN, 0);
+ vTaskDelay((TickType_t) 2 / portTICK_PERIOD_MS);
- ESP_ERROR_CHECK(gpio_set_level(EPD_RST_PIN, 1));
- delay_ms(200);
+ gpio_set_level(EPD_RST_PIN, 1);
+ vTaskDelay((TickType_t) 200 / portTICK_PERIOD_MS);
}
static inline void config_lut(uint8_t cmd, const uint8_t *lut)
{
- uint8_t i;
-
send_cmd(cmd);
- for(i = 0; i < 42; i++)
+
+ for (int i = 0; i < 42; i++)
send_data(lut[i]);
}
@@ -155,11 +156,12 @@ static inline void gpio_init(void)
};
ESP_ERROR_CHECK(gpio_config(&io_cfg));
+
ESP_ERROR_CHECK(gpio_set_direction(EPD_DC_PIN, GPIO_MODE_OUTPUT));
ESP_ERROR_CHECK(gpio_set_direction(EPD_RST_PIN, GPIO_MODE_OUTPUT));
ESP_ERROR_CHECK(gpio_set_direction(EPD_BUSY_PIN, GPIO_MODE_INPUT));
- delay_ms(500);
+ vTaskDelay((TickType_t) 1000 / portTICK_PERIOD_MS);
}
static void spi_init(void)
@@ -170,25 +172,23 @@ static void spi_init(void)
.sclk_io_num = EPD_CLK_PIN,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
- .max_transfer_sz = 8
+ .max_transfer_sz = EPD_WIDTH * EPD_HEIGHT
};
- ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST,
- &bus_cfg,
- SPI_DMA_CH_AUTO));
+ ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &bus_cfg, SPI_DMA_CH_AUTO));
spi_device_interface_config_t dev_cfg = {
.clock_speed_hz = 10 * 1000 * 1000,
.mode = 0,
.spics_io_num = EPD_CS_PIN,
- .queue_size = 1,
+ .queue_size = 3,
.pre_cb = spi_pre_cb_handler
};
ESP_ERROR_CHECK(spi_bus_add_device(SPI2_HOST, &dev_cfg, &spi));
}
-void epd_init(void)
+void epd_init()
{
spi_init();
gpio_init();
@@ -216,7 +216,7 @@ void epd_init(void)
send_data(*(VOLTAGE_FRAME + 0));
send_cmd(0x04);
- delay_ms(100);
+ vTaskDelay((TickType_t) 100 / portTICK_PERIOD_MS);
wait_until_idle();
send_cmd(0x00);
@@ -254,55 +254,66 @@ void epd_init(void)
static inline void refresh()
{
send_cmd(0x12);
- delay_ms(100);
-
+ vTaskDelay((TickType_t) 100 / portTICK_PERIOD_MS);
wait_until_idle();
}
void epd_clear(void)
{
- uint16_t i, width, height;
-
- width = (EPD_SCREEN_WIDTH % 8 == 0) ?
- (EPD_SCREEN_WIDTH / 8 ) :
- (EPD_SCREEN_WIDTH / 8 + 1);
- height = EPD_SCREEN_HEIGHT;
+ int height = EPD_HEIGHT;
+ int width = (EPD_WIDTH % 8 == 0) ? (EPD_WIDTH / 8 ) : (EPD_WIDTH / 8 + 1);
send_cmd(0x10);
- for(i = 0; i < height * width; i++)
+ for(int i = 0; i < height * width; i++)
send_data(0x00);
send_cmd(0x13);
- for(i = 0; i < height * width; i++)
+ for(int i = 0; i < height * width; i++)
send_data(0x00);
refresh();
}
-void epd_draw(const uint8_t pb[48000])
+void epd_draw_async(const uint8_t *buf, size_t n)
+{
+ static spi_transaction_t t[3];
+
+ memset(&t[0], 0, sizeof(t[0]));
+ t[0].length = 8;
+ t[0].tx_data[0] = 0x13;
+ t[0].user = (void*) 0;
+ t[0].flags = SPI_TRANS_USE_TXDATA;
+
+ memset(&t[1], 0, sizeof(t[1]));
+ t[1].length = 8 * n;
+ t[1].tx_buffer = buf;
+ t[1].user = (void*) 1;
+
+ memset(&t[2], 0, sizeof(t[2]));
+ t[2].length = 8;
+ t[2].tx_data[0] = 0x12;
+ t[2].user = (void*) 0;
+ t[2].flags = SPI_TRANS_USE_TXDATA;
+
+ for (int i = 0; i < 3; i++)
+ spi_device_queue_trans(spi, &t[i], portMAX_DELAY);
+}
+
+void epd_draw_await(void)
{
- uint32_t i, j, width, height;
+ esp_err_t rc;
+ spi_transaction_t *t;
- width = (EPD_SCREEN_WIDTH % 8 == 0) ?
- (EPD_SCREEN_WIDTH / 8 ) :
- (EPD_SCREEN_WIDTH / 8 + 1);
- height = EPD_SCREEN_HEIGHT;
-
- send_cmd(0x13);
- for (i = 0; i < height; i++) {
- for (j = 0; j < width; j++)
- send_data(~pb[i * width + j]);
+ for (int i = 0; i < 3; i++) {
+ rc = spi_device_get_trans_result(spi, &t, portMAX_DELAY);
+ assert(rc == ESP_OK);
}
-
- refresh();
}
void epd_sleep(void)
{
send_cmd(0x02);
-
wait_until_idle();
-
send_cmd(0x07);
send_data(0xA5);
}
diff --git a/main/epd.h b/main/epd.h
index fa124ab..e1595bd 100644
--- a/main/epd.h
+++ b/main/epd.h
@@ -3,7 +3,8 @@
void epd_init(void);
void epd_clear(void);
-void epd_draw(const uint8_t pb[48000]);
+void epd_draw_async(const uint8_t *buf, size_t n);
+void epd_draw_await(void);
void epd_sleep(void);
#endif /* EPD_H */
diff --git a/main/git_srht_cert.pem b/main/git_srht_cert.pem
new file mode 100644
index 0000000..123d192
--- /dev/null
+++ b/main/git_srht_cert.pem
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/
+MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
+DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow
+TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
+cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC
+ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL
+wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D
+LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK
+4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5
+bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y
+sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ
+Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4
+FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc
+SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql
+PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND
+TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
+SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1
+c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx
++tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB
+ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu
+b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E
+U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu
+MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC
+5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW
+9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG
+WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O
+he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC
+Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5
+-----END CERTIFICATE-----
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");
}
diff --git a/main/util.c b/main/util.c
deleted file mode 100644
index d2b6f22..0000000
--- a/main/util.c
+++ /dev/null
@@ -1,10 +0,0 @@
-#include <freertos/FreeRTOS.h>
-#include <freertos/task.h>
-
-#include "util.h"
-
-void delay_ms(unsigned int t)
-{
- vTaskDelay((TickType_t) t / portTICK_PERIOD_MS);
-}
-
diff --git a/main/util.h b/main/util.h
deleted file mode 100644
index 7156c8f..0000000
--- a/main/util.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef EPD_UTIL_H
-#define EPD_UTIL_H
-
-void delay_ms(unsigned int t);
-
-#endif /* EPD_UTIL_H */
diff --git a/main/wifi.c b/main/wifi.c
new file mode 100644
index 0000000..5024df9
--- /dev/null
+++ b/main/wifi.c
@@ -0,0 +1,86 @@
+#include <freertos/FreeRTOS.h>
+#include <freertos/event_groups.h>
+#include <freertos/task.h>
+
+#include <esp_log.h>
+#include <esp_wifi.h>
+
+#include "wifi.h"
+
+#define WIFI_SSID CONFIG_ESP_WIFI_SSID
+#define WIFI_PASSWORD CONFIG_ESP_WIFI_PASSWORD
+#define WIFI_MAX_RETRY CONFIG_ESP_MAXIMUM_RETRY
+
+#define WIFI_CONNECTED_BIT BIT0
+#define WIFI_ERROR_BIT BIT1
+
+static const char* TAG = "wifi";
+
+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)
+{
+ 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);
+ }
+}
+
+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");
+}
diff --git a/main/wifi.h b/main/wifi.h
new file mode 100644
index 0000000..eca5248
--- /dev/null
+++ b/main/wifi.h
@@ -0,0 +1,6 @@
+#ifndef EPD_WIFI_H
+#define EPD_WIFI_H
+
+void wifi_connect(void);
+
+#endif /* EPD_WIFI_H */
diff --git a/pdftoebm.py b/pdftoebm.py
index a3785de..e03ef33 100644
--- a/pdftoebm.py
+++ b/pdftoebm.py
@@ -28,15 +28,15 @@ for o, a in opts:
os.makedirs(output_path)
root = output_path + "/doc"
-print("Converting PDF to JPEGs...")
-subprocess.run(["pdftoppm", "-jpeg", "-progress", "-r", dpi, "-thinlinemode", "solid", doc, root])
-print("Finished converting PDF to JPEGs.")
+print("Converting PDF to images...")
+subprocess.run(["pdftoppm", "-png", "-progress", "-r", dpi, "-thinlinemode", "solid", doc, root])
+print("Finished converting PDF to images.")
-paths = list(Path(output_path).glob('*.jpg'))
+paths = sorted(list(Path(output_path).glob('*.png')))
print("Determining page size...")
w = h = 0
-dx = dy = sys.maxsize
+
for p in paths:
rv = subprocess.run(
["magick", p, "-trim", "-format", "%[fx:w] %[fx:h] %[fx:page.x] %[fx:page.y]", "info:"],
@@ -44,49 +44,44 @@ for p in paths:
text=True
)
area = [int(x) for x in rv.stdout.split()]
- if w < area[0]:
+ if w * h < area[0] * area[1]:
w = area[0]
- if h < area[1]:
h = area[1]
- if dx > area[2]:
dx = area[2]
- if dy > area[3]:
dy = area[3]
crop = "{}x{}+{}+{}".format(w, h, dx, dy)
-print("Crop area: {}".format(crop))
-
-for i, p in enumerate(paths):
- print("Processing page {}/{}...".format(i+1, len(paths)))
- jpg = str(p)
- txt = jpg.replace(".jpg", ".txt")
- ebm = jpg.replace(".jpg", ".ebm")
+print("Crop: {}".format(crop))
- subprocess.run(["magick", jpg, "-crop", crop, jpg])
- subprocess.run(["convert", jpg, "-resize", screen_size, jpg])
- subprocess.run(["convert", jpg, "-threshold", "80%", jpg])
- subprocess.run(["mogrify", "-rotate", "-90", jpg])
- subprocess.run(["convert", jpg, "-depth", "1", "-format", "'txt'", txt])
+ebm = "a.ebm"
- with open(txt, "r") as src, open(ebm, "wb") as dst:
- total = 0
- n = 7
- x = 0xFF
- count = 0
- src.readline()
- for line in src:
- px = re.search("\([^\)]+\)", line).group()
- if px == "(0)":
- x &= ~(1 << n)
- n -= 1
- if n < 0:
- dst.write(x.to_bytes(1))
- count += 1
- total += 1
- if count >= 12:
- count = 0
- n = 7
- x = 0xFF
- os.remove(txt)
- os.remove(jpg)
+with open(ebm, "ab") as dst:
+ for i, p in enumerate(paths):
+ print("Processing page {}/{}...".format(i+1, len(paths)))
+ png = str(p)
+ txt = re.sub("-0+", "-", png, count=1).replace(".png", ".txt")
+
+ subprocess.run(["magick", png, "-crop", crop, png])
+ subprocess.run(["convert", png, "-resize", screen_size, png])
+ subprocess.run(["convert", png, "-threshold", "80%", png])
+ subprocess.run(["mogrify", "-rotate", "-90", png])
+ subprocess.run(["convert", png, "-depth", "1", "-format", "'txt'", txt])
+
+ with open(txt, "r") as src:
+ total = 0
+ n = 7
+ x = 0
+ src.readline()
+ for line in src:
+ px = re.search("\([^\)]+\)", line).group()
+ if px == "(0)":
+ x |= (1 << n)
+ n -= 1
+ if n < 0:
+ dst.write(x.to_bytes(1))
+ total += 1
+ n = 7
+ x = 0
+ os.remove(txt)
+ os.remove(png)