diff --git a/dependencies.lock b/dependencies.lock index f0125e1..5e505df 100644 --- a/dependencies.lock +++ b/dependencies.lock @@ -2,13 +2,13 @@ dependencies: chmorgan/esp-audio-player: component_hash: c8ac1998e9af863bc41b57e592f88d1a5791a0f891485122336ddabbf7a65033 dependencies: - - name: idf - require: private - version: '>=5.0' - name: chmorgan/esp-libhelix-mp3 registry_url: https://components.espressif.com require: private version: '>=1.0.0,<2.0.0' + - name: idf + require: private + version: '>=5.0' source: registry_url: https://components.espressif.com/ type: service @@ -46,13 +46,13 @@ dependencies: espressif/eppp_link: component_hash: c2fd9c57ac14a68a62c9d9cdeec39a2b265abc16779196ce2c9f5000c9a4dd8b dependencies: - - name: idf - require: private - version: '>=5.2' - name: espressif/esp_serial_slave_link registry_url: https://components.espressif.com require: private version: ^1.1.0 + - name: idf + require: private + version: '>=5.2' source: registry_url: https://components.espressif.com type: service @@ -104,7 +104,7 @@ dependencies: type: service version: 1.2.0 espressif/esp_hosted: - component_hash: 9e7a202cc18c08fa9b67c0261f9733b33af9b3af73eafd4ef6704cdb37bde7c2 + component_hash: fba52659b7d0256b0f6bd497ebce2492bf93506d797935a292f0fd864e364e47 dependencies: - name: idf require: private @@ -112,7 +112,7 @@ dependencies: source: registry_url: https://components.espressif.com type: service - version: 1.4.1 + version: 2.0.1 espressif/esp_lcd_ek79007: component_hash: 07c1afab7e9fd4dd2fd06ff9245e65327c5bbd5485efec199496e19a9304d47b dependencies: @@ -189,16 +189,6 @@ dependencies: registry_url: https://components.espressif.com type: service version: 1.1.0 - espressif/esp_websocket_client: - component_hash: f77326f0e1c38da4e9c97e17c5d649b0dd13027f2645e720e48db269638fd622 - dependencies: - - name: idf - require: private - version: '>=5.0' - source: - registry_url: https://components.espressif.com/ - type: service - version: 1.4.0 espressif/esp_wifi_remote: component_hash: f772731a8cc7361a3eb416eac94ac46cf85369cb996c5a5fc9245a07f241fee2 dependencies: @@ -256,12 +246,11 @@ direct_dependencies: - espressif/esp32_p4_function_ev_board - espressif/esp_lcd_touch_gt911 - espressif/esp_lvgl_port -- espressif/esp_websocket_client - espressif/esp_wifi_remote - idf - joltwallet/littlefs - lvgl/lvgl - suda-morris/am2302_rmt -manifest_hash: 15284e0a2c7903f038a0abcadaa03469042782b30abea68977d3e3e45b11bbaa +manifest_hash: 7f55ed1927cdc36bd55b14a1d25259f250e5b0415a9bf10a74a1681a6336990d target: esp32p4 version: 2.0.0 diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 376263e..d99231a 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -3,13 +3,14 @@ set(EXTRA_COMPONENT_DIRS ../components) set(comps heap nvs_flash meteofrance esp_netif image_downloader fatfs protocol_examples_common mqtt esp_wifi) if(${IDF_TARGET} STREQUAL "esp32p4") - list(APPEND comps bsp_extra esp32_p4_function_ev_board sdmmc vfs littlefs wifi_logger app_update esp_https_ota) + list(APPEND comps bsp_extra esp32_p4_function_ev_board sdmmc vfs littlefs wifi_logger app_update esp_https_ota espcoredump esp_http_server) endif() idf_component_register(SRC_DIRS . fonts INCLUDE_DIRS "." REQUIRES ${comps} - EMBED_TXTFILES ${project_dir}/main/ca_cert.pem) + EMBED_TXTFILES ${project_dir}/main/ca_cert.pem + EMBED_FILES "index.html") set_source_files_properties( diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 6908f20..bd7b37c 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -1,4 +1,4 @@ -menu "Example Configuration" +menu "Domotic Configuration" config ESP_WIFI_SSID string "WiFi SSID" @@ -12,56 +12,11 @@ menu "Example Configuration" help WiFi password (WPA or WPA2) for the example to use. - choice ESP_WIFI_SAE_MODE - prompt "WPA3 SAE mode selection" - default ESP_WPA3_SAE_PWE_BOTH + config GPIO_INPUT_CAPTEUR_PIR + int "GPIO PIN Capteur PIR" + range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX + default 4 help - Select mode for SAE as Hunt and Peck, H2E or both. - config ESP_WPA3_SAE_PWE_HUNT_AND_PECK - bool "HUNT AND PECK" - config ESP_WPA3_SAE_PWE_HASH_TO_ELEMENT - bool "H2E" - config ESP_WPA3_SAE_PWE_BOTH - bool "BOTH" - endchoice - - config ESP_WIFI_PW_ID - string "PASSWORD IDENTIFIER" - depends on ESP_WPA3_SAE_PWE_HASH_TO_ELEMENT|| ESP_WPA3_SAE_PWE_BOTH - default "" - help - password identifier for SAE H2E - - config ESP_MAXIMUM_RETRY - int "Maximum retry" - default 5 - help - Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent. - - choice ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD - prompt "WiFi Scan auth mode threshold" - default ESP_WIFI_AUTH_WPA2_PSK - help - The weakest authmode to accept in the scan mode. - This value defaults to ESP_WIFI_AUTH_WPA2_PSK incase password is present and ESP_WIFI_AUTH_OPEN is used. - Please select ESP_WIFI_AUTH_WEP/ESP_WIFI_AUTH_WPA_PSK incase AP is operating in WEP/WPA mode. - - config ESP_WIFI_AUTH_OPEN - bool "OPEN" - config ESP_WIFI_AUTH_WEP - bool "WEP" - config ESP_WIFI_AUTH_WPA_PSK - bool "WPA PSK" - config ESP_WIFI_AUTH_WPA2_PSK - bool "WPA2 PSK" - config ESP_WIFI_AUTH_WPA_WPA2_PSK - bool "WPA/WPA2 PSK" - config ESP_WIFI_AUTH_WPA3_PSK - bool "WPA3 PSK" - config ESP_WIFI_AUTH_WPA2_WPA3_PSK - bool "WPA2/WPA3 PSK" - config ESP_WIFI_AUTH_WAPI_PSK - bool "WAPI PSK" - endchoice - + GPIO pin à utiliser pour le capteur de présence IR. + endmenu diff --git a/main/ca_cert.pem b/main/ca_cert.pem index 7eff939..bd2b618 100644 --- a/main/ca_cert.pem +++ b/main/ca_cert.pem @@ -1,22 +1,22 @@ -----BEGIN CERTIFICATE----- -MIIDmTCCAoGgAwIBAgIUd5qKY6blEffPyHQZnmQfxkcCO7AwDQYJKoZIhvcNAQEL -BQAwXDELMAkGA1UEBhMCRlIxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +MIIDmTCCAoGgAwIBAgIUJyG8nVHyoUV/0lOqRtSCjVnEtfYwDQYJKoZIhvcNAQEL +BQAwXDELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEVMBMGA1UEAwwMMTkyLjE2OC4wLjI4 -MB4XDTI0MTExMzE4MjYxOVoXDTI1MTExMzE4MjYxOVowXDELMAkGA1UEBhMCRlIx +MB4XDTI1MDUwNzA3NTMzMVoXDTI2MDUwNzA3NTMzMVowXDELMAkGA1UEBhMCQVUx EzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMg UHR5IEx0ZDEVMBMGA1UEAwwMMTkyLjE2OC4wLjI4MIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEA8lKPcpJ6/FhrI+E8fzR93N/XIfEW7GpFa+KNp+DK9DGS -hHno2yVGXNdUFRQEL/2pL8aiZzZ7xGMubzEIr1dlHrb/PplGRTXCxQWnDJDsOu4w -7TbzjYxDhgMwXhSGuFlMexFBh+W9qcO85l4wNSOhHusyf7XZaPAd3NGmK4XsoeXJ -DSROJLLpvyZM3yt1kuC3GTWSqUe4Ldv+kaAfyW+X/PJ7Tgb6frLGNCs5A0zLhFxb -FS2omnqX6+H2Bjvk3nCQr85zcuIrnXQ+Hy58MayS+dRqPTSNw7RqRVvrGUuQuj5y -/ruAVLjG6F9wTZZFJ8Nk2veuFxIG+8ADpglWoYrokQIDAQABo1MwUTAdBgNVHQ4E -FgQUUa64jnTc+VqWQB93Fp/yPuirm2cwHwYDVR0jBBgwFoAUUa64jnTc+VqWQB93 -Fp/yPuirm2cwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAnqg9 -DeBozovXmwcbDTlTqz1b5LJ3Xz4mhUnEssmlDvvlXMqL1CjeXDKgOXtkWaomTJNO -MfMTmkkKg2lomNe2O84nUyPJnHYle5cbxZXAvbkmsi6R95lXFf5+bHAtU05TFYKc -BWMPB3Vwym9qrAc8G1LPr05LYgrJsQ9xkf0pVR7hrjgu9k6ElNAQSiH4dlyK4b/T -12U4zBawZNv3f6OnKOTq2NuwwzxWSwRRbEGUf0qO6Z8LNsj7yvmp2ImfN1e3a39p -+WmxJkHBzg5LxUon8jtiZLKeAPNlAPvKTs/4umE0LdZnsdlYrNR+kFeMMurxHvfZ -ykxPELUVUWEgv/IRbA== +AAOCAQ8AMIIBCgKCAQEAvG8y2D7/NR+7YZIRLUYgpe88nWxU/WPTgq5+0wZElEhx +e7ZG0YvYFy298RHhZ3m2KsMrWTaZcnjS41QRsMajoeIjCwnmJ5MkNfCMxAoeFC4D +p26CIzkA6h++RK8MmHLwEdB3sjskafd+Iu/bBA+KDUdQiy6GL3zXVOUjdUFB5MFT +EO0vNZhfjdpv4iQ71KIvS9ORCh6OfvSkUaRCoIa2NQXbLi4be0onV+8UXpX06V6Y +dADj+Gdw32STOb8PI24Ri1EQkED34IaGeaNte0+882ma3J8hX3vnXQbhpC1N+TqA +1szvZUDNs2qmRiLqXyZkxhXJRS055n0wjGdFUmzPgwIDAQABo1MwUTAdBgNVHQ4E +FgQUk7EOCIXLo4LGatOpmk1XdGr7tkwwHwYDVR0jBBgwFoAUk7EOCIXLo4LGatOp +mk1XdGr7tkwwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkGpE +Q8n9za+NxdAnBMcV4GB0zPBK2NNEY7OXbRv0GA/qBAd0CsvP9QbidC/9Toz7ptT4 +KyCZFGx8Xx2AWRx60kJ/f2VVUZIZzUoOA6qj3lN8keAT+OGWszvaXlXIbW/TJrs0 +lCv4ynkXI4dBhAd3DnXPQSrEyr1h8DValqh1R/kxi+Kb4SYODIoLz0aRbPJFes3z +n10wPTlxARiz6iKQrZP5UKIrFuWyBPZ5xCHn7AmNdqZqtBKB+ERychSjh5b0oznO +AzZDnBoB4lriWTM0yVV1w1eurz0B0Qtz/rqQnYEhWLJodZC8ipjeUoap6BcPHOMq +tx49i3GdxzVoewbZFQ== -----END CERTIFICATE----- diff --git a/main/communication.c b/main/communication.c index efa5c71..872eab0 100644 --- a/main/communication.c +++ b/main/communication.c @@ -197,7 +197,6 @@ static EventGroupHandle_t s_wifi_event_group; #define EXAMPLE_ESP_MAXIMUM_RETRY 5 #define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_BOTH -#define EXAMPLE_H2E_IDENTIFIER CONFIG_ESP_WIFI_PW_ID #define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK static int s_retry_num = 0; @@ -271,7 +270,7 @@ void wifi_init_sta(wifi_callback callback) */ .threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD, .sae_pwe_h2e = ESP_WIFI_SAE_MODE, - .sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER, + .sae_h2e_identifier = "", }, }; ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); diff --git a/main/ihm.c b/main/ihm.c index 61217ec..310d7e3 100644 --- a/main/ihm.c +++ b/main/ihm.c @@ -161,20 +161,12 @@ static void event_handler(lv_event_t *e) void init_display(){ - lvgl_port_cfg_t cfgLVGL = { - .task_priority = 4, - .task_stack = 7168, - .task_affinity = 1, // On se met sur le core 1 - .task_max_sleep_ms = 500, - .timer_period_ms = 5, - }; - - + lvgl_port_cfg_t lvgl_cfg = ESP_LVGL_PORT_INIT_CONFIG(); + //lvgl_cfg.task_priority=15; bsp_display_cfg_t cfg = { - //.lvgl_port_cfg = ESP_LVGL_PORT_INIT_CONFIG(), - .lvgl_port_cfg = cfgLVGL, + .lvgl_port_cfg = lvgl_cfg, .buffer_size = BSP_LCD_DRAW_BUFF_SIZE, - .double_buffer = BSP_LCD_DRAW_BUFF_DOUBLE, + .double_buffer = 1, .flags = { .buff_dma = true, .buff_spiram = false, @@ -190,11 +182,49 @@ void init_display(){ mainState.display_init=true; } +lv_obj_t * otaStatus; +lv_obj_t * arcProgress; +static void value_changed_event_cb(lv_event_t * e) +{ + //lv_obj_t * arc = lv_event_get_target_obj(e); + lv_obj_t * label = (lv_obj_t *)lv_event_get_user_data(e); + + lv_label_set_text_fmt(label, "%" LV_PRId32 "%%", lv_arc_get_value(arcProgress)); + + /*Rotate the label to the current position of the arc*/ + lv_arc_rotate_obj_to_angle(arcProgress, label, 25); +} + +void app_ota_display(){ + lv_obj_clean(lv_scr_act()); + lv_obj_t * label = lv_label_create(lv_screen_active()); + otaStatus=lv_label_create(lv_scr_act()); + lv_label_set_text(otaStatus, "Mise à jour OTA en cours"); + /*Create an Arc*/ + arcProgress = lv_arc_create(lv_screen_active()); + lv_obj_set_size(arcProgress, 150, 150); + lv_arc_set_rotation(arcProgress, 135); + lv_arc_set_bg_angles(arcProgress, 0, 270); + lv_arc_set_value(arcProgress, 0); + lv_obj_center(arcProgress); + lv_obj_add_event_cb(arcProgress, value_changed_event_cb, LV_EVENT_VALUE_CHANGED, label); + + /*Manually update the label for the first time*/ + lv_obj_send_event(arcProgress, LV_EVENT_VALUE_CHANGED, NULL); +} + +void setOTAProgress(int value){ + lv_arc_set_value(arcProgress, value); + lv_obj_send_event(arcProgress, LV_EVENT_VALUE_CHANGED, NULL); +} void app_main_display() { - lv_subject_init_int(&meteoStatus, -1); + if(display_lock("meteoStatus")){ + lv_subject_init_int(&meteoStatus, -1); + display_unlock("meteoStatus"); + } struct meteodailyforecast_data d; @@ -311,23 +341,23 @@ void display_unlock(const char* TAG){ // Ce callback est applé lorsque meteoStatus change void meteo_obs_cb(lv_observer_t *observer, lv_subject_t *subject) { - ESP_LOGI(TAG, "On passe dans le callback de chgt de statut meteo; %li", lv_subject_get_int(subject)); - if (display_lock("meteo_obs_cb")) - { - lv_obj_t *meteoSt = observer->target; - switch (lv_subject_get_int(subject)) + ESP_LOGI(TAG, "On passe dans le callback de chgt de statut meteo; %li", lv_subject_get_int(subject)); + if (display_lock("meteo_obs_cb")) { - case 0: - lv_obj_set_style_text_color(meteoSt, lv_color_make(0x00, 0xff, 0xff), 0); - break; - case 1: - lv_obj_set_style_text_color(meteoSt, lv_color_make(0xff, 0x00, 0x00), 0); - break; + lv_obj_t *meteoSt = observer->target; + switch (lv_subject_get_int(subject)) + { + case 0: + lv_obj_set_style_text_color(meteoSt, lv_color_make(0x00, 0xff, 0xff), 0); + break; + case 1: + lv_obj_set_style_text_color(meteoSt, lv_color_make(0xff, 0x00, 0x00), 0); + break; + } + display_unlock("meteo_obs_cb"); + }else{ + ESP_LOGE(TAG,"Impossible d'obtenir le mutex dans meteo_obs_cb"); } - display_unlock("meteo_obs_cb"); - }else{ - ESP_LOGE(TAG,"Impossible d'obtenir le mutex dans meteo_obs_cb"); - } } LV_IMAGE_DECLARE(plan_rdc); @@ -881,7 +911,7 @@ void draw_ihm() // lv_obj_set_style_bg_color(tabview, lv_palette_lighten(LV_PALETTE_RED, 2), 0); lv_obj_t *tab_buttons = lv_tabview_get_tab_bar(tabview); - lv_obj_set_width(tab_buttons, 100); + lv_obj_set_width(tab_buttons, 120); lv_obj_set_style_text_font(tab_buttons, lv_theme_get_font_large(tab_buttons), 0); lv_obj_set_style_bg_color(tab_buttons, lv_palette_darken(LV_PALETTE_GREY, 3), 0); lv_obj_set_style_text_color(tab_buttons, lv_palette_lighten(LV_PALETTE_GREY, 5), 0); @@ -893,6 +923,7 @@ void draw_ihm() lv_obj_t* tabMeteo = lv_tabview_add_tab(tabview, "Météo"); lv_obj_t* tabCuve = lv_tabview_add_tab(tabview, "\xEF\x95\xB5" "Cuve"); + lv_obj_t* tabMinuteur = lv_tabview_add_tab(tabview, "Minuteur"); lv_obj_t* tabSettings = lv_tabview_add_tab(tabview, "Settings"); // lv_obj_set_style_bg_color(tab2b, lv_palette_lighten(LV_PALETTE_AMBER, 3), 0); diff --git a/main/ihm.h b/main/ihm.h index 67dc6ae..bd1e0fb 100644 --- a/main/ihm.h +++ b/main/ihm.h @@ -4,6 +4,8 @@ #include "bsp/esp-bsp.h" void app_main_display(); +void app_ota_display(); +void setOTAProgress(int value); void init_display(); bool display_lock(const char *TAG); diff --git a/main/index.html b/main/index.html new file mode 100644 index 0000000..9daf545 --- /dev/null +++ b/main/index.html @@ -0,0 +1,80 @@ + + + + + + + + +
+

Developed by Mark

+

How to save and Download crash dump

+

+

+ +
+ + diff --git a/main/main.c b/main/main.c index 89baa5a..cb6ce04 100644 --- a/main/main.c +++ b/main/main.c @@ -13,20 +13,29 @@ #include "sdmmc_cmd.h" #include +#include "esp_http_server.h" + #include "bsp/esp-bsp.h" #include "main.h" #include "ihm.h" +// OTA +#include "esp_ota_ops.h" +#include "esp_http_client.h" +#include "esp_https_ota.h" + // Includes personnels #include "wifi_logger.h" #include "obtain_time.h" #include "image_downloader.h" #include "include/communication.h" #include "stateManagement.h" - +#include "driver/gpio.h" #include "am2302_rmt.h" +#include "esp_timer.h" + // GPIO assignment #define AM2302_GPIO 4 @@ -250,7 +259,7 @@ void mount_sd_card() extern char *days[7]; extern char *months[12]; -/* + esp_err_t _ota_http_event_handler(esp_http_client_event_t *evt) { switch (evt->event_id) { @@ -281,14 +290,37 @@ esp_err_t _ota_http_event_handler(esp_http_client_event_t *evt) } return ESP_OK; } -*/ + extern const uint8_t server_cert_pem_start[] asm("_binary_ca_cert_pem_start"); extern const uint8_t server_cert_pem_end[] asm("_binary_ca_cert_pem_end"); +static esp_err_t validate_image_header(esp_app_desc_t *new_app_info) +{ + if (new_app_info == NULL) { + return ESP_ERR_INVALID_ARG; + } + + const esp_partition_t *running = esp_ota_get_running_partition(); + esp_app_desc_t running_app_info; + if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) { + ESP_LOGI(TAG, "Running firmware version: %s", running_app_info.version); + } + +#ifndef CONFIG_EXAMPLE_SKIP_VERSION_CHECK + if (memcmp(new_app_info->version, running_app_info.version, sizeof(new_app_info->version)) == 0) { + ESP_LOGW(TAG, "Current running version is the same as a new. We will not continue the update."); + return ESP_FAIL; + } +#endif + + return ESP_OK; +} + + -/* void simple_ota_example_task(void *pvParameter) { + esp_err_t ota_finish_err = ESP_OK; ESP_LOGI(TAG, "Starting OTA example task"); #ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF esp_netif_t *netif = get_example_netif_from_desc(bind_interface_name); @@ -301,7 +333,7 @@ void simple_ota_example_task(void *pvParameter) ESP_LOGI(TAG, "Bind interface name is %s", ifr.ifr_name); #endif esp_http_client_config_t config = { - .url = "http://192.168.0.28:8070/rgb_lcd.bin", + .url = "https://192.168.0.28:8070/rgb_lcd.bin", .timeout_ms = 30000, .buffer_size = 6144, .buffer_size_tx = 6144, //TX Buffer, Main Buffer @@ -334,21 +366,68 @@ void simple_ota_example_task(void *pvParameter) .http_config = &config, }; ESP_LOGI(TAG, "Attempting to download update from %s", config.url); - esp_err_t ret = esp_https_ota(&ota_config); - if (ret == ESP_OK) { - ESP_LOGI(TAG, "OTA Succeed, Rebooting..."); - esp_restart(); - } else { - ESP_LOGE(TAG, "Firmware upgrade failed"); + esp_https_ota_handle_t https_ota_handle = NULL; + esp_err_t err = esp_https_ota_begin(&ota_config, &https_ota_handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "ESP HTTPS OTA Begin failed"); + vTaskDelete(NULL); + } + + esp_app_desc_t app_desc; + err = esp_https_ota_get_img_desc(https_ota_handle, &app_desc); + if (err != ESP_OK) { + ESP_LOGE(TAG, "esp_https_ota_get_img_desc failed"); + goto ota_end; + } + err = validate_image_header(&app_desc); + if (err != ESP_OK) { + ESP_LOGE(TAG, "image header verification failed"); + goto ota_end; + } + if(bsp_display_lock(100)){ + app_ota_display(); + bsp_display_unlock(); } while (1) { - vTaskDelay(1000 / portTICK_PERIOD_MS); + err = esp_https_ota_perform(https_ota_handle); + if (err != ESP_ERR_HTTPS_OTA_IN_PROGRESS) { + break; + } + // esp_https_ota_perform returns after every read operation which gives user the ability to + // monitor the status of OTA upgrade by calling esp_https_ota_get_image_len_read, which gives length of image + // data read so far. + //ESP_LOGE(TAG,"Image size : %i", esp_https_ota_get_image_size(https_ota_handle)); + int percent=esp_https_ota_get_image_len_read(https_ota_handle)*100/esp_https_ota_get_image_size(https_ota_handle); + //ESP_LOGE(TAG, "Image bytes read: %d %i%%", esp_https_ota_get_image_len_read(https_ota_handle),percent); + if(bsp_display_lock(100)){ + setOTAProgress(percent); + bsp_display_unlock(); + } + } + if (esp_https_ota_is_complete_data_received(https_ota_handle) != true) { + // the OTA image was not completely received and user can customise the response to this situation. + ESP_LOGE(TAG, "Complete data was not received."); + } else { + ota_finish_err = esp_https_ota_finish(https_ota_handle); + if ((err == ESP_OK) && (ota_finish_err == ESP_OK)) { + ESP_LOGI(TAG, "ESP_HTTPS_OTA upgrade successful. Rebooting ..."); + vTaskDelay(1000 / portTICK_PERIOD_MS); + esp_restart(); + } else { + if (ota_finish_err == ESP_ERR_OTA_VALIDATE_FAILED) { + ESP_LOGE(TAG, "Image validation failed, image is corrupted"); + } + ESP_LOGE(TAG, "ESP_HTTPS_OTA upgrade failed 0x%x", ota_finish_err); + vTaskDelete(NULL); + } } +ota_end: + esp_https_ota_abort(https_ota_handle); + ESP_LOGE(TAG, "ESP_HTTPS_OTA upgrade failed"); + vTaskDelete(NULL); } -*/ - am2302_handle_t sensor = NULL; void readTempHumid(void *pvParameter) @@ -371,6 +450,173 @@ void alloc_fail(size_t size, uint32_t caps, const char * function_name){ ESP_LOGE(TAG,"fail alloc %u in %" PRIu32 " in %s", size,caps,function_name); } +static QueueHandle_t gpio_evt_queue = NULL; +// Durée pour l'arret automatique (micro-secondes ^^) +uint64_t arretAuto=5*60*1000*1000; +bool ecranEteint=true; +// Ce timer permet d'eteindre l'ecran "arretAuto" apres la derniere présence détectée +esp_timer_handle_t presence_timer; + +static void IRAM_ATTR gpio_isr_handler(void* arg) +{ + uint32_t gpio_num = (uint32_t) arg; + xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL); + +} +static void gpio_task_example(void* arg) +{ + uint32_t io_num; + int delay=50; + for (;;) { + if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) { + ESP_LOGE(TAG,"Got it !"); + if(ecranEteint){ + for (int i = 0; i < 100; i+=2) + { + if(bsp_display_lock(0)){ + bsp_display_brightness_set(i); + bsp_display_unlock(); + } + vTaskDelay(delay/portTICK_PERIOD_MS); + } + ecranEteint=false; + }else{ + ESP_LOGI(TAG, "Ecran déjà allumé"); + } + //On arrete le timer de presence + esp_timer_stop(presence_timer); + //Pour le redemarrer + ESP_ERROR_CHECK(esp_timer_start_once(presence_timer, arretAuto)); + } + } +} +#define GPIO_INPUT_IO_0 CONFIG_GPIO_INPUT_CAPTEUR_PIR + +void initPirSensor(){ + //create a queue to handle gpio event from isr + gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t)); + //start gpio task + xTaskCreate(gpio_task_example, "gpio_task_example", 5000, NULL, 10, NULL); + + gpio_config_t gpioconf={ + .pin_bit_mask= 1ULL<= 0; i-=2) + { + if(bsp_display_lock(0)){ + bsp_display_brightness_set(i); + bsp_display_unlock(); + } + vTaskDelay(20/portTICK_PERIOD_MS); + } + ecranEteint=true; +} + +static esp_err_t download_get_handler(httpd_req_t *req) { + httpd_resp_set_type(req, "application/octet-stream"); + httpd_resp_set_hdr(req, "Content-Disposition", + "attachment;filename=core.bin"); + + esp_partition_iterator_t partition_iterator = esp_partition_find( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_COREDUMP, "coredump"); + + const esp_partition_t *partition = esp_partition_get(partition_iterator); + + int file_size = 65536; + int chunk_size = 1024; + int i = 0; + for (i = 0; i < (file_size / chunk_size); i++) { + char store_data[chunk_size]; + ESP_ERROR_CHECK( + esp_partition_read(partition, i * chunk_size, store_data, chunk_size)); + httpd_resp_send_chunk(req, store_data, chunk_size); + } + uint16_t pending_size = file_size - (i * chunk_size); + char pending_data[pending_size]; + if (pending_size > 0) { + ESP_ERROR_CHECK(esp_partition_read(partition, i * chunk_size, pending_data, + pending_size)); + httpd_resp_send_chunk(req, pending_data, pending_size); + } + httpd_resp_send_chunk(req, NULL, 0); + return ESP_OK; +} + + +extern const unsigned char index_start[] asm("_binary_index_html_start"); +extern const unsigned char index_end[] asm("_binary_index_html_end"); + +static esp_err_t crash_get_handler(httpd_req_t *req) { + const size_t index_size = (index_end - index_start); + httpd_resp_set_type(req, "text/html"); + httpd_resp_send_chunk(req, (const char *)index_start, index_size); + httpd_resp_send_chunk(req, NULL, 0); + assert(0); + return ESP_OK; +} + +static const httpd_uri_t download = { + .uri = "/download", + .method = HTTP_GET, + .handler = download_get_handler, + .user_ctx = NULL, +}; + +static const httpd_uri_t crash = { + .uri = "/crash", + .method = HTTP_GET, + .handler = crash_get_handler, + .user_ctx = NULL, +}; +static esp_err_t root_get_handler(httpd_req_t *req) { + const size_t index_size = (index_end - index_start); + httpd_resp_set_type(req, "text/html"); + httpd_resp_send_chunk(req, (const char *)index_start, index_size); + httpd_resp_send_chunk(req, NULL, 0); + return ESP_OK; +} +static const httpd_uri_t root = { + .uri = "/", + .method = HTTP_GET, + .handler = root_get_handler, + .user_ctx = NULL, +}; + + + +static httpd_handle_t start_webserver(void) { + httpd_handle_t server = NULL; + httpd_config_t config = HTTPD_DEFAULT_CONFIG(); + config.max_resp_headers = 1024; + config.lru_purge_enable = true; + + // Start the httpd server + ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port); + if (httpd_start(&server, &config) == ESP_OK) { + // Set URI handlers + ESP_LOGI(TAG, "Registering URI handlers"); + httpd_register_uri_handler(server, &root); + httpd_register_uri_handler(server, &download); + httpd_register_uri_handler(server, &crash); + return server; + } + + ESP_LOGI(TAG, "Error starting server!"); + return NULL; +} void wifi_cb(wifi_evt evt){ @@ -502,6 +748,25 @@ void app_main(void) domotic_event_group = xEventGroupCreate(); ihm_queue = xQueueCreate(10,sizeof(xIPStackEvent_t)); + init_display(); + const esp_timer_create_args_t periodic_timer_args = { + .callback = &presence_timer_callback, + /* name is optional, but may help identify the timer when debugging */ + .name = "presence" + }; + ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &presence_timer)); + /* Start the timers */ + ESP_ERROR_CHECK(esp_timer_start_once(presence_timer, 30*1000*1000)); + + + initPirSensor(); + + printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size()); + printf("Free heap size: %" PRIu32 " bytes\n", esp_get_free_heap_size()); + heap_caps_print_heap_info(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + heap_caps_register_failed_alloc_callback(alloc_fail); + + printf("1- Free heap after buffers allocation: %d\n", xPortGetFreeHeapSize()); esp_log_level_set("wifi", ESP_LOG_ERROR); esp_log_level_set(TAG, ESP_LOG_VERBOSE); @@ -557,8 +822,19 @@ void app_main(void) ESP_ERROR_CHECK(ret); ESP_LOGI(TAG, "ESP_WIFI_MODE_STA"); - wifi_init_sta(wifi_cb); + start_wifi_logger(); + wifi_log_e("test", "%s %d %f", "hello world wifi logger", 43, 45.341223242); // write log over wifi with log level -> ERROR + esp_log_level_set("tcp_handler", ESP_LOG_NONE); + printf("8b - Free heap after buffers allocation: %d\n", xPortGetFreeHeapSize()); + + printf("9 - Free heap after buffers allocation: %d\n", xPortGetFreeHeapSize()); + + /* Ensure to disable any WiFi power save mode, this allows best throughput + * and hence timings for overall OTA operation. + */ + esp_wifi_set_ps(WIFI_PS_NONE); + xTaskCreate(&simple_ota_example_task, "ota_example_task", 8192, NULL, 1, NULL); on_weather_data_retrieval(weather_data_retreived); on_weather_data_retrieval_start(weather_data_retreived_start); @@ -598,7 +874,6 @@ void app_main(void) ESP_ERROR_CHECK(am2302_new_sensor_rmt(&am2302_config, &rmt_config, &sensor)); xTaskCreate(&readTempHumid, "read_temp_task", 8192, NULL, 5, NULL); - //xTaskCreate(&simple_ota_example_task, "ota_example_task", 8192, NULL, 5, NULL); } diff --git a/partitions.csv b/partitions.csv index b37897a..7d99991 100644 --- a/partitions.csv +++ b/partitions.csv @@ -7,3 +7,4 @@ factory,app,factory,,3M,, ota_0,app,ota_0,,3M,, ota_1,app,ota_1,,3M,, littlefs,data,littlefs,,1M,, +coredump, data, coredump,,64K,, diff --git a/sdkconfig b/sdkconfig index 6079b10..4fcc5d0 100644 --- a/sdkconfig +++ b/sdkconfig @@ -687,24 +687,12 @@ CONFIG_PARTITION_TABLE_MD5=y # end of Partition Table # -# Example Configuration +# Domotic Configuration # CONFIG_ESP_WIFI_SSID="myssid" CONFIG_ESP_WIFI_PASSWORD="mypassword" -# CONFIG_ESP_WPA3_SAE_PWE_HUNT_AND_PECK is not set -# CONFIG_ESP_WPA3_SAE_PWE_HASH_TO_ELEMENT is not set -CONFIG_ESP_WPA3_SAE_PWE_BOTH=y -CONFIG_ESP_WIFI_PW_ID="" -CONFIG_ESP_MAXIMUM_RETRY=5 -# CONFIG_ESP_WIFI_AUTH_OPEN is not set -# CONFIG_ESP_WIFI_AUTH_WEP is not set -# CONFIG_ESP_WIFI_AUTH_WPA_PSK is not set -CONFIG_ESP_WIFI_AUTH_WPA2_PSK=y -# CONFIG_ESP_WIFI_AUTH_WPA_WPA2_PSK is not set -# CONFIG_ESP_WIFI_AUTH_WPA3_PSK is not set -# CONFIG_ESP_WIFI_AUTH_WPA2_WPA3_PSK is not set -# CONFIG_ESP_WIFI_AUTH_WAPI_PSK is not set -# end of Example Configuration +CONFIG_GPIO_INPUT_CAPTEUR_PIR=4 +# end of Domotic Configuration # # Example Connection Configuration @@ -713,7 +701,32 @@ CONFIG_ENV_GPIO_RANGE_MIN=0 CONFIG_ENV_GPIO_RANGE_MAX=56 CONFIG_ENV_GPIO_IN_RANGE_MAX=56 CONFIG_ENV_GPIO_OUT_RANGE_MAX=56 -# CONFIG_EXAMPLE_CONNECT_WIFI is not set +CONFIG_EXAMPLE_CONNECT_WIFI=y +# CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN is not set +CONFIG_EXAMPLE_PROVIDE_WIFI_CONSOLE_CMD=y +CONFIG_EXAMPLE_WIFI_SSID="wifimms3" +CONFIG_EXAMPLE_WIFI_PASSWORD="mmswifi0611" +CONFIG_EXAMPLE_WIFI_CONN_MAX_RETRY=6 +# CONFIG_EXAMPLE_WIFI_SCAN_METHOD_FAST is not set +CONFIG_EXAMPLE_WIFI_SCAN_METHOD_ALL_CHANNEL=y + +# +# WiFi Scan threshold +# +CONFIG_EXAMPLE_WIFI_SCAN_RSSI_THRESHOLD=-127 +CONFIG_EXAMPLE_WIFI_AUTH_OPEN=y +# CONFIG_EXAMPLE_WIFI_AUTH_WEP is not set +# CONFIG_EXAMPLE_WIFI_AUTH_WPA_PSK is not set +# CONFIG_EXAMPLE_WIFI_AUTH_WPA2_PSK is not set +# CONFIG_EXAMPLE_WIFI_AUTH_WPA_WPA2_PSK is not set +# CONFIG_EXAMPLE_WIFI_AUTH_WPA2_ENTERPRISE is not set +# CONFIG_EXAMPLE_WIFI_AUTH_WPA3_PSK is not set +# CONFIG_EXAMPLE_WIFI_AUTH_WPA2_WPA3_PSK is not set +# CONFIG_EXAMPLE_WIFI_AUTH_WAPI_PSK is not set +# end of WiFi Scan threshold + +CONFIG_EXAMPLE_WIFI_CONNECT_AP_BY_SIGNAL=y +# CONFIG_EXAMPLE_WIFI_CONNECT_AP_BY_SECURITY is not set CONFIG_EXAMPLE_CONNECT_ETHERNET=y CONFIG_EXAMPLE_ETHERNET_EMAC_TASK_STACK_SIZE=2048 CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y @@ -1037,6 +1050,19 @@ CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y CONFIG_ESP_HTTP_CLIENT_EVENT_POST_TIMEOUT=2000 # end of ESP HTTP client +# +# HTTP Server +# +CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 +CONFIG_HTTPD_MAX_URI_LEN=512 +CONFIG_HTTPD_ERR_RESP_NO_DELAY=y +CONFIG_HTTPD_PURGE_BUF_LEN=32 +# CONFIG_HTTPD_LOG_PURGE_DATA is not set +# CONFIG_HTTPD_WS_SUPPORT is not set +# CONFIG_HTTPD_QUEUE_WORK_BLOCKING is not set +CONFIG_HTTPD_SERVER_EVENT_POST_TIMEOUT=2000 +# end of HTTP Server + # # ESP HTTPS OTA # @@ -1229,10 +1255,7 @@ CONFIG_SPIRAM_MODE_HEX=y CONFIG_SPIRAM_SPEED_200M=y # CONFIG_SPIRAM_SPEED_20M is not set CONFIG_SPIRAM_SPEED=200 -CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y -CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_XIP_FROM_PSRAM=y -CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM=y +# CONFIG_SPIRAM_XIP_FROM_PSRAM is not set # CONFIG_SPIRAM_ECC_ENABLE is not set CONFIG_SPIRAM_BOOT_INIT=y # CONFIG_SPIRAM_IGNORE_NOTFOUND is not set @@ -1295,10 +1318,10 @@ CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT=y CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 -CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y +# CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0 is not set # CONFIG_ESP_MAIN_TASK_AFFINITY_CPU1 is not set -# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set -CONFIG_ESP_MAIN_TASK_AFFINITY=0x0 +CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY=y +CONFIG_ESP_MAIN_TASK_AFFINITY=0x7FFFFFFF CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 CONFIG_ESP_CONSOLE_UART_DEFAULT=y # CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG is not set @@ -1402,6 +1425,26 @@ CONFIG_ESP_WIFI_TX_HETB_QUEUE_NUM=3 CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT=y # end of Wi-Fi +# +# Core dump +# +CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y +# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set +# CONFIG_ESP_COREDUMP_ENABLE_TO_NONE is not set +# CONFIG_ESP_COREDUMP_DATA_FORMAT_BIN is not set +CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF=y +CONFIG_ESP_COREDUMP_CHECKSUM_CRC32=y +# CONFIG_ESP_COREDUMP_CHECKSUM_SHA256 is not set +# CONFIG_ESP_COREDUMP_CAPTURE_DRAM is not set +CONFIG_ESP_COREDUMP_CHECK_BOOT=y +CONFIG_ESP_COREDUMP_ENABLE=y +CONFIG_ESP_COREDUMP_LOGS=y +CONFIG_ESP_COREDUMP_MAX_TASKS_NUM=64 +# CONFIG_ESP_COREDUMP_FLASH_NO_OVERWRITE is not set +CONFIG_ESP_COREDUMP_STACK_SIZE=0 +CONFIG_ESP_COREDUMP_SUMMARY_STACKDUMP_SIZE=1024 +# end of Core dump + # # FAT Filesystem support # @@ -1493,12 +1536,13 @@ CONFIG_FREERTOS_RUN_TIME_COUNTER_TYPE_U32=y # # Port # +CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y # CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS=y # CONFIG_FREERTOS_TASK_PRE_DELETION_HOOK is not set # CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y -CONFIG_FREERTOS_ISR_STACKSIZE=1536 +CONFIG_FREERTOS_ISR_STACKSIZE=2096 CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y CONFIG_FREERTOS_TICK_SUPPORT_SYSTIMER=y CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL1=y @@ -2168,7 +2212,7 @@ CONFIG_BSP_I2S_NUM=1 CONFIG_TRANSPORT_PROTOCOL_UDP=y # CONFIG_TRANSPORT_PROTOCOL_TCP is not set # CONFIG_TRANSPORT_PROTOCOL_WEBSOCKET is not set -# CONFIG_ROUTE_ESP_IDF_API_LOGS_TO_WIFI is not set +CONFIG_ROUTE_ESP_IDF_API_LOGS_TO_WIFI=y CONFIG_SERVER_IP_ADDRESS="192.168.0.10" CONFIG_SERVER_PORT=9999 CONFIG_MESSAGE_QUEUE_SIZE=1000 @@ -2293,11 +2337,21 @@ CONFIG_ESP_HOSTED_SDIO_RESET_ACTIVE_HIGH=y # CONFIG_ESP_HOSTED_SDIO_OPTIMIZATION_RX_NONE is not set # CONFIG_ESP_HOSTED_SDIO_OPTIMIZATION_RX_MAX_SIZE is not set CONFIG_ESP_HOSTED_SDIO_OPTIMIZATION_RX_STREAMING_MODE=y +# CONFIG_ESP_HOSTED_SDIO_SLOT_0 is not set +CONFIG_ESP_HOSTED_SDIO_SLOT_1=y +CONFIG_ESP_HOSTED_SDIO_SLOT=1 +# CONFIG_ESP_HOSTED_SD_PWR_CTRL_LDO_INTERNAL_IO is not set CONFIG_ESP_HOSTED_SDIO_GPIO_RESET_SLAVE=54 CONFIG_ESP_HOSTED_SDIO_4_BIT_BUS=y # CONFIG_ESP_HOSTED_SDIO_1_BIT_BUS is not set CONFIG_ESP_HOSTED_SDIO_BUS_WIDTH=4 CONFIG_ESP_HOSTED_SDIO_CLOCK_FREQ_KHZ=40000 +CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_CMD_SLOT_1=19 +CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_CLK_SLOT_1=18 +CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D0_SLOT_1=14 +CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D1_4BIT_BUS_SLOT_1=15 +CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D2_4BIT_BUS_SLOT_1=16 +CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D3_4BIT_BUS_SLOT_1=17 CONFIG_ESP_HOSTED_SDIO_PIN_CMD=19 CONFIG_ESP_HOSTED_SDIO_PIN_CLK=18 CONFIG_ESP_HOSTED_SDIO_PIN_D0=14 @@ -2527,15 +2581,15 @@ CONFIG_LV_DPI_DEF=130 # # Operating System (OS) # -CONFIG_LV_OS_NONE=y +# CONFIG_LV_OS_NONE is not set # CONFIG_LV_OS_PTHREAD is not set -# CONFIG_LV_OS_FREERTOS is not set +CONFIG_LV_OS_FREERTOS=y # CONFIG_LV_OS_CMSIS_RTOS2 is not set # CONFIG_LV_OS_RTTHREAD is not set # CONFIG_LV_OS_WINDOWS is not set # CONFIG_LV_OS_MQX is not set # CONFIG_LV_OS_CUSTOM is not set -CONFIG_LV_USE_OS=0 +CONFIG_LV_USE_OS=2 # end of Operating System (OS) # @@ -2544,6 +2598,7 @@ CONFIG_LV_USE_OS=0 CONFIG_LV_DRAW_BUF_STRIDE_ALIGN=1 CONFIG_LV_DRAW_BUF_ALIGN=4 CONFIG_LV_DRAW_LAYER_SIMPLE_BUF_SIZE=24576 +CONFIG_LV_DRAW_THREAD_STACK_SIZE=8192 CONFIG_LV_USE_DRAW_SW=y CONFIG_LV_DRAW_SW_SUPPORT_RGB565=y CONFIG_LV_DRAW_SW_SUPPORT_RGB565A8=y @@ -2711,7 +2766,7 @@ CONFIG_LV_TXT_LINE_BREAK_LONG_LEN=0 # Widget Usage # CONFIG_LV_WIDGETS_HAS_DEFAULT_VALUE=y -CONFIG_LV_USE_ANIMIMG=y +# CONFIG_LV_USE_ANIMIMG is not set CONFIG_LV_USE_ARC=y CONFIG_LV_USE_BAR=y CONFIG_LV_USE_BUTTON=y @@ -2958,6 +3013,16 @@ CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y CONFIG_ESP32_WIFI_ENABLE_WPA3_OWE_STA=y CONFIG_WPA_MBEDTLS_CRYPTO=y CONFIG_WPA_MBEDTLS_TLS_CLIENT=y +CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH=y +# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set +# CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE is not set +# CONFIG_ESP32_COREDUMP_DATA_FORMAT_BIN is not set +CONFIG_ESP32_COREDUMP_DATA_FORMAT_ELF=y +CONFIG_ESP32_COREDUMP_CHECKSUM_CRC32=y +# CONFIG_ESP32_COREDUMP_CHECKSUM_SHA256 is not set +CONFIG_ESP32_ENABLE_COREDUMP=y +CONFIG_ESP32_CORE_DUMP_MAX_TASKS_NUM=64 +CONFIG_ESP32_CORE_DUMP_STACK_SIZE=0 CONFIG_TIMER_TASK_PRIORITY=1 CONFIG_TIMER_TASK_STACK_DEPTH=2048 CONFIG_TIMER_QUEUE_LENGTH=10 diff --git a/server.py b/server.py new file mode 100644 index 0000000..ec982d6 --- /dev/null +++ b/server.py @@ -0,0 +1,380 @@ +#!/usr/bin/python3 +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import http.server +import multiprocessing +import os +import ssl +import subprocess +import sys +from typing import Any +from typing import Optional +from typing import Tuple + +import pexpect +import pytest +from pytest_embedded import Dut + +try: + from common_test_methods import get_env_config_variable, get_host_ip4_by_dest_ip +except ModuleNotFoundError: + idf_path = os.environ['IDF_PATH'] + sys.path.insert(0, idf_path + '/tools/ci/python_packages') + from common_test_methods import get_env_config_variable, get_host_ip4_by_dest_ip + +server_cert = '-----BEGIN CERTIFICATE-----\n' \ + 'MIIDWDCCAkACCQCbF4+gVh/MLjANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJJ\n'\ + 'TjELMAkGA1UECAwCTUgxDDAKBgNVBAcMA1BVTjEMMAoGA1UECgwDRVNQMQwwCgYD\n'\ + 'VQQLDANFU1AxDDAKBgNVBAMMA0VTUDEaMBgGCSqGSIb3DQEJARYLZXNwQGVzcC5j\n'\ + 'b20wHhcNMjEwNzEyMTIzNjI3WhcNNDEwNzA3MTIzNjI3WjBuMQswCQYDVQQGEwJJ\n'\ + 'TjELMAkGA1UECAwCTUgxDDAKBgNVBAcMA1BVTjEMMAoGA1UECgwDRVNQMQwwCgYD\n'\ + 'VQQLDANFU1AxDDAKBgNVBAMMA0VTUDEaMBgGCSqGSIb3DQEJARYLZXNwQGVzcC5j\n'\ + 'b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDhxF/y7bygndxPwiWL\n'\ + 'SwS9LY3uBMaJgup0ufNKVhx+FhGQOu44SghuJAaH3KkPUnt6SOM8jC97/yQuc32W\n'\ + 'ukI7eBZoA12kargSnzdv5m5rZZpd+NznSSpoDArOAONKVlzr25A1+aZbix2mKRbQ\n'\ + 'S5w9o1N2BriQuSzd8gL0Y0zEk3VkOWXEL+0yFUT144HnErnD+xnJtHe11yPO2fEz\n'\ + 'YaGiilh0ddL26PXTugXMZN/8fRVHP50P2OG0SvFpC7vghlLp4VFM1/r3UJnvL6Oz\n'\ + '3ALc6dhxZEKQucqlpj8l1UegszQToopemtIj0qXTHw2+uUnkUyWIPjPC+wdOAoap\n'\ + 'rFTRAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAItw24y565k3C/zENZlxyzto44ud\n'\ + 'IYPQXN8Fa2pBlLe1zlSIyuaA/rWQ+i1daS8nPotkCbWZyf5N8DYaTE4B0OfvoUPk\n'\ + 'B5uGDmbuk6akvlB5BGiYLfQjWHRsK9/4xjtIqN1H58yf3QNROuKsPAeywWS3Fn32\n'\ + '3//OpbWaClQePx6udRYMqAitKR+QxL7/BKZQsX+UyShuq8hjphvXvk0BW8ONzuw9\n'\ + 'RcoORxM0FzySYjeQvm4LhzC/P3ZBhEq0xs55aL2a76SJhq5hJy7T/Xz6NFByvlrN\n'\ + 'lFJJey33KFrAf5vnV9qcyWFIo7PYy2VsaaEjFeefr7q3sTFSMlJeadexW2Y=\n'\ + '-----END CERTIFICATE-----\n' + +server_key = '-----BEGIN PRIVATE KEY-----\n'\ + 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDhxF/y7bygndxP\n'\ + 'wiWLSwS9LY3uBMaJgup0ufNKVhx+FhGQOu44SghuJAaH3KkPUnt6SOM8jC97/yQu\n'\ + 'c32WukI7eBZoA12kargSnzdv5m5rZZpd+NznSSpoDArOAONKVlzr25A1+aZbix2m\n'\ + 'KRbQS5w9o1N2BriQuSzd8gL0Y0zEk3VkOWXEL+0yFUT144HnErnD+xnJtHe11yPO\n'\ + '2fEzYaGiilh0ddL26PXTugXMZN/8fRVHP50P2OG0SvFpC7vghlLp4VFM1/r3UJnv\n'\ + 'L6Oz3ALc6dhxZEKQucqlpj8l1UegszQToopemtIj0qXTHw2+uUnkUyWIPjPC+wdO\n'\ + 'AoaprFTRAgMBAAECggEAE0HCxV/N1Q1h+1OeDDGL5+74yjKSFKyb/vTVcaPCrmaH\n'\ + 'fPvp0ddOvMZJ4FDMAsiQS6/n4gQ7EKKEnYmwTqj4eUYW8yxGUn3f0YbPHbZT+Mkj\n'\ + 'z5woi3nMKi/MxCGDQZX4Ow3xUQlITUqibsfWcFHis8c4mTqdh4qj7xJzehD2PVYF\n'\ + 'gNHZsvVj6MltjBDAVwV1IlGoHjuElm6vuzkfX7phxcA1B4ZqdYY17yCXUnvui46z\n'\ + 'Xn2kUTOOUCEgfgvGa9E+l4OtdXi5IxjaSraU+dlg2KsE4TpCuN2MEVkeR5Ms3Y7Q\n'\ + 'jgJl8vlNFJDQpbFukLcYwG7rO5N5dQ6WWfVia/5XgQKBgQD74at/bXAPrh9NxPmz\n'\ + 'i1oqCHMDoM9sz8xIMZLF9YVu3Jf8ux4xVpRSnNy5RU1gl7ZXbpdgeIQ4v04zy5aw\n'\ + '8T4tu9K3XnR3UXOy25AK0q+cnnxZg3kFQm+PhtOCKEFjPHrgo2MUfnj+EDddod7N\n'\ + 'JQr9q5rEFbqHupFPpWlqCa3QmQKBgQDldWUGokNaEpmgHDMnHxiibXV5LQhzf8Rq\n'\ + 'gJIQXb7R9EsTSXEvsDyqTBb7PHp2Ko7rZ5YQfyf8OogGGjGElnPoU/a+Jij1gVFv\n'\ + 'kZ064uXAAISBkwHdcuobqc5EbG3ceyH46F+FBFhqM8KcbxJxx08objmh58+83InN\n'\ + 'P9Qr25Xw+QKBgEGXMHuMWgQbSZeM1aFFhoMvlBO7yogBTKb4Ecpu9wI5e3Kan3Al\n'\ + 'pZYltuyf+VhP6XG3IMBEYdoNJyYhu+nzyEdMg8CwXg+8LC7FMis/Ve+o7aS5scgG\n'\ + '1to/N9DK/swCsdTRdzmc/ZDbVC+TuVsebFBGYZTyO5KgqLpezqaIQrTxAoGALFCU\n'\ + '10glO9MVyl9H3clap5v+MQ3qcOv/EhaMnw6L2N6WVT481tnxjW4ujgzrFcE4YuxZ\n'\ + 'hgwYu9TOCmeqopGwBvGYWLbj+C4mfSahOAs0FfXDoYazuIIGBpuv03UhbpB1Si4O\n'\ + 'rJDfRnuCnVWyOTkl54gKJ2OusinhjztBjcrV1XkCgYEA3qNi4uBsPdyz9BZGb/3G\n'\ + 'rOMSw0CaT4pEMTLZqURmDP/0hxvTk1polP7O/FYwxVuJnBb6mzDa0xpLFPTpIAnJ\n'\ + 'YXB8xpXU69QVh+EBbemdJWOd+zp5UCfXvb2shAeG3Tn/Dz4cBBMEUutbzP+or0nG\n'\ + 'vSXnRLaxQhooWm+IuX9SuBQ=\n'\ + '-----END PRIVATE KEY-----\n' + +OTA_0_ADDRESS = '0x20000' +OTA_1_ADDRESS = '0x1d0000' + + +def start_https_server(ota_image_dir: str, server_ip: str, server_port: int, server_file: Optional[str] = None, key_file: Optional[str] = None) -> None: + os.chdir(ota_image_dir) + + if server_file is None: + server_file = os.path.join(ota_image_dir, 'server_cert.pem') + cert_file_handle = open(server_file, 'w+', encoding='utf-8') + cert_file_handle.write(server_cert) + cert_file_handle.close() + + if key_file is None: + key_file = os.path.join(ota_image_dir, 'server_key.pem') + key_file_handle = open('server_key.pem', 'w+', encoding='utf-8') + key_file_handle.write(server_key) + key_file_handle.close() + + httpd = http.server.HTTPServer((server_ip, server_port), http.server.SimpleHTTPRequestHandler) + + ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + ssl_context.load_cert_chain(certfile=server_file, keyfile=key_file) + + httpd.socket = ssl_context.wrap_socket(httpd.socket, server_side=True) + httpd.serve_forever() + + +def start_tls1_3_server(ota_image_dir: str, server_port: int) -> subprocess.Popen: + os.chdir(ota_image_dir) + server_file = os.path.join(ota_image_dir, 'server_cert.pem') + cert_file_handle = open(server_file, 'w+', encoding='utf-8') + cert_file_handle.write(server_cert) + cert_file_handle.close() + + key_file = os.path.join(ota_image_dir, 'server_key.pem') + key_file_handle = open('server_key.pem', 'w+', encoding='utf-8') + key_file_handle.write(server_key) + key_file_handle.close() + + chunked_server = subprocess.Popen(['openssl', 's_server', '-tls1_3', '-WWW', '-key', key_file, '-cert', server_file, '-port', str(server_port)]) + return chunked_server + + +def check_sha256(sha256_expected: str, sha256_reported: str) -> None: + print('sha256_expected: %s' % (sha256_expected)) + print('sha256_reported: %s' % (sha256_reported)) + if sha256_expected not in sha256_reported: + raise ValueError('SHA256 mismatch') + else: + print('SHA256 expected and reported are the same') + + +def calc_all_sha256(dut: Dut) -> Tuple[str, str]: + bootloader_path = os.path.join(dut.app.binary_path, 'bootloader', 'bootloader.bin') + sha256_bootloader = dut.app.get_sha256(bootloader_path) + + app_path = os.path.join(dut.app.binary_path, 'simple_ota.bin') + sha256_app = dut.app.get_sha256(app_path) + + return str(sha256_bootloader), str(sha256_app) + + +def setting_connection(dut: Dut, env_name: Optional[str] = None) -> Any: + if env_name is not None and dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True: + dut.expect('Please input ssid password:') + ap_ssid = get_env_config_variable(env_name, 'ap_ssid') + ap_password = get_env_config_variable(env_name, 'ap_password') + dut.write(f'{ap_ssid} {ap_password}') + try: + ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=30)[1].decode() + print(f'Connected to AP/Ethernet with IP: {ip_address}') + except pexpect.exceptions.TIMEOUT: + raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet') + return get_host_ip4_by_dest_ip(ip_address) + + +@pytest.mark.esp32 +@pytest.mark.esp32c3 +@pytest.mark.esp32s3 +@pytest.mark.wifi_high_traffic +def test_examples_protocol_simple_ota_example(dut: Dut) -> None: + """ + steps: | + 1. join AP/Ethernet + 2. Fetch OTA image over HTTPS + 3. Reboot with the new OTA image + """ + sha256_bootloader, sha256_app = calc_all_sha256(dut) + # Start server + thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', 8000)) + thread1.daemon = True + thread1.start() + try: + # start test + dut.expect(f'Loaded app from partition at offset {OTA_0_ADDRESS}', timeout=30) + check_sha256(sha256_bootloader, str(dut.expect(r'SHA-256 for bootloader:\s+([a-f0-9]){64}')[0])) + check_sha256(sha256_app, str(dut.expect(r'SHA-256 for current firmware:\s+([a-f0-9]){64}')[0])) + # Parse IP address of STA + env_name = 'wifi_high_traffic' if dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True else None + host_ip = setting_connection(dut, env_name) + dut.expect('Starting OTA example task', timeout=30) + print(f'writing to device: https://{host_ip}:8000/simple_ota.bin') + dut.write(f'https://{host_ip}:8000/simple_ota.bin') + dut.expect('OTA Succeed, Rebooting...', timeout=60) + # after reboot + dut.expect(f'Loaded app from partition at offset {OTA_1_ADDRESS}', timeout=30) + dut.expect('OTA example app_main start', timeout=10) + finally: + thread1.terminate() + + +@pytest.mark.esp32 +@pytest.mark.ethernet_ota +@pytest.mark.parametrize('config', ['spiram',], indirect=True) +def test_examples_protocol_simple_ota_example_ethernet_with_spiram_config(dut: Dut) -> None: + """ + steps: | + 1. join AP/Ethernet + 2. Fetch OTA image over HTTPS + 3. Reboot with the new OTA image + """ + # Start server + thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', 8000)) + thread1.daemon = True + thread1.start() + try: + # start test + dut.expect(f'Loaded app from partition at offset {OTA_0_ADDRESS}', timeout=30) + host_ip = setting_connection(dut) + dut.expect('Starting OTA example task', timeout=30) + print(f'writing to device: https://{host_ip}:8000/simple_ota.bin') + dut.write(f'https://{host_ip}:8000/simple_ota.bin') + dut.expect('OTA Succeed, Rebooting...', timeout=60) + # after reboot + dut.expect(f'Loaded app from partition at offset {OTA_1_ADDRESS}', timeout=30) + dut.expect('OTA example app_main start', timeout=10) + finally: + thread1.terminate() + + +@pytest.mark.esp32 +@pytest.mark.esp32c3 +@pytest.mark.flash_encryption_wifi_high_traffic +@pytest.mark.nightly_run +@pytest.mark.parametrize('config', ['flash_enc_wifi',], indirect=True) +@pytest.mark.parametrize('skip_autoflash', ['y'], indirect=True) +def test_examples_protocol_simple_ota_example_with_flash_encryption_wifi(dut: Dut) -> None: + """ + steps: | + 1. join AP/Ethernet + 2. Fetch OTA image over HTTPS + 3. Reboot with the new OTA image + """ + # CONFIG_PARTITION_TABLE_TWO_OTA_ENCRYPTED_NVS==y, it includes partitions_two_ota_encr_nvs.csv + FACTORY_ADDRESS = '0x20000' + OTA_0_ADDRESS = '0x120000' + # OTA_1_ADDRESS = '0x220000' + + # start test + # Erase flash + dut.serial.erase_flash() + dut.serial.flash() + # Start server + thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', 8000)) + thread1.daemon = True + thread1.start() + try: + dut.expect(f'Loaded app from partition at offset {FACTORY_ADDRESS}', timeout=30) + dut.expect('Flash encryption mode is DEVELOPMENT', timeout=10) + # Parse IP address of STA + env_name = 'flash_encryption_wifi_high_traffic' if dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True else None + host_ip = setting_connection(dut, env_name) + + dut.expect('Starting OTA example task', timeout=30) + print(f'writing to device: https://{host_ip}:8000/simple_ota.bin') + dut.write(f'https://{host_ip}:8000/simple_ota.bin') + dut.expect('OTA Succeed, Rebooting...', timeout=60) + # after reboot + dut.expect(f'Loaded app from partition at offset {OTA_0_ADDRESS}', timeout=30) + dut.expect('Flash encryption mode is DEVELOPMENT', timeout=10) + dut.expect('OTA example app_main start', timeout=10) + finally: + thread1.terminate() + + +@pytest.mark.esp32 +@pytest.mark.ethernet_ota +@pytest.mark.parametrize('config', ['on_update_no_sb_ecdsa',], indirect=True) +def test_examples_protocol_simple_ota_example_with_verify_app_signature_on_update_no_secure_boot_ecdsa(dut: Dut) -> None: + """ + steps: | + 1. join AP/Ethernet + 2. Fetch OTA image over HTTPS + 3. Reboot with the new OTA image + """ + sha256_bootloader, sha256_app = calc_all_sha256(dut) + # Start server + thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', 8000)) + thread1.daemon = True + thread1.start() + try: + # start test + dut.expect(f'Loaded app from partition at offset {OTA_0_ADDRESS}', timeout=30) + check_sha256(sha256_bootloader, str(dut.expect(r'SHA-256 for bootloader:\s+([a-f0-9]){64}')[0])) + check_sha256(sha256_app, str(dut.expect(r'SHA-256 for current firmware:\s+([a-f0-9]){64}')[0])) + + host_ip = setting_connection(dut) + + dut.expect('Starting OTA example task', timeout=30) + print(f'writing to device: https://{host_ip}:8000/simple_ota.bin') + dut.write(f'https://{host_ip}:8000/simple_ota.bin') + dut.expect(f'Writing to partition at offset {OTA_1_ADDRESS}', timeout=20) + dut.expect('Verifying image signature...', timeout=60) + dut.expect('OTA Succeed, Rebooting...', timeout=60) + # after reboot + dut.expect(f'Loaded app from partition at offset {OTA_1_ADDRESS}', timeout=20) + dut.expect('OTA example app_main start', timeout=10) + finally: + thread1.terminate() + + +@pytest.mark.esp32 +@pytest.mark.ethernet_ota +@pytest.mark.parametrize('config', ['on_update_no_sb_rsa',], indirect=True) +def test_examples_protocol_simple_ota_example_with_verify_app_signature_on_update_no_secure_boot_rsa(dut: Dut) -> None: + """ + steps: | + 1. join AP/Ethernet + 2. Fetch OTA image over HTTPS + 3. Reboot with the new OTA image + """ + sha256_bootloader, sha256_app = calc_all_sha256(dut) + # Start server + thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', 8000)) + thread1.daemon = True + thread1.start() + try: + # start test + dut.expect(f'Loaded app from partition at offset {OTA_0_ADDRESS}', timeout=30) + check_sha256(sha256_bootloader, str(dut.expect(r'SHA-256 for bootloader:\s+([a-f0-9]){64}')[0])) + check_sha256(sha256_app, str(dut.expect(r'SHA-256 for current firmware:\s+([a-f0-9]){64}')[0])) + + host_ip = setting_connection(dut) + + dut.expect('Starting OTA example task', timeout=30) + print(f'writing to device: https://{host_ip}:8000/simple_ota.bin') + dut.write(f'https://{host_ip}:8000/simple_ota.bin') + dut.expect(f'Writing to partition at offset {OTA_1_ADDRESS}', timeout=20) + dut.expect('Verifying image signature...', timeout=60) + dut.expect('#0 app key digest == #0 trusted key digest', timeout=10) + dut.expect('Verifying with RSA-PSS...', timeout=10) + dut.expect('Signature verified successfully!', timeout=10) + dut.expect('OTA Succeed, Rebooting...', timeout=60) + # after reboot + dut.expect(f'Loaded app from partition at offset {OTA_1_ADDRESS}', timeout=20) + dut.expect('OTA example app_main start', timeout=10) + finally: + thread1.terminate() + + +@pytest.mark.esp32 +@pytest.mark.ethernet_ota +@pytest.mark.parametrize('config', ['tls1_3',], indirect=True) +def test_examples_protocol_simple_ota_example_tls1_3(dut: Dut) -> None: + """ + steps: | + 1. join AP/Ethernet + 2. Fetch OTA image over HTTPS + 3. Reboot with the new OTA image + """ + sha256_bootloader, sha256_app = calc_all_sha256(dut) + # Start server + tls1_3_server = start_tls1_3_server(dut.app.binary_path, 8000) + try: + # start test + dut.expect(f'Loaded app from partition at offset {OTA_0_ADDRESS}', timeout=30) + check_sha256(sha256_bootloader, str(dut.expect(r'SHA-256 for bootloader:\s+([a-f0-9]){64}')[0])) + check_sha256(sha256_app, str(dut.expect(r'SHA-256 for current firmware:\s+([a-f0-9]){64}')[0])) + # Parse IP address of STA + env_name = 'wifi_high_traffic' if dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True else None + host_ip = setting_connection(dut, env_name) + + dut.expect('Starting OTA example task', timeout=30) + print(f'writing to device: https://{host_ip}:8000/simple_ota.bin') + dut.write(f'https://{host_ip}:8000/simple_ota.bin') + dut.expect('OTA Succeed, Rebooting...', timeout=120) + # after reboot + dut.expect(f'Loaded app from partition at offset {OTA_1_ADDRESS}', timeout=30) + dut.expect('OTA example app_main start', timeout=10) + finally: + tls1_3_server.kill() + + +if __name__ == '__main__': + if sys.argv[2:]: # if two or more arguments provided: + # Usage: pytest_simple_ota.py [cert_dir] + this_dir = os.path.dirname(os.path.realpath(__file__)) + bin_dir = os.path.join(this_dir, sys.argv[1]) + port = int(sys.argv[2]) + cert_dir = bin_dir if not sys.argv[3:] else os.path.join(this_dir, sys.argv[3]) # optional argument + print(f'Starting HTTPS server at "https://0.0.0.0:{port}"') + start_https_server(bin_dir, '', port, + server_file=os.path.join(cert_dir, 'ca_cert.pem'), + key_file=os.path.join(cert_dir, 'ca_key.pem')) + diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..ceab6e1 --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +0.1 \ No newline at end of file