diff -Naur orig/lib/lv_bindings/driver/esp32/espidf.h new/lib/lv_bindings/driver/esp32/espidf.h --- orig/lib/lv_bindings/driver/esp32/espidf.h 2021-02-10 18:24:03.605801218 +0100 +++ new/lib/lv_bindings/driver/esp32/espidf.h 2021-02-10 18:24:34.254373767 +0100 @@ -122,6 +122,64 @@ config->user_data = user_data; } +// -vv- http server -vv------------------------------------------------------- + +#include "esp_http_server.h" + +typedef void * SemaphoreHandle_t; +#include "http_server.h" + +static inline esp_err_t http_server_start(http_server_t *server) { + return http_server_start_internal(server); +} + +static inline esp_err_t http_server_stop(http_server_t *server) { + return http_server_stop_internal(server); +} + +static inline esp_err_t http_server_register(http_server_t *server, http_server_handler_t *data, esp_err_t (*handler_cb)(struct http_server_handler *handler_data, httpd_req_t *req), void *user_data) +{ + data->handler_cb = handler_cb; + data->user_data = user_data; + + data->httpd_uri.handler = http_server_internal_handler; + data->httpd_uri.user_ctx = data; + data->cmd = HTTP_SERVER_CMD_INIT; + data->data = NULL; + + data->event_httpd = NULL; + data->event_python = NULL; + data->lock = xSemaphoreCreateBinary(); // handler lock, initially taken + xSemaphoreGive(data->lock); // release it + + return httpd_register_uri_handler(server->handle, &(data->httpd_uri)); +} + +static inline void http_server_handler_give_control(http_server_handler_t *data) { + xSemaphoreGive(data->event_httpd); // let httpd run + xSemaphoreTake(data->event_python, portMAX_DELAY); // wait for python callback to give +} + +// send a string either complete or chunk'ed +static inline void http_server_handler_send_str(http_server_handler_t *data, char *str, bool chunk) { + data->cmd = chunk?HTTP_SERVER_CMD_SENDSTR_CHUNK:HTTP_SERVER_CMD_SENDSTR; // send string + data->data = (void*)str; + http_server_handler_give_control(data); +} + +static inline void http_server_handler_send(http_server_handler_t *data, char *bytes, int len, bool chunk) { + data->cmd = chunk?HTTP_SERVER_CMD_SEND_CHUNK:HTTP_SERVER_CMD_SEND; // send bytes + data->data = (void*)bytes; + data->len = len; + http_server_handler_give_control(data); +} + +static inline const char *httpd_req_get_uri(httpd_req_t *req) { + return req->uri; +} + +// -^^- http server -^^------------------------------------------------------- + // We don't want the whole FreeRTOS, only selected functions void task_delay_ms(int ms); diff -Naur orig/lib/lv_bindings/driver/esp32/http_server.c new/lib/lv_bindings/driver/esp32/http_server.c --- orig/lib/lv_bindings/driver/esp32/http_server.c 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/lv_bindings/driver/esp32/http_server.c 2021-02-10 19:30:59.511115597 +0100 @@ -0,0 +1,95 @@ +#include "py/obj.h" +#include "py/runtime.h" +#include "esp_http_server.h" + +#include "http_server.h" +#include "lib/lv_bindings/driver/include/common.h" + +#if CONFIG_HTTPD_MAX_REQ_HDR_LEN < 1024 +#error Please increase CONFIG_HTTPD_MAX_REQ_HDR_LEN to 1024 +#endif + +esp_err_t http_server_start_internal(http_server_t *server) { + /* Generate default configuration */ + static const httpd_config_t dc = HTTPD_DEFAULT_CONFIG(); + memcpy(&(server->config), &dc, sizeof(httpd_config_t)); + /* enable wildcard matching by default */ + server->config.uri_match_fn = httpd_uri_match_wildcard; + /* force running on core 1 */ + server->config.core_id = 1; + server->config.stack_size = 8192; + + return httpd_start(&(server->handle), &(server->config)); +} + +esp_err_t http_server_stop_internal(http_server_t *server) { + return httpd_stop(server->handle); +} + +// This is the function that is scheduled and run in Micropython thread +STATIC mp_obj_t http_server_handler_cb(mp_obj_t arg) +{ + mp_ptr_t *ctx = MP_OBJ_TO_PTR(arg); + httpd_req_t *req = ctx->ptr; + http_server_handler_t *data = req->user_ctx; + + data->res = data->handler_cb(data, req); + + data->cmd = HTTP_SERVER_CMD_DONE; + xSemaphoreGive(data->event_httpd); // final "give" as we are done + return mp_const_none; +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_1(http_server_handler_cb_obj, http_server_handler_cb); + +esp_err_t http_server_internal_handler(httpd_req_t *req) +{ + http_server_handler_t *data = req->user_ctx; + + xSemaphoreTake(data->lock, portMAX_DELAY); // handler in use + + data->event_httpd = xSemaphoreCreateBinary(); // the binary is by default "taken" + data->event_python = xSemaphoreCreateBinary(); // -"- + if(!mp_sched_schedule((mp_obj_t)&http_server_handler_cb_obj, NEW_PTR_OBJ(httpd_req_t, req))) { + printf("Scheduling failed ...\n"); + httpd_resp_set_status(req, "503 Service Unavailable"); + httpd_resp_sendstr(req, "

Internal problem: Scheduler failed

"); + vSemaphoreDelete(data->event_httpd); + vSemaphoreDelete(data->event_python); + xSemaphoreGive(data->lock); // handler free + return 0; + } + + xSemaphoreTake(data->event_httpd, portMAX_DELAY); // wait for python callback to give + + // wait for cmd 1 "callback done" + while(data->cmd != HTTP_SERVER_CMD_DONE) { + switch(data->cmd) { + case HTTP_SERVER_CMD_SENDSTR: + httpd_resp_sendstr(req, (char*)(data->data)); + break; + + case HTTP_SERVER_CMD_SENDSTR_CHUNK: + httpd_resp_sendstr_chunk(req, (char*)(data->data)); + break; + + case HTTP_SERVER_CMD_SEND: + httpd_resp_send(req, (char*)(data->data), data->len); + break; + + case HTTP_SERVER_CMD_SEND_CHUNK: + httpd_resp_send_chunk(req, (char*)(data->data), data->len); + break; + } + xSemaphoreGive(data->event_python); + + xSemaphoreTake(data->event_httpd, portMAX_DELAY); // wait for python callback to give + } + + // whole transfer done. + vSemaphoreDelete(data->event_httpd); + vSemaphoreDelete(data->event_python); + xSemaphoreGive(data->lock); // handler free + return data->res; +} + diff -Naur orig/lib/lv_bindings/driver/esp32/http_server.h new/lib/lv_bindings/driver/esp32/http_server.h --- orig/lib/lv_bindings/driver/esp32/http_server.h 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/lv_bindings/driver/esp32/http_server.h 2021-02-10 18:23:05.440704053 +0100 @@ -0,0 +1,53 @@ +// httpd_server.h + +#ifndef HTTPD_SERVER_H +#define HTTPD_SERVER_H + +extern esp_err_t http_server_internal_handler(httpd_req_t *req); + +enum { + http_server_DELETE = 0, + http_server_GET, + http_server_HEAD, + http_server_POST, + http_server_PUT +}; +typedef uint8_t http_server_method_t; + +typedef struct { + httpd_handle_t handle; + httpd_config_t config; + + void *user_data; +} http_server_t; + +extern esp_err_t http_server_start_internal(http_server_t *server); +extern esp_err_t http_server_stop_internal(http_server_t *server); + +#define HTTP_SERVER_CMD_INIT 0 +#define HTTP_SERVER_CMD_DONE 1 +#define HTTP_SERVER_CMD_SENDSTR 2 +#define HTTP_SERVER_CMD_SENDSTR_CHUNK 3 +#define HTTP_SERVER_CMD_SEND 4 +#define HTTP_SERVER_CMD_SEND_CHUNK 5 + +typedef struct http_server_handler { + SemaphoreHandle_t lock; // main handler lock + + // Filled by the Python user (only "uri" and "method" on httpd_uri): + httpd_uri_t httpd_uri; + + esp_err_t (*handler_cb)(struct http_server_handler *handler_data, httpd_req_t *req); + void *user_data; + + SemaphoreHandle_t event_httpd; // httpd waits for python + SemaphoreHandle_t event_python; // python waits for httpd + esp_err_t res; // callback result + + // command structure to exchange data between python and httpd + int cmd; + void *data; + int len; +} http_server_handler_t; + +#endif // HTTPD_SERVER_H diff -Naur orig/lib/lv_bindings/gen/gen_mpy.py new/lib/lv_bindings/gen/gen_mpy.py --- orig/lib/lv_bindings/gen/gen_mpy.py 2021-02-10 18:33:39.287947309 +0100 +++ new/lib/lv_bindings/gen/gen_mpy.py 2021-02-10 18:33:21.107660176 +0100 @@ -868,7 +868,18 @@ STATIC inline const char *convert_from_str(mp_obj_t str) { - return (str == NULL || str == mp_const_none)? NULL: mp_obj_str_get_str(str); + if (str == NULL || str == mp_const_none) + return NULL; + + if (MP_OBJ_IS_TYPE(str, &mp_type_bytearray) || + MP_OBJ_IS_TYPE(str, &mp_type_memoryview)) { + mp_buffer_info_t buffer_info; + if (mp_get_buffer(str, &buffer_info, MP_BUFFER_READ)) { + return buffer_info.buf; + } + } + + return mp_obj_str_get_str(str); } // struct handling diff -Naur orig/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.mk new/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.mk --- orig/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.mk 2021-02-10 18:28:10.474323021 +0100 +++ new/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.mk 2021-02-10 18:28:41.370876602 +0100 @@ -1,3 +1,4 @@ SDKCONFIG += boards/sdkconfig.base SDKCONFIG += boards/sdkconfig.spiram SDKCONFIG += boards/sdkconfig.240mhz +SDKCONFIG += boards/sdkconfig.http_server diff -Naur orig/ports/esp32/boards/sdkconfig.http_server new/ports/esp32/boards/sdkconfig.http_server --- orig/ports/esp32/boards/sdkconfig.http_server 1970-01-01 01:00:00.000000000 +0100 +++ new/ports/esp32/boards/sdkconfig.http_server 2021-02-10 18:30:28.760784218 +0100 @@ -0,0 +1,4 @@ +# MicroPython on ESP32, ESP IDF configuration for httpd + +CONFIG_HTTPD_WS_SUPPORT=y +CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 diff -Naur orig/ports/esp32/Makefile new/ports/esp32/Makefile --- orig/ports/esp32/Makefile 2021-02-10 18:25:43.375652299 +0100 +++ new/ports/esp32/Makefile 2021-02-10 18:26:37.656645139 +0100 @@ -167,6 +167,9 @@ INC_ESPCOMP += -I$(ESPCOMP)/esp_http_client/include INC_ESPCOMP += -I$(ESPCOMP)/esp_http_client/lib/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_http_server/include +INC_ESPCOMP += -I$(ESPCOMP)/esp_http_server/src/port/esp32 +INC_ESPCOMP += -I$(ESPCOMP)/esp_http_server/src/util INC_ESPCOMP += -I$(ESPCOMP)/nghttp/port/include INC_ESPCOMP += -I$(ESPCOMP)/nghttp/nghttp2/lib/includes INC_ESPCOMP += -I$(ESPCOMP)/nghttp/private_include @@ -403,8 +406,9 @@ lib/lv_bindings/driver/esp32/modrtch.c \ lib/lv_bindings/driver/esp32/espidf.c \ lib/lv_bindings/driver/esp32/sh2lib.c \ + lib/lv_bindings/driver/esp32/http_server.c \ $(ESPIDFMOD_MODULE) - + # lib/lv_bindings/driver/esp32/modxpt2046.c # lib/lv_bindings/driver/esp32/modILI9341.c @@ -559,6 +563,11 @@ $(wildcard $(ESPCOMP)/esp_http_client/lib/*.c) \ ) +ESPIDF_HTTP_SERVER_O = $(patsubst %.c,%.o,\ + $(wildcard $(ESPCOMP)/esp_http_server/src/*.c) \ + $(wildcard $(ESPCOMP)/esp_http_server/src/util/*.c) \ + ) + ESPIDF_NGHTTP_O = $(patsubst %.c,%.o,\ $(wildcard $(ESPCOMP)/nghttp/nghttp2/lib/*.c) \ $(wildcard $(ESPCOMP)/nghttp/port/*.c) \ @@ -692,6 +701,7 @@ $(eval $(call gen_espidf_lib_rule,mdns,$(ESPIDF_MDNS_O))) $(eval $(call gen_espidf_lib_rule,esp_http_client,$(ESPIDF_HTTP_CLIENT_O))) +$(eval $(call gen_espidf_lib_rule,esp_http_server,$(ESPIDF_HTTP_SERVER_O))) $(eval $(call gen_espidf_lib_rule,esp_nghttp,$(ESPIDF_NGHTTP_O))) $(eval $(call gen_espidf_lib_rule,esp_tcp_transport,$(ESPIDF_TCP_TRANSPORT_O))) $(eval $(call gen_espidf_lib_rule,esp_tls,$(ESPIDF_TLS_O)))