From 2f2a5f2f02829fc67de004bc557b39d33b21a2a0 Mon Sep 17 00:00:00 2001 From: cpq Date: Thu, 15 Oct 2026 16:12:49 +0100 Subject: [PATCH] Add TLS and health backtrace to esp32 --- mongoose.c | 52 ++++- mongoose.h | 70 +------ src/arch_esp32.h | 57 +----- src/health.c | 52 ++++- src/health.h | 13 +- tutorials/esp32/minimal/main/CMakeLists.txt | 2 +- tutorials/esp32/minimal/main/main.c | 181 ++++++------------ .../esp32/minimal/main/mongoose_config.h | 3 +- 8 files changed, 167 insertions(+), 263 deletions(-) diff --git a/mongoose.c b/mongoose.c index 6f71df5a..542977e4 100644 --- a/mongoose.c +++ b/mongoose.c @@ -3653,12 +3653,12 @@ struct mg_health mg_health_record MG_HEALTH_RAM; // "used" keeps the linker from garbage-collecting this section: the only // reference is the "b fault_c" branch in the naked handler below __attribute__((used, noinline)) static void fault_c(uint32_t *frame, - uint32_t exc_return) { + uint32_t exc_return) { extern uint32_t _estack; uint32_t *stack = frame + 8 + ((exc_return & (1U << 4)) ? 0 : 18); uint32_t *r = mg_health_record.data; - if (frame[7] & (1U << 9)) stack++; // Eight-byte stack alignment padding + if (frame[7] & (1U << 9)) stack++; // Eight-byte stack alignment padding r[0] = (uint32_t) (uintptr_t) stack; // SP r[1] = frame[5]; // LR r[2] = frame[6]; // PC @@ -3688,6 +3688,54 @@ void BusFault_Handler(void) __attribute__((alias("HardFault_Handler"))); void UsageFault_Handler(void) __attribute__((alias("HardFault_Handler"))); #endif +// Start a new boot: validate the record, count the boot, store the reset +// reason. The current boot moves to prev_* slots first, so the previous +// boot's uptime and reason stay readable. Called by MG_HEALTH_INIT() +void mg_health_init(void) { + char magic[] = MG_HEALTH_MAGIC; + // struct mg_health *h = mg_health_get(); + if (!mg_health_valid()) { // First boot, or RAM lost its contents + memset(&mg_health_record, 0, sizeof(mg_health_record)); + memcpy(mg_health_record.magic, magic, sizeof(mg_health_record.magic)); + } + +#if 0 && MG_ARCH == MG_ARCH_ESP32 && CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH + { + // After a crash, copy the backtrace from the core dump in flash: the same + // addresses the panic handler prints as "Backtrace: PC:SP PC:SP ...". + // The core dump stays in flash, so check the reset reason, otherwise an + // old crash is reported on every boot + static esp_core_dump_summary_t s; // Big on RISC-V, keep it off the stack + esp_reset_reason_t rr = esp_reset_reason(); + uint32_t *out = mg_health_record.data; + size_t n = 0, max = MG_HEALTH_DATA_SIZE; + if (rr != ESP_RST_PANIC && rr != ESP_RST_INT_WDT && rr != ESP_RST_TASK_WDT) + return; // Not a crash that went through the panic handler + if (max == 0 || esp_core_dump_get_summary(&s) != ESP_OK) return; + + mg_health_record.cpuid = 42; // ESP32 + mg_health_record.reset_reason = MG_HEALTH_RESET_FAULT; + + memset(out, 0, sizeof(mg_health_record.data)); + out[n++] = s.exc_pc; +#if CONFIG_IDF_TARGET_ARCH_XTENSA + for (uint32_t i = 0; i < s.exc_bt_info.depth && n < max; i++) { + if (s.exc_bt_info.bt[i] != s.exc_pc) out[n++] = s.exc_bt_info.bt[i]; + } +#elif CONFIG_IDF_TARGET_ARCH_RISCV + // No unwinder: take the return address, then words on the stack that + // point into executable memory (a heuristic, may include stale values) + if (n < max) out[n++] = s.ex_info.ra; + for (uint32_t i = 0; i + 4 <= s.exc_bt_info.dump_size && n < max; i += 4) { + uint32_t w; + memcpy(&w, &s.exc_bt_info.stackdump[i], sizeof(w)); // Byte array + if (esp_ptr_executable((void *) (uintptr_t) w)) out[n++] = w; + } +#endif + } +#endif +} + static size_t print_uint32(void (*fn)(char, void *), void *arg, va_list *ap) { size_t n = va_arg(*ap, size_t); uint32_t *p = va_arg(*ap, uint32_t *); diff --git a/mongoose.h b/mongoose.h index 13b1c4f0..4bf24501 100644 --- a/mongoose.h +++ b/mongoose.h @@ -314,10 +314,8 @@ extern "C" { #include #include #include -#include -#include -#include -#include +// #include // For health record coredumps +// #include // For health record coredumps #define MG_PATH_MAX 128 @@ -325,55 +323,8 @@ extern "C" { #define MG_ENABLE_POSIX_FS 1 #endif -#ifndef MG_OTA_ESP32_WDT_TIMEOUT_MS -#define MG_OTA_ESP32_WDT_TIMEOUT_MS 10000U -#endif - -static inline void mg_ota_esp32_timer_start(void) { -#if ESP_IDF_VERSION_MAJOR >= 5 - esp_task_wdt_config_t cfg = {0}; - esp_err_t err; - - cfg.timeout_ms = MG_OTA_ESP32_WDT_TIMEOUT_MS; - cfg.idle_core_mask = 0; - cfg.trigger_panic = true; - - err = esp_task_wdt_init(&cfg); - if (err == ESP_ERR_INVALID_STATE) esp_task_wdt_reconfigure(&cfg); -#else - esp_task_wdt_init(MG_OTA_ESP32_WDT_TIMEOUT_MS / 1000U, true); -#endif - esp_task_wdt_add(NULL); - esp_task_wdt_reset(); -} - -static inline uint32_t mg_ota_esp32_state_set(uint32_t state) { - if (state == 0) esp_ota_mark_app_valid_cancel_rollback(); - REG_WRITE(RTC_CNTL_STORE0_REG, state); - return REG_READ(RTC_CNTL_STORE0_REG); -} - -#define MG_OTA_STATE_GET() \ - REG_READ(RTC_CNTL_STORE0_REG) - -#define MG_OTA_STATE_SET(v) mg_ota_esp32_state_set((uint32_t) (v)) - -#ifndef MG_OTA_ROLLBACK_TIMER_START -#define MG_OTA_ROLLBACK_TIMER_START() mg_ota_esp32_timer_start() -#endif - -#ifndef MG_OTA_ROLLBACK_TIMER_FEED -#define MG_OTA_ROLLBACK_TIMER_FEED() \ - do { \ - (void) esp_task_wdt_reset(); \ - } while (0) -#endif - -#ifndef MG_OTA_ROLLBACK -#define MG_OTA_ROLLBACK() \ - do { \ - (void) esp_ota_mark_app_invalid_rollback_and_reboot(); \ - } while (0) +#ifndef MG_HEALTH_DATA_SIZE +#define MG_HEALTH_DATA_SIZE 20 #endif #endif @@ -4562,20 +4513,9 @@ static inline const char *mg_health_reason_str(int reason) { } } -// Start a new boot: validate the record, count the boot, store the reset -// reason. The current boot moves to prev_* slots first, so the previous -// boot's uptime and reason stay readable. Called by MG_HEALTH_INIT() -static inline void mg_health_init(void) { - char magic[] = MG_HEALTH_MAGIC; - // struct mg_health *h = mg_health_get(); - if (!mg_health_valid()) { // First boot, or RAM lost its contents - memset(&mg_health_record, 0, sizeof(mg_health_record)); - memcpy(mg_health_record.magic, magic, sizeof(mg_health_record.magic)); - } -} - #define MG_HEALTH_INIT() mg_health_init() extern size_t mg_print_crash_record(mg_pfn_t, void *, va_list *); +extern void mg_health_init(void); // Cloud connector API to https://mdash.net - device management cloud diff --git a/src/arch_esp32.h b/src/arch_esp32.h index df0f76b8..24a4c366 100644 --- a/src/arch_esp32.h +++ b/src/arch_esp32.h @@ -22,10 +22,8 @@ #include #include #include -#include -#include -#include -#include +// #include // For health record coredumps +// #include // For health record coredumps #define MG_PATH_MAX 128 @@ -33,55 +31,8 @@ #define MG_ENABLE_POSIX_FS 1 #endif -#ifndef MG_OTA_ESP32_WDT_TIMEOUT_MS -#define MG_OTA_ESP32_WDT_TIMEOUT_MS 10000U -#endif - -static inline void mg_ota_esp32_timer_start(void) { -#if ESP_IDF_VERSION_MAJOR >= 5 - esp_task_wdt_config_t cfg = {0}; - esp_err_t err; - - cfg.timeout_ms = MG_OTA_ESP32_WDT_TIMEOUT_MS; - cfg.idle_core_mask = 0; - cfg.trigger_panic = true; - - err = esp_task_wdt_init(&cfg); - if (err == ESP_ERR_INVALID_STATE) esp_task_wdt_reconfigure(&cfg); -#else - esp_task_wdt_init(MG_OTA_ESP32_WDT_TIMEOUT_MS / 1000U, true); -#endif - esp_task_wdt_add(NULL); - esp_task_wdt_reset(); -} - -static inline uint32_t mg_ota_esp32_state_set(uint32_t state) { - if (state == 0) esp_ota_mark_app_valid_cancel_rollback(); - REG_WRITE(RTC_CNTL_STORE0_REG, state); - return REG_READ(RTC_CNTL_STORE0_REG); -} - -#define MG_OTA_STATE_GET() \ - REG_READ(RTC_CNTL_STORE0_REG) - -#define MG_OTA_STATE_SET(v) mg_ota_esp32_state_set((uint32_t) (v)) - -#ifndef MG_OTA_ROLLBACK_TIMER_START -#define MG_OTA_ROLLBACK_TIMER_START() mg_ota_esp32_timer_start() -#endif - -#ifndef MG_OTA_ROLLBACK_TIMER_FEED -#define MG_OTA_ROLLBACK_TIMER_FEED() \ - do { \ - (void) esp_task_wdt_reset(); \ - } while (0) -#endif - -#ifndef MG_OTA_ROLLBACK -#define MG_OTA_ROLLBACK() \ - do { \ - (void) esp_ota_mark_app_invalid_rollback_and_reboot(); \ - } while (0) +#ifndef MG_HEALTH_DATA_SIZE +#define MG_HEALTH_DATA_SIZE 20 #endif #endif diff --git a/src/health.c b/src/health.c index 1c167976..d1b7fbd2 100644 --- a/src/health.c +++ b/src/health.c @@ -13,12 +13,12 @@ struct mg_health mg_health_record MG_HEALTH_RAM; // "used" keeps the linker from garbage-collecting this section: the only // reference is the "b fault_c" branch in the naked handler below __attribute__((used, noinline)) static void fault_c(uint32_t *frame, - uint32_t exc_return) { + uint32_t exc_return) { extern uint32_t _estack; uint32_t *stack = frame + 8 + ((exc_return & (1U << 4)) ? 0 : 18); uint32_t *r = mg_health_record.data; - if (frame[7] & (1U << 9)) stack++; // Eight-byte stack alignment padding + if (frame[7] & (1U << 9)) stack++; // Eight-byte stack alignment padding r[0] = (uint32_t) (uintptr_t) stack; // SP r[1] = frame[5]; // LR r[2] = frame[6]; // PC @@ -48,6 +48,54 @@ void BusFault_Handler(void) __attribute__((alias("HardFault_Handler"))); void UsageFault_Handler(void) __attribute__((alias("HardFault_Handler"))); #endif +// Start a new boot: validate the record, count the boot, store the reset +// reason. The current boot moves to prev_* slots first, so the previous +// boot's uptime and reason stay readable. Called by MG_HEALTH_INIT() +void mg_health_init(void) { + char magic[] = MG_HEALTH_MAGIC; + // struct mg_health *h = mg_health_get(); + if (!mg_health_valid()) { // First boot, or RAM lost its contents + memset(&mg_health_record, 0, sizeof(mg_health_record)); + memcpy(mg_health_record.magic, magic, sizeof(mg_health_record.magic)); + } + +#if 0 && MG_ARCH == MG_ARCH_ESP32 && CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH + { + // After a crash, copy the backtrace from the core dump in flash: the same + // addresses the panic handler prints as "Backtrace: PC:SP PC:SP ...". + // The core dump stays in flash, so check the reset reason, otherwise an + // old crash is reported on every boot + static esp_core_dump_summary_t s; // Big on RISC-V, keep it off the stack + esp_reset_reason_t rr = esp_reset_reason(); + uint32_t *out = mg_health_record.data; + size_t n = 0, max = MG_HEALTH_DATA_SIZE; + if (rr != ESP_RST_PANIC && rr != ESP_RST_INT_WDT && rr != ESP_RST_TASK_WDT) + return; // Not a crash that went through the panic handler + if (max == 0 || esp_core_dump_get_summary(&s) != ESP_OK) return; + + mg_health_record.cpuid = 42; // ESP32 + mg_health_record.reset_reason = MG_HEALTH_RESET_FAULT; + + memset(out, 0, sizeof(mg_health_record.data)); + out[n++] = s.exc_pc; +#if CONFIG_IDF_TARGET_ARCH_XTENSA + for (uint32_t i = 0; i < s.exc_bt_info.depth && n < max; i++) { + if (s.exc_bt_info.bt[i] != s.exc_pc) out[n++] = s.exc_bt_info.bt[i]; + } +#elif CONFIG_IDF_TARGET_ARCH_RISCV + // No unwinder: take the return address, then words on the stack that + // point into executable memory (a heuristic, may include stale values) + if (n < max) out[n++] = s.ex_info.ra; + for (uint32_t i = 0; i + 4 <= s.exc_bt_info.dump_size && n < max; i += 4) { + uint32_t w; + memcpy(&w, &s.exc_bt_info.stackdump[i], sizeof(w)); // Byte array + if (esp_ptr_executable((void *) (uintptr_t) w)) out[n++] = w; + } +#endif + } +#endif +} + static size_t print_uint32(void (*fn)(char, void *), void *arg, va_list *ap) { size_t n = va_arg(*ap, size_t); uint32_t *p = va_arg(*ap, uint32_t *); diff --git a/src/health.h b/src/health.h index 34711ec9..3304732f 100644 --- a/src/health.h +++ b/src/health.h @@ -76,17 +76,6 @@ static inline const char *mg_health_reason_str(int reason) { } } -// Start a new boot: validate the record, count the boot, store the reset -// reason. The current boot moves to prev_* slots first, so the previous -// boot's uptime and reason stay readable. Called by MG_HEALTH_INIT() -static inline void mg_health_init(void) { - char magic[] = MG_HEALTH_MAGIC; - // struct mg_health *h = mg_health_get(); - if (!mg_health_valid()) { // First boot, or RAM lost its contents - memset(&mg_health_record, 0, sizeof(mg_health_record)); - memcpy(mg_health_record.magic, magic, sizeof(mg_health_record.magic)); - } -} - #define MG_HEALTH_INIT() mg_health_init() extern size_t mg_print_crash_record(mg_pfn_t, void *, va_list *); +extern void mg_health_init(void); diff --git a/tutorials/esp32/minimal/main/CMakeLists.txt b/tutorials/esp32/minimal/main/CMakeLists.txt index 647593e4..07e56cb1 100644 --- a/tutorials/esp32/minimal/main/CMakeLists.txt +++ b/tutorials/esp32/minimal/main/CMakeLists.txt @@ -3,6 +3,7 @@ idf_component_register(SRCS "main.c" "../../../../mongoose.c" INCLUDE_DIRS "." "../../../.." + PRIV_REQUIRES mbedtls REQUIRES esp_event esp_netif esp_partition @@ -11,4 +12,3 @@ idf_component_register(SRCS "main.c" espcoredump nvs_flash app_update) -component_compile_options(-DHTTP_URL="http://0.0.0.0:80") diff --git a/tutorials/esp32/minimal/main/main.c b/tutorials/esp32/minimal/main/main.c index fbcfe6a4..6c525bb0 100644 --- a/tutorials/esp32/minimal/main/main.c +++ b/tutorials/esp32/minimal/main/main.c @@ -1,13 +1,9 @@ // Copyright (c) 2026 Cesanta Software Limited // All rights reserved -#include -#include "esp_core_dump.h" -#include "esp_err.h" -#include "esp_partition.h" +#include "esp_heap_caps.h" #include "esp_system.h" #include "mongoose.h" -#include "sdkconfig.h" #define WIFI_SSID "YOUR_WIFI_NETWORK_NAME" // SET THIS! #define WIFI_PASS "YOUR_WIFI_PASSWORD" // SET THIS! @@ -16,133 +12,56 @@ #define HTTP_URL "http://0.0.0.0:80" #endif -#ifndef CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH -#define CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH 0 +#ifndef HTTPS_URL +#define HTTPS_URL "https://0.0.0.0:443" #endif -#ifndef ESP_PARTITION_SUBTYPE_DATA_COREDUMP -#define ESP_PARTITION_SUBTYPE_DATA_COREDUMP 0x03 -#endif +// Self-signed P-256 certificate and key for the HTTPS listener. Created by: +// openssl ecparam -genkey -name prime256v1 -noout -out key.pem +// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg +#define TLS_CERT \ + "-----BEGIN CERTIFICATE-----\n" \ + "MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \ + "FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \ + "MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \ + "SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \ + "uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \ + "MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \ + "BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \ + "lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \ + "BCjX++LI\n" \ + "-----END CERTIFICATE-----\n" -struct crash_download { - const esp_partition_t *partition; - size_t offset; - size_t size; - size_t sent; -}; - -static void crash_json(struct mg_connection *c) { -#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH - esp_core_dump_summary_t summary; - char reason[200] = ""; - size_t address = 0, size = 0; - esp_err_t err = esp_core_dump_image_get(&address, &size); - esp_err_t sr = err == ESP_OK ? esp_core_dump_get_summary(&summary) : err; - esp_err_t rr = err == ESP_OK ? esp_core_dump_get_panic_reason( - reason, sizeof(reason)) : err; - - mg_http_reply(c, 200, "Content-Type: application/json\r\n", - "{%m:%s,%m:%d,%m:%u,%m:%u,%m:%m,%m:%m,%m:%d,%m:%d,%m:%m}\n", - MG_ESC("present"), err == ESP_OK ? "true" : "false", - MG_ESC("reset_reason"), (int) esp_reset_reason(), - MG_ESC("address"), (unsigned) address, MG_ESC("size"), - (unsigned) size, MG_ESC("panic_reason"), - MG_ESC(rr == ESP_OK ? reason : ""), MG_ESC("task"), - MG_ESC(sr == ESP_OK ? summary.exc_task : ""), MG_ESC("pc"), - sr == ESP_OK ? (int) summary.exc_pc : 0, MG_ESC("error"), - (int) err, MG_ESC("binary"), MG_ESC("/api/crash.bin")); -#else - mg_http_reply(c, 501, "Content-Type: application/json\r\n", - "{%m:false,%m:%d,%m:%m}\n", MG_ESC("present"), - MG_ESC("reset_reason"), (int) esp_reset_reason(), - MG_ESC("error"), MG_ESC("coredump to flash is disabled")); -#endif -} - -static void crash_send(struct mg_connection *c) { -#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH - struct crash_download *d = (struct crash_download *) c->fn_data; - while (d != NULL && d->sent < d->size && c->send.len < 2048) { - uint8_t buf[512]; - size_t left = d->size - d->sent; - size_t len = left > sizeof(buf) ? sizeof(buf) : left; - esp_err_t err = esp_partition_read(d->partition, d->offset + d->sent, buf, - len); - if (err != ESP_OK) { - MG_ERROR(("esp_partition_read: %s", esp_err_to_name(err))); - c->is_draining = 1; - return; - } - mg_send(c, buf, len); - d->sent += len; - } - if (d != NULL && d->sent >= d->size) { - free(d); - c->fn_data = NULL; - c->is_draining = 1; - } -#else - (void) c; -#endif -} - -static void crash_bin(struct mg_connection *c) { -#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH - const esp_partition_t *p = esp_partition_find_first( - ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_COREDUMP, NULL); - struct crash_download *d; - size_t address = 0, size = 0, offset = 0; - esp_err_t err = esp_core_dump_image_get(&address, &size); - - if (err != ESP_OK) { - mg_http_reply(c, 404, "Content-Type: application/json\r\n", - "{%m:%m}\n", MG_ESC("error"), MG_ESC(esp_err_to_name(err))); - } else if (p == NULL || address < p->address || - address + size > p->address + p->size) { - mg_http_reply(c, 500, "Content-Type: application/json\r\n", - "{%m:%m}\n", MG_ESC("error"), - MG_ESC("invalid coredump partition")); - } else if ((d = (struct crash_download *) calloc(1, sizeof(*d))) == NULL) { - mg_http_reply(c, 500, "Content-Type: application/json\r\n", - "{%m:%m}\n", MG_ESC("error"), MG_ESC("out of memory")); - } else { - offset = address - p->address; - d->partition = p; - d->offset = offset; - d->size = size; - c->fn_data = d; - mg_printf(c, - "HTTP/1.1 200 OK\r\n" - "Content-Type: application/octet-stream\r\n" - "Content-Length: %u\r\n" - "Content-Disposition: attachment; filename=\"esp32-coredump." - "bin\"\r\n" - "\r\n", - (unsigned) size); - crash_send(c); - } -#else - mg_http_reply(c, 501, "Content-Type: application/json\r\n", - "{%m:%m}\n", MG_ESC("error"), - MG_ESC("coredump to flash is disabled")); -#endif -} +#define TLS_KEY \ + "-----BEGIN EC PRIVATE KEY-----\n" \ + "MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \ + "AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \ + "LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \ + "-----END EC PRIVATE KEY-----\n" static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_HTTP_MSG) { + if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener + struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), + .key = mg_str(TLS_KEY)}; + mg_tls_init(c, &opts); + } else if (ev == MG_EV_HTTP_MSG) { struct mg_http_message *hm = (struct mg_http_message *) ev_data; - if (mg_match(hm->uri, mg_str("/api/crash.bin"), NULL)) { - crash_bin(c); + size_t total = heap_caps_get_total_size(MALLOC_CAP_DEFAULT); + size_t ram_free = heap_caps_get_free_size(MALLOC_CAP_DEFAULT); + if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { + mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), mg_millis()); } else if (mg_match(hm->uri, mg_str("/api/crash"), NULL)) { - crash_json(c); + *(volatile uint32_t *) 0 = 0; // Store to address 0: CPU exception } else { - mg_http_reply(c, 200, "", "Hi from Mongoose\n"); + mg_http_reply(c, 200, "", + "Hi from Mongoose!\n" + "tick: %llu\n" + "ram used: %zu\n" + "ram free: %zu\n" + "ram min: %zu\n", // Lowest free heap since boot + mg_millis(), total - ram_free, ram_free, + heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT)); } - } else if (ev == MG_EV_POLL && c->fn_data != NULL) { - crash_send(c); - } else if (ev == MG_EV_CLOSE && c->fn_data != NULL) { - free(c->fn_data); - c->fn_data = NULL; } } @@ -151,11 +70,19 @@ void app_main(void) { wifi_init(WIFI_SSID, WIFI_PASS); struct mg_mgr mgr; - mg_log_set(MG_LL_INFO); mg_mgr_init(&mgr); - MG_INFO(("Mongoose version : v%s", MG_VERSION)); - MG_INFO(("Listening on : %s", HTTP_URL)); mg_http_listen(&mgr, HTTP_URL, http_ev_handler, NULL); + mg_http_listen(&mgr, HTTPS_URL, http_ev_handler, NULL); - for (;;) mg_mgr_poll(&mgr, 1000); + MG_INFO(("Initialised. CPU clock: %lu MHz", + (unsigned long) esp_rom_get_cpu_ticks_per_us())); + MG_INFO(("RAM used: %zu, free: %zu", + heap_caps_get_total_size(MALLOC_CAP_DEFAULT) - + heap_caps_get_free_size(MALLOC_CAP_DEFAULT), + heap_caps_get_free_size(MALLOC_CAP_DEFAULT))); + MG_INFO(("Crash record: %M", mg_print_crash_record)); + + for (;;) { + mg_mgr_poll(&mgr, 1000); + } } diff --git a/tutorials/esp32/minimal/main/mongoose_config.h b/tutorials/esp32/minimal/main/mongoose_config.h index 3282da6a..d7a026cb 100644 --- a/tutorials/esp32/minimal/main/mongoose_config.h +++ b/tutorials/esp32/minimal/main/mongoose_config.h @@ -1,3 +1,4 @@ #define MG_ARCH MG_ARCH_ESP32 -#define MG_TLS MG_TLS_NONE +#define MG_TLS MG_TLS_BUILTIN +//#define MG_TLS MG_TLS_MBED