From 4572252d1a18a5e835df7373eaa5247da5a3d3b4 Mon Sep 17 00:00:00 2001 From: Gillian Minnehan Date: Wed, 16 Oct 2024 11:55:03 -0400 Subject: [PATCH] chore: update app to latest esp32 app --- CMakeLists.txt | 18 - README.md | 5 +- main/Kconfig.projbuild | 5 + main/app_memfault_transport.h | 2 +- main/app_memfault_transport_http.c | 2 +- main/app_memfault_transport_mqtt.c | 2 +- main/button.c | 16 +- main/button.h | 2 +- main/cmd_app.c | 31 +- main/cmd_wifi.c | 2 +- main/cmd_wifi_legacy.c | 8 +- main/config/memfault_platform_config.h | 2 +- main/console_example_main.c | 437 ------------------ main/led.c | 2 +- main/led.h | 2 +- main/main.c | 43 +- .../memfault_metrics_heartbeat_config.def | 12 - main/memfault/memfault_platform_config.h | 12 - main/memfault/memfault_platform_device_info.c | 62 --- .../memfault_task_watchdog_config.def | 3 - .../memfault_trace_reason_user_config.def | 3 - main/ota_session_metrics.c | 13 +- main/ota_session_metrics.h | 2 +- main/settings.c | 2 +- main/settings.h | 23 +- sdkconfig.defaults | 5 + sdkconfig.heaptrace | 4 + sdkconfig.mqtt | 1 + third-party/memfault-firmware-sdk | 2 +- 29 files changed, 76 insertions(+), 647 deletions(-) delete mode 100644 main/console_example_main.c delete mode 100644 main/memfault/memfault_metrics_heartbeat_config.def delete mode 100644 main/memfault/memfault_platform_config.h delete mode 100644 main/memfault/memfault_platform_device_info.c delete mode 100644 main/memfault/memfault_task_watchdog_config.def delete mode 100644 main/memfault/memfault_trace_reason_user_config.def create mode 100644 sdkconfig.heaptrace diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c38cab..ae16623 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,21 +63,3 @@ if (INVALID_PARTITION_TABLE) If this error occurs repeatedly run `idf.py fullclean && rm sdkconfig`" ) endif() - -if (CONFIG_MEMFAULT) - # Add the Memfault Build ID so each build can have a unique version. - set(IDF_PROJECT_EXECUTABLE ${PROJECT_NAME}.elf) - add_custom_command(TARGET ${IDF_PROJECT_EXECUTABLE} - POST_BUILD - # Compute and insert the build id - COMMAND python ${memfault_firmware_sdk_dir}/scripts/fw_build_id.py ${IDF_PROJECT_EXECUTABLE} - # Save a copy of the ELF that includes the 'log_fmt' section - BYPRODUCTS ${IDF_PROJECT_EXECUTABLE}.memfault_log_fmt - # Compress debug sections; this reduces the elf file size from ~10MB -> ~4.8MB - COMMAND ${CMAKE_OBJCOPY} --compress-debug-sections ${IDF_PROJECT_EXECUTABLE} - COMMAND ${CMAKE_COMMAND} -E copy ${IDF_PROJECT_EXECUTABLE} ${IDF_PROJECT_EXECUTABLE}.memfault_log_fmt - COMMAND ${CMAKE_COMMAND} -E echo "*** NOTE: the symbol file to upload to app.memfault.com is ${IDF_PROJECT_EXECUTABLE}.memfault_log_fmt ***" - # Remove the 'log_fmt' compact log section, which confuses elf2image - COMMAND ${CMAKE_OBJCOPY} --remove-section log_fmt ${IDF_PROJECT_EXECUTABLE} - ) -endif() # NOT CONFIG_MEMFAULT_DISABLE diff --git a/README.md b/README.md index 766cd84..c6884eb 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ You can either follow the steps outlined here or use your own MQTT setup. ### Broker Setup -1. Install a local installtion of Cedalo by following the [installation guide](https://docs.cedalo.com/management-center/installation/) +1. Install a local installation of Cedalo by following the [installation guide](https://docs.cedalo.com/management-center/installation/) 2. Login to Cedalo at 3. Create a new client login for the device - Ensure device client has the "client" role to allow publishing data @@ -21,7 +21,8 @@ You can either follow the steps outlined here or use your own MQTT setup. ### Service Setup -1. Modify the script found in Docs->Best Practices->MQTT with Memfault with the the following: +1. Modify the script found in [Docs->Best Practices->MQTT](https://docs.memfault.com/docs/best-practices/mqtt-with-memfault#service-examples) + with Memfault with the the following: 1. The service client login information previously created 2. Connection info for your local broker 3. Map of Memfault projects to project keys diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 7d8fd87..ee54523 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -24,6 +24,11 @@ config MEMFAULT_APP_WIFI_AUTOJOIN help Automatically join if credentials are configured. +config MEMFAULT_APP_HEAP_TRACING + bool "Print allocation tracing information at runtime" + default n + depends on HEAP_USE_HOOKS + choice APP_MEMFAULT_TRANSPORT prompt "Protocol to send chunks over" default APP_MEMFAULT_TRANSPORT_HTTP diff --git a/main/app_memfault_transport.h b/main/app_memfault_transport.h index 8e25e45..99c6c6d 100644 --- a/main/app_memfault_transport.h +++ b/main/app_memfault_transport.h @@ -1,7 +1,7 @@ //! @file //! //! Copyright (c) Memfault, Inc. -//! See License.txt for details +//! See LICENSE for details #pragma once diff --git a/main/app_memfault_transport_http.c b/main/app_memfault_transport_http.c index 46bf79b..140b297 100644 --- a/main/app_memfault_transport_http.c +++ b/main/app_memfault_transport_http.c @@ -1,7 +1,7 @@ //! @file //! //! Copyright (c) Memfault, Inc. -//! See License.txt for details +//! See LICENSE for details #include "app_memfault_transport.h" #include "memfault/esp_port/http_client.h" diff --git a/main/app_memfault_transport_mqtt.c b/main/app_memfault_transport_mqtt.c index 1fe81e7..555f941 100644 --- a/main/app_memfault_transport_mqtt.c +++ b/main/app_memfault_transport_mqtt.c @@ -1,7 +1,7 @@ //! @file //! //! Copyright (c) Memfault, Inc. -//! See License.txt for details +//! See LICENSE for details #include #include diff --git a/main/button.c b/main/button.c index ea1cf2c..5a8a11f 100644 --- a/main/button.c +++ b/main/button.c @@ -1,7 +1,7 @@ //! @file //! //! Copyright (c) Memfault, Inc. -//! See License.txt for details +//! See LICENSE for details //! //! Button setup and handling @@ -11,15 +11,21 @@ #include "esp_attr.h" #include "esp_log.h" #include "esp_system.h" +#include "freertos/FreeRTOS.h" static const char *TAG = "button"; +static portMUX_TYPE s_button_spinlock = portMUX_INITIALIZER_UNLOCKED; static void IRAM_ATTR prv_gpio_isr_handler(void *arg) { - uint32_t gpio_num = (uint32_t)arg; + // Make volatile to prevent compiler optimization in while loop + volatile uint32_t gpio_num = (uint32_t)arg; - // dereference a null point to trigger a crash - volatile uint32_t *ptr = NULL; - *ptr = gpio_num; + // Grab a spinlock to ensure this ISR does not get interrupted + portENTER_CRITICAL_ISR(&s_button_spinlock); + // Hang the interrupt to trigger a fault from the interrupt watchdog + while (true) { + gpio_num++; + } } // The flex glitch filter is only available on 5.1. Skip it for earlier SDKs. diff --git a/main/button.h b/main/button.h index cea9901..6faaa47 100644 --- a/main/button.h +++ b/main/button.h @@ -1,7 +1,7 @@ //! @file //! //! Copyright (c) Memfault, Inc. -//! See License.txt for details +//! See LICENSE for details //! //! Button setup and handling diff --git a/main/cmd_app.c b/main/cmd_app.c index 98df0d4..a89dee7 100644 --- a/main/cmd_app.c +++ b/main/cmd_app.c @@ -1,7 +1,7 @@ //! @file //! //! Copyright (c) Memfault, Inc. -//! See License.txt for details +//! See LICENSE for details //! Miscellaneous commands specific to this example app //! @@ -31,17 +31,16 @@ static int test_task_watchdog(int argc, char **argv) { } #endif -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0) - #if defined(CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK) || \ - !defined(CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE) - #define OVERFLOW_TASK_STACK_SIZE 4096 +#if defined(CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK) || \ + !defined(CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE) + #define OVERFLOW_TASK_STACK_SIZE 4096 static StaticTask_t s_overflow_task_tcb; static StackType_t s_overflow_task_stack[OVERFLOW_TASK_STACK_SIZE]; static TaskHandle_t s_overflow_task_handle = NULL; static void prv_trigger_stack_overflow(void) { - #if defined(CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL) + #if defined(CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL) // General idea is to allocate a bunch of memory on the stack but not too much // to hose FreeRTOS Then yield and the FreeRTOS stack overflow check (on task // switch) should kick in due to stack pointer limits @@ -60,11 +59,11 @@ static void prv_trigger_stack_overflow(void) { stack_array[i] = i; taskYIELD(); } - #else + #else // The canary checks only look at the last bytes (lowest addresses) of the // stack Execute a write over the last 32 bytes to trigger the watchpoint memset(s_overflow_task_stack, 0, 32); - #endif // defined(CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTR) + #endif // defined(CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTR) } /** @@ -107,9 +106,8 @@ static void prv_init_stack_overflow_test(void) { }; ESP_ERROR_CHECK(esp_console_cmd_register(&test_stack_overflow_cmd)); } - #endif // defined(CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK) || - // !defined(CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE) -#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0) +#endif // defined(CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK) || + // !defined(CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE) #if defined(CONFIG_HEAP_TASK_TRACKING) // Print out per-task heap allocations. This is lifted from the example here: @@ -173,12 +171,9 @@ void register_app(void) { ESP_ERROR_CHECK(esp_console_cmd_register(&heap_task_stats_cmd)); #endif -// Only support the stack overflow test on esp-idf >= 4.3.0 -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0) - #if defined(CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK) || \ - !defined(CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE) +#if defined(CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK) || \ + !defined(CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE) prv_init_stack_overflow_test(); - #endif // defined(CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK) || - // !defined(CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE) -#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0) +#endif // defined(CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK) || + // !defined(CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE) } diff --git a/main/cmd_wifi.c b/main/cmd_wifi.c index 82e4248..7dfe56a 100644 --- a/main/cmd_wifi.c +++ b/main/cmd_wifi.c @@ -1,7 +1,7 @@ //! @file //! //! Copyright (c) Memfault, Inc. -//! See License.txt for details +//! See LICENSE for details //! //! Wifi-specific commands for the ESP32 console. diff --git a/main/cmd_wifi_legacy.c b/main/cmd_wifi_legacy.c index cce79e0..020cab1 100644 --- a/main/cmd_wifi_legacy.c +++ b/main/cmd_wifi_legacy.c @@ -1,7 +1,7 @@ //! @file //! //! Copyright (c) Memfault, Inc. -//! See License.txt for details +//! See LICENSE for details //! //! Version of cmd_wifi.c that uses the legacy wifi API, for ESP-IDF v3. @@ -34,12 +34,6 @@ static char s_wifi_pass[WIFI_CREDS_MAX_SIZE]; static EventGroupHandle_t wifi_event_group; const int CONNECTED_BIT = BIT0; -// this type changed in ESP-IDF v4.0, to 'nvs_handle_t'; add a backwards-compat -// typedef -#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 0, 0) -typedef nvs_handle nvs_handle_t; -#endif - int wifi_get_project_key(char *project_key, size_t project_key_len) { // Configurable project key not supported, project key must be compiled in via // CONFIG_MEMFAULT_PROJECT_KEY diff --git a/main/config/memfault_platform_config.h b/main/config/memfault_platform_config.h index e1f8f73..14a1010 100644 --- a/main/config/memfault_platform_config.h +++ b/main/config/memfault_platform_config.h @@ -3,7 +3,7 @@ //! @file //! //! Copyright (c) Memfault, Inc. -//! See License.txt for details +//! See LICENSE for details //! //! Platform overrides for the default configuration settings in the memfault-firmware-sdk. //! Default configuration settings can be found in "memfault/config.h" diff --git a/main/console_example_main.c b/main/console_example_main.c deleted file mode 100644 index ca5b91b..0000000 --- a/main/console_example_main.c +++ /dev/null @@ -1,437 +0,0 @@ -/* Console example - - This example code is in the Public Domain (or CC0 licensed, at your option.) - - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ - -#include -#include -#include - -#include "app_memfault_transport.h" -#include "argtable3/argtable3.h" -#include "cmd_decl.h" -#include "driver/uart.h" -#include "esp_console.h" -#include "esp_log.h" -#include "esp_system.h" -#include "esp_task.h" -#include "esp_vfs_dev.h" -#include "esp_vfs_fat.h" -#include "freertos/FreeRTOS.h" -#include "freertos/semphr.h" -#include "freertos/timers.h" -#include "led.h" -#include "linenoise/linenoise.h" -#include "memfault/components.h" -#include "memfault/esp_port/cli.h" -#include "memfault/esp_port/core.h" -#include "memfault/esp_port/http_client.h" -#include "memfault/esp_port/version.h" -#include "nvs.h" -#include "nvs_flash.h" -#include "settings.h" - -static const char *TAG = "example"; - -/* Console command history can be stored to and loaded from a file. - * The easiest way to do this is to use FATFS filesystem on top of - * wear_levelling library. - */ -#if CONFIG_STORE_HISTORY - - #define MOUNT_PATH "/data" - #define HISTORY_PATH MOUNT_PATH "/history.txt" - -static void initialize_filesystem() { - static wl_handle_t wl_handle; - const esp_vfs_fat_mount_config_t mount_config = {.max_files = 4, .format_if_mount_failed = true}; - esp_err_t err = - #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) - esp_vfs_fat_spiflash_mount_rw_wl - #else - esp_vfs_fat_spiflash_mount - #endif - (MOUNT_PATH, "storage", &mount_config, &wl_handle); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err)); - return; - } -} -#endif // CONFIG_STORE_HISTORY - -static void initialize_nvs() { - esp_err_t err = nvs_flash_init(); - if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { - ESP_ERROR_CHECK(nvs_flash_erase()); - err = nvs_flash_init(); - } - ESP_ERROR_CHECK(err); -} - -// Name change at version 4.x -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) - #define CONFIG_CONSOLE_UART_NUM CONFIG_ESP_CONSOLE_UART_NUM -#endif - -static void initialize_console() { - /* Disable buffering on stdin and stdout */ - setvbuf(stdin, NULL, _IONBF, 0); - setvbuf(stdout, NULL, _IONBF, 0); - -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0) - /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */ - esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR); - /* Move the caret to the beginning of the next line on '\n' */ - esp_vfs_dev_uart_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF); -#else - /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */ - esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR); - /* Move the caret to the beginning of the next line on '\n' */ - esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF); -#endif - - /* Install UART driver for interrupt-driven reads and writes */ - ESP_ERROR_CHECK(uart_driver_install(CONFIG_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0)); - - /* Tell VFS to use UART driver */ - esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM); - - /* Initialize the console */ - esp_console_config_t console_config = { - .max_cmdline_args = 8, - .max_cmdline_length = 256, -#if CONFIG_LOG_COLORS - .hint_color = atoi(LOG_COLOR_CYAN) -#endif - }; - ESP_ERROR_CHECK(esp_console_init(&console_config)); - - /* Configure linenoise line completion library */ - /* Enable multiline editing. If not set, long commands will scroll within - * single line. - */ - linenoiseSetMultiLine(1); - - /* Tell linenoise where to get command completions and hints */ - linenoiseSetCompletionCallback(&esp_console_get_completion); - linenoiseSetHintsCallback((linenoiseHintsCallback *)&esp_console_get_hint); - - /* Set command history size */ - linenoiseHistorySetMaxLen(100); - -#if CONFIG_STORE_HISTORY - /* Load command history from filesystem */ - linenoiseHistoryLoad(HISTORY_PATH); -#endif -} - -// Put this buffer in the IRAM region. Accesses on the instruction bus must be word-aligned -// while data accesses don't have to be. See "1.3.1 Address Mapping" in the ESP32 technical -// reference manual. -MEMFAULT_ALIGNED(4) static IRAM_ATTR uint8_t s_my_buf[10]; -void *g_unaligned_buffer; - -#if CONFIG_MEMFAULT_APP_OTA - -static bool prv_handle_ota_upload_available(void *user_ctx) { - // set blue when performing update - led_set_color(kLedColor_Blue); - - MEMFAULT_LOG_INFO("Starting OTA download ..."); - return true; -} - -static bool prv_handle_ota_download_complete(void *user_ctx) { - MEMFAULT_LOG_INFO("OTA Update Complete, Rebooting System"); - - // The pc & lr which result in the reboot can always be *optionally* recorded - void *pc; - MEMFAULT_GET_PC(pc); - void *lr; - MEMFAULT_GET_LR(lr); - sMfltRebootTrackingRegInfo reg_info = { - .pc = (uint32_t)pc, - .lr = (uint32_t)lr, - }; - // Note: "reg_info" may be NULL if no register information collection is desired - memfault_reboot_tracking_mark_reset_imminent(kMfltRebootReason_FirmwareUpdate, ®_info); - - esp_restart(); - return true; -} - -static void prv_memfault_ota(void) { - if (!memfault_esp_port_wifi_connected()) { - return; - } - - sMemfaultOtaUpdateHandler handler = { - .user_ctx = NULL, - .handle_update_available = prv_handle_ota_upload_available, - .handle_download_complete = prv_handle_ota_download_complete, - }; - - MEMFAULT_LOG_INFO("Checking for OTA Update"); - - int rv = memfault_esp_port_ota_update(&handler); - if (rv == 0) { - MEMFAULT_LOG_INFO("Up to date!"); - led_set_color(kLedColor_Green); - } else if (rv == 1) { - MEMFAULT_LOG_INFO("Update available!"); - } else if (rv < 0) { - MEMFAULT_LOG_ERROR("OTA update failed, rv=%d", rv); - - // record a Trace Event when this happens, and freeze the log buffer to be - // uploaded for diagnosis - MEMFAULT_TRACE_EVENT_WITH_LOG(ota_install_failure, "error code=%d", rv); - memfault_log_trigger_collection(); - - led_set_color(kLedColor_Red); - } -} -#else -static void prv_memfault_ota(void) {} -#endif // CONFIG_MEMFAULT_APP_OTA - -#if CONFIG_MEMFAULT_APP_WIFI_AUTOJOIN -void memfault_esp_port_wifi_autojoin(void) { - if (memfault_esp_port_wifi_connected()) { - return; - } - - char *ssid, *pass; - wifi_load_creds(&ssid, &pass); - if ((ssid == NULL) || (pass == NULL) || (strnlen(ssid, 64) == 0) || (strnlen(pass, 64) == 0)) { - MEMFAULT_LOG_DEBUG("No WiFi credentials found"); - return; - } - MEMFAULT_LOG_DEBUG("Starting WiFi Autojoin ..."); - bool result = wifi_join(ssid, pass); - if (!result) { - MEMFAULT_LOG_DEBUG("Failed to join WiFi network"); - } -} - -#endif // CONFIG_MEMFAULT_APP_WIFI_AUTOJOIN - -// Periodically post any Memfault data that has not yet been posted. -static void prv_poster_task(void *args) { - const uint32_t interval_sec = 60; - const TickType_t delay_ms = (1000 * interval_sec) / portTICK_PERIOD_MS; - const TickType_t ota_check_interval = pdMS_TO_TICKS(60 * 60 * 1000); - TickType_t ota_last_check_time = xTaskGetTickCount() - ota_check_interval; - - app_memfault_transport_init(); - - MEMFAULT_LOG_INFO("Data poster task up and running every %" PRIu32 "s.", interval_sec); - - while (true) { - // count the number of times this task has run - memfault_metrics_heartbeat_add(MEMFAULT_METRICS_KEY(PosterTaskNumSchedules), 1); - // attempt to autojoin wifi, if configured - memfault_esp_port_wifi_autojoin(); - - // if connected, post any memfault data - if (memfault_esp_port_wifi_connected()) { - MEMFAULT_LOG_DEBUG("Checking for memfault data to send"); - int err = app_memfault_transport_send_chunks(); - // if the check-in succeeded, set green, otherwise clear. - // gives a quick eyeball check that the app is alive and well - led_set_color((err == 0) ? kLedColor_Green : kLedColor_Red); - - // Check for OTA hourly - if ((xTaskGetTickCount() - ota_last_check_time) >= ota_check_interval) { - prv_memfault_ota(); - ota_last_check_time = xTaskGetTickCount(); - } - } - - // sleep - vTaskDelay(delay_ms); - } -} - -// Example showing how to use the task watchdog -#if MEMFAULT_TASK_WATCHDOG_ENABLE - -SemaphoreHandle_t g_example_task_lock; - -static void prv_example_task(void *args) { - (void)args; - - // set up the semaphore used to programmatically make this task stuck - #if MEMFAULT_FREERTOS_PORT_USE_STATIC_ALLOCATION != 0 - static StaticSemaphore_t s_memfault_lock_context; - g_example_task_lock = xSemaphoreCreateRecursiveMutexStatic(&s_memfault_lock_context); - #else - g_example_task_lock = xSemaphoreCreateRecursiveMutex(); - #endif - - MEMFAULT_ASSERT(g_example_task_lock != NULL); - - // this task runs every 250ms and gets/puts a semaphore. if the semaphore is - // claimed, the task watchdog will eventually trip and mark this task as stuck - const uint32_t interval_ms = 250; - - MEMFAULT_LOG_INFO("Task watchdog example task running every %" PRIu32 "ms.", interval_ms); - while (true) { - // enable the task watchdog - MEMFAULT_TASK_WATCHDOG_START(example_task); - - // get the semaphore. if we can't get it, the task watchdog should - // eventually trip - xSemaphoreTakeRecursive(g_example_task_lock, portMAX_DELAY); - xSemaphoreGiveRecursive(g_example_task_lock); - - // disable the task watchdog now that this task is done in this run - MEMFAULT_TASK_WATCHDOG_STOP(example_task); - - vTaskDelay(interval_ms / portTICK_PERIOD_MS); - } -} - -static void prv_task_watchdog_timer_callback(MEMFAULT_UNUSED TimerHandle_t handle) { - memfault_task_watchdog_check_all(); -} - -static void prv_initialize_task_watchdog(void) { - memfault_task_watchdog_init(); - - // create a timer that runs the watchdog check once a second - const char *const pcTimerName = "TaskWatchdogTimer"; - const TickType_t xTimerPeriodInTicks = pdMS_TO_TICKS(1000); - - TimerHandle_t timer; - - #if MEMFAULT_FREERTOS_PORT_USE_STATIC_ALLOCATION != 0 - static StaticTimer_t s_task_watchdog_timer_context; - timer = xTimerCreateStatic(pcTimerName, xTimerPeriodInTicks, pdTRUE, NULL, - prv_task_watchdog_timer_callback, &s_task_watchdog_timer_context); - #else - timer = - xTimerCreate(pcTimerName, xTimerPeriodInTicks, pdTRUE, NULL, prv_task_watchdog_timer_callback); - #endif - - MEMFAULT_ASSERT(timer != 0); - - xTimerStart(timer, 0); - - // create and start the example task - const portBASE_TYPE res = xTaskCreate(prv_example_task, "example_task", ESP_TASK_MAIN_STACK, NULL, - ESP_TASK_MAIN_PRIO, NULL); - MEMFAULT_ASSERT(res == pdTRUE); -} -#else -static void prv_initialize_task_watchdog(void) { - // task watchdog disabled, do nothing -} -#endif - -// This task started by cpu_start.c::start_cpu0_default(). -void app_main() { -#if !CONFIG_MEMFAULT_AUTOMATIC_INIT - memfault_boot(); -#endif - memfault_device_info_dump(); - - g_unaligned_buffer = &s_my_buf[1]; - - initialize_nvs(); - -#if CONFIG_STORE_HISTORY - initialize_filesystem(); -#endif - - initialize_console(); - - led_init(); - - prv_initialize_task_watchdog(); - - // We need another task to post data since we block waiting for user - // input in this task. - const portBASE_TYPE res = - xTaskCreate(prv_poster_task, "poster", ESP_TASK_MAIN_STACK, NULL, ESP_TASK_MAIN_PRIO, NULL); - MEMFAULT_ASSERT(res == pdTRUE); - - /* Register commands */ - esp_console_register_help_command(); - register_system(); - register_wifi(); - register_app(); - settings_register_shell_commands(); - - // Attempt to load project key from nvs - static char project_key[MEMFAULT_PROJECT_KEY_LEN + 1] = {0}; - int err = wifi_get_project_key(project_key, sizeof(project_key)); - if (err == 0) { - project_key[sizeof(project_key) - 1] = '\0'; - g_mflt_http_client_config.api_key = project_key; - } - -#if MEMFAULT_COMPACT_LOG_ENABLE - MEMFAULT_COMPACT_LOG_SAVE(kMemfaultPlatformLogLevel_Info, "This is a compact log example"); -#endif - - /* Prompt to be printed before each line. - * This can be customized, made dynamic, etc. - */ - const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR; - - const char banner[] = "\n\n" MEMFAULT_BANNER_COLORIZED; - - puts(banner); - - /* Figure out if the terminal supports escape sequences */ - int probe_status = linenoiseProbe(); - if (probe_status) { /* zero indicates success */ - printf("\n" - "Your terminal application does not support escape sequences.\n" - "Line editing and history features are disabled.\n" - "On Windows, try using Putty instead.\n"); - linenoiseSetDumbMode(1); -#if CONFIG_LOG_COLORS - /* Since the terminal doesn't support escape sequences, - * don't use color codes in the prompt. - */ - prompt = "esp32> "; -#endif // CONFIG_LOG_COLORS - } - - /* Main loop */ - while (true) { - /* Get a line using linenoise (blocking call). - * The line is returned when ENTER is pressed. - */ - char *line = linenoise(prompt); - if (line == NULL) { /* Ignore empty lines */ - continue; - } - /* Add the command to the history */ - linenoiseHistoryAdd(line); -#if CONFIG_STORE_HISTORY - /* Save command history to filesystem */ - linenoiseHistorySave(HISTORY_PATH); -#endif - - /* Try to run the command */ - int ret; - esp_err_t err = esp_console_run(line, &ret); - if (err == ESP_ERR_NOT_FOUND) { - printf("Unrecognized command\n"); - } else if (err == ESP_ERR_INVALID_ARG) { - // command was empty - } else if (err == ESP_OK && ret != ESP_OK) { - printf("Command returned non-zero error code: 0x%x (%s)\n", ret, esp_err_to_name(ret)); - } else if (err != ESP_OK) { - printf("Internal error: %s\n", esp_err_to_name(err)); - } - /* linenoise allocates line buffer on the heap, so need to free it */ - linenoiseFree(line); - } -} diff --git a/main/led.c b/main/led.c index 2f03905..500ebb3 100644 --- a/main/led.c +++ b/main/led.c @@ -1,7 +1,7 @@ //! @file //! //! Copyright (c) Memfault, Inc. -//! See License.txt for details +//! See LICENSE for details //! //! Module for controlling the RGB LED. Implementation varies depending on which //! target board; the ESP32-WROVER has a 3-gpio LED, while the ESP32-S3-DevKitC diff --git a/main/led.h b/main/led.h index 8951097..fa2050b 100644 --- a/main/led.h +++ b/main/led.h @@ -1,7 +1,7 @@ //! @file //! //! Copyright (c) Memfault, Inc. -//! See License.txt for details +//! See LICENSE for details //! //! LED control module header. diff --git a/main/main.c b/main/main.c index 0c2f1ac..83878df 100644 --- a/main/main.c +++ b/main/main.c @@ -36,16 +36,16 @@ #endif #if defined(CONFIG_MEMFAULT) + #include "esp_idf_version.h" #include "memfault/components.h" #include "memfault/esp_port/cli.h" #include "memfault/esp_port/core.h" #include "memfault/esp_port/http_client.h" - #include "memfault/esp_port/version.h" #include "settings.h" #endif // Conditionally enable the logging tag variable only when it's used -#if defined(CONFIG_STORE_HISTORY) || defined(CONFIG_HEAP_USE_HOOKS) +#if defined(CONFIG_STORE_HISTORY) || defined(CONFIG_MEMFAULT_APP_HEAP_TRACING) static const char *TAG = "main"; #endif @@ -85,42 +85,32 @@ static void initialize_nvs() { ESP_ERROR_CHECK(err); } -// Name change at version 4.x -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) - #define CONFIG_CONSOLE_UART_NUM CONFIG_ESP_CONSOLE_UART_NUM -#endif - static void initialize_console() { /* Disable buffering on stdin and stdout */ setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); - // These APIs vary depending on ESP-IDF version. +// These APIs vary depending on ESP-IDF version. #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */ uart_vfs_dev_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR); /* Move the caret to the beginning of the next line on '\n' */ uart_vfs_dev_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF); -#elif ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0) +#else // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */ esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR); /* Move the caret to the beginning of the next line on '\n' */ esp_vfs_dev_uart_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF); -#else - /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */ - esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR); - /* Move the caret to the beginning of the next line on '\n' */ - esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF); -#endif +#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) /* Install UART driver for interrupt-driven reads and writes */ - ESP_ERROR_CHECK(uart_driver_install(CONFIG_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0)); + ESP_ERROR_CHECK(uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0)); - /* Tell VFS to use UART driver */ +/* Tell VFS to use UART driver */ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0) - uart_vfs_dev_use_driver(CONFIG_CONSOLE_UART_NUM); + uart_vfs_dev_use_driver(CONFIG_ESP_CONSOLE_UART_NUM); #else - esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM); + esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM); #endif /* Initialize the console */ @@ -254,7 +244,7 @@ void memfault_esp_port_wifi_autojoin(void) { #endif // CONFIG_MEMFAULT_APP_WIFI_AUTOJOIN -// // Periodically post any Memfault data that has not yet been posted. +// Periodically post any Memfault data that has not yet been posted. static void prv_ota_task(void *args) { const TickType_t ota_check_interval = pdMS_TO_TICKS(60 * 60 * 1000); @@ -263,7 +253,7 @@ static void prv_ota_task(void *args) { while (true) { // count the number of times this task has run MEMFAULT_METRIC_ADD(PosterTaskNumSchedules, 1); - // attempt to autojoin wifi, if configured + // attempt to autojoin wifi, if configured #if defined(CONFIG_MEMFAULT_APP_WIFI_AUTOJOIN) memfault_esp_port_wifi_autojoin(); #endif @@ -359,18 +349,18 @@ static void prv_initialize_task_watchdog(void) { #endif // defined(CONFIG_MEMFAULT) -#if defined(CONFIG_HEAP_USE_HOOKS) +#if defined(CONFIG_MEMFAULT_APP_HEAP_TRACING) // This callback is triggered when a heap allocation is made. It prints large // allocations for debugging heap usage from the serial log. void esp_heap_trace_alloc_hook(void *ptr, size_t size, uint32_t caps) { // In our app, there's a periodic 1696 byte alloc. Filter out anything that // size or smaller from this log, otherwise it's quite spammy if (size > 1696) { - ESP_LOGI("main", "Large alloc: %p, size: %d, caps: %lu", ptr, size, caps); + ESP_LOGI(TAG, "Large alloc: %p, size: %d, caps: %lu", ptr, size, caps); multi_heap_info_t heap_info = { 0 }; heap_caps_get_info(&heap_info, MALLOC_CAP_DEFAULT); - ESP_LOGI("main", "Total free bytes: %d", heap_info.total_free_bytes); + ESP_LOGI(TAG, "Total free bytes: %d", heap_info.total_free_bytes); } } #endif @@ -454,9 +444,7 @@ void app_main() { g_mflt_http_client_config.api_key = project_key; } - // Load chunks + device URLs from NVS too, only for esp_idf >=4 - #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) - // Need to persist for the lifetime of the program + // Load chunks + device URLs from NVS too. Need to persist for the lifetime of the program static char chunks_url[128] = { 0 }; static char device_url[128] = { 0 }; size_t chunks_url_len = sizeof(chunks_url); @@ -466,7 +454,6 @@ void app_main() { g_mflt_http_client_config.chunks_api.host = (chunks_url_len > 1) ? chunks_url : NULL; g_mflt_http_client_config.device_api.host = (device_url_len > 1) ? device_url : NULL; } - #endif #if MEMFAULT_COMPACT_LOG_ENABLE MEMFAULT_COMPACT_LOG_SAVE(kMemfaultPlatformLogLevel_Info, "This is a compact log example"); diff --git a/main/memfault/memfault_metrics_heartbeat_config.def b/main/memfault/memfault_metrics_heartbeat_config.def deleted file mode 100644 index bc0a105..0000000 --- a/main/memfault/memfault_metrics_heartbeat_config.def +++ /dev/null @@ -1,12 +0,0 @@ -#include "sdkconfig.h" - -// File for holding custom metrics: -// https://mflt.io/embedded-metrics -MEMFAULT_METRICS_KEY_DEFINE(PosterTaskNumSchedules, kMemfaultMetricType_Unsigned) - -#if defined(CONFIG_APP_MEMFAULT_TRANSPORT_MQTT) -MEMFAULT_METRICS_KEY_DEFINE(mqtt_publish_bytes, kMemfaultMetricType_Unsigned) -MEMFAULT_METRICS_KEY_DEFINE(mqtt_publish_count, kMemfaultMetricType_Unsigned) -MEMFAULT_METRICS_KEY_DEFINE(mqtt_conn_downtime, kMemfaultMetricType_Timer) -MEMFAULT_METRICS_KEY_DEFINE(mqtt_conn_uptime, kMemfaultMetricType_Timer) -#endif diff --git a/main/memfault/memfault_platform_config.h b/main/memfault/memfault_platform_config.h deleted file mode 100644 index 558782d..0000000 --- a/main/memfault/memfault_platform_config.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -//! @file -//! -//! Copyright (c) Memfault, Inc. -//! See License.txt for details -//! -//! Platform overrides for the default configuration settings in the memfault-firmware-sdk. -//! Default configuration settings can be found in "memfault/config.h" - -#define MEMFAULT_TASK_WATCHDOG_ENABLE 1 -#define MEMFAULT_COMPACT_LOG_ENABLE 1 diff --git a/main/memfault/memfault_platform_device_info.c b/main/memfault/memfault_platform_device_info.c deleted file mode 100644 index b63dbac..0000000 --- a/main/memfault/memfault_platform_device_info.c +++ /dev/null @@ -1,62 +0,0 @@ -//! @file -//! -//! Copyright (c) Memfault, Inc. -//! See License.txt for details -//! -//! @brief -//! Reference implementation of Memfault device info API platform dependencies for the ESP32 - -#include - -#include "memfault/components.h" -#include "memfault/esp_port/version.h" -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) - #include "esp_mac.h" -#endif - -#include - -#include "esp_system.h" -#include "memfault/components.h" - -#ifndef MEMFAULT_ESP32_SOFTWARE_TYPE - #define MEMFAULT_ESP32_SOFTWARE_TYPE "esp32-main" -#endif - -#ifndef MEMFAULT_ESP32_HW_REVISION - #define MEMFAULT_ESP32_HW_REVISION CONFIG_IDF_TARGET "-proto" -#endif - -static char s_device_serial[32]; - -// NOTE: Some versions of the esp-idf use locking when reading mac info -// so this isn't safe to call from an interrupt -static void prv_get_device_serial(char *buf, size_t buf_len) { - // Use the ESP32's MAC address as unique device id: - uint8_t mac[6]; - esp_read_mac(mac, ESP_MAC_WIFI_STA); - - size_t curr_idx = 0; - for (size_t i = 0; i < sizeof(mac); i++) { - size_t space_left = buf_len - curr_idx; - int bytes_written = snprintf(&buf[curr_idx], space_left, "%02X", (int)mac[i]); - if (bytes_written < space_left) { - curr_idx += bytes_written; - } else { // we are out of space, return what we got, it's NULL terminated - return; - } - } -} - -void memfault_platform_device_info_boot(void) { - prv_get_device_serial(s_device_serial, sizeof(s_device_serial)); -} - -void memfault_platform_get_device_info(struct MemfaultDeviceInfo *info) { - *info = (struct MemfaultDeviceInfo){ - .device_serial = s_device_serial, - .hardware_version = MEMFAULT_ESP32_HW_REVISION, - .software_version = CONFIG_MEMFAULT_ESP32_MAIN_FIRMWARE_VERSION, - .software_type = MEMFAULT_ESP32_SOFTWARE_TYPE, - }; -} diff --git a/main/memfault/memfault_task_watchdog_config.def b/main/memfault/memfault_task_watchdog_config.def deleted file mode 100644 index 6097d77..0000000 --- a/main/memfault/memfault_task_watchdog_config.def +++ /dev/null @@ -1,3 +0,0 @@ -//! @file - -MEMFAULT_TASK_WATCHDOG_CHANNEL_DEFINE(example_task) diff --git a/main/memfault/memfault_trace_reason_user_config.def b/main/memfault/memfault_trace_reason_user_config.def deleted file mode 100644 index 0106503..0000000 --- a/main/memfault/memfault_trace_reason_user_config.def +++ /dev/null @@ -1,3 +0,0 @@ -// File for holding custom error traces: -// https://mflt.io/error-tracing -MEMFAULT_TRACE_REASON_DEFINE(ota_install_failure) diff --git a/main/ota_session_metrics.c b/main/ota_session_metrics.c index 7bdd9fc..4db8310 100644 --- a/main/ota_session_metrics.c +++ b/main/ota_session_metrics.c @@ -1,7 +1,7 @@ //! @file //! //! Copyright (c) Memfault, Inc. -//! See License.txt for details +//! See LICENSE for details //! //! Implementation for Memfault OTA Session Metrics @@ -57,17 +57,6 @@ int __wrap_mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len) { return rv; } -// This API was added in ESP-IDF v4.3.6, v4.4.6, v5.0.4, and v5.1.1. Add a stub for versions -// < v4.3.6. For simplicity, projects with versions > v4.3.6 but less than the patch the API was -// added in for the corresponding minor version are not supported with this check. There will be a -// build error due to a missing definition for the API. -// https://github.com/espressif/esp32-wifi-lib/blob/release/v4.4/esp32/libnet80211.a -#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 3, 6) -esp_err_t esp_wifi_sta_get_rssi(int *rssi) { - return -1; -} -#endif - void ota_session_metrics_end(int ota_error_code) { // error code MEMFAULT_METRIC_SESSION_SET_SIGNED(ota_error_code, ota, ota_error_code); diff --git a/main/ota_session_metrics.h b/main/ota_session_metrics.h index 092e26a..eeaf20b 100644 --- a/main/ota_session_metrics.h +++ b/main/ota_session_metrics.h @@ -1,7 +1,7 @@ //! @file //! //! Copyright (c) Memfault, Inc. -//! See License.txt for details +//! See LICENSE for details //! //! API for Memfault OTA Session Metrics diff --git a/main/settings.c b/main/settings.c index ae7dd89..7941770 100644 --- a/main/settings.c +++ b/main/settings.c @@ -1,7 +1,7 @@ //! @file //! //! Copyright (c) Memfault, Inc. -//! See License.txt for details +//! See LICENSE for details //! //! Implement app settings helpers diff --git a/main/settings.h b/main/settings.h index b541d9e..d1c4b4b 100644 --- a/main/settings.h +++ b/main/settings.h @@ -1,7 +1,7 @@ //! @file //! //! Copyright (c) Memfault, Inc. -//! See License.txt for details +//! See LICENSE for details //! //! App settings helper functions. @@ -9,7 +9,7 @@ #include -#include "memfault/esp_port/version.h" +#include "esp_idf_version.h" enum settings_key { kSettingsWifiSsid, @@ -21,25 +21,14 @@ enum settings_key { kSettingsDeviceUrl, }; -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) - #if __GNUC__ >= 11 +#if __GNUC__ >= 11 __attribute__((access(write_only, 2))) - #endif +#endif int settings_get(enum settings_key key, void *value, size_t *len); - #if __GNUC__ >= 11 +#if __GNUC__ >= 11 __attribute__((access(read_only, 2, 3))) - #endif +#endif int settings_set(enum settings_key key, const void *value, size_t len); void settings_register_shell_commands(void); -#else // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) -// stub definitions that always fail -static inline int settings_get(enum settings_key key, void *value, size_t *len) { - return -1; -} -static inline int settings_set(enum settings_key key, const void *value, size_t len) { - return -1; -} -static inline void settings_register_shell_commands(void) { } -#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 99795df..5d87283 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -50,6 +50,11 @@ CONFIG_MEMFAULT_COMPACT_LOG_ENABLE=y # Enable periodic upload thread for posting Memfault data CONFIG_MEMFAULT_HTTP_PERIODIC_UPLOAD=y +# Upload logs. Not recommended for production. +CONFIG_MEMFAULT_HTTP_PERIODIC_UPLOAD_LOGS=y + +# Pretty-print reboot reason +CONFIG_MEMFAULT_ENABLE_REBOOT_DIAG_DUMP=y # Support older ESP32-C3 variants CONFIG_ESP32C3_REV_MIN_2=y diff --git a/sdkconfig.heaptrace b/sdkconfig.heaptrace new file mode 100644 index 0000000..8c2445b --- /dev/null +++ b/sdkconfig.heaptrace @@ -0,0 +1,4 @@ +# Heap tracing configs +CONFIG_HEAP_POISONING_LIGHT=y +CONFIG_HEAP_TASK_TRACKING=y +CONFIG_HEAP_USE_HOOKS=y diff --git a/sdkconfig.mqtt b/sdkconfig.mqtt index 938c2ff..119ea39 100644 --- a/sdkconfig.mqtt +++ b/sdkconfig.mqtt @@ -1,2 +1,3 @@ CONFIG_APP_MEMFAULT_TRANSPORT_MQTT=y +CONFIG_MEMFAULT_HTTP_PERIODIC_UPLOAD=n CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example_mqtt.csv" diff --git a/third-party/memfault-firmware-sdk b/third-party/memfault-firmware-sdk index 0fbb820..72f52c0 160000 --- a/third-party/memfault-firmware-sdk +++ b/third-party/memfault-firmware-sdk @@ -1 +1 @@ -Subproject commit 0fbb8209353722311a509730df9c1a044cfeeb61 +Subproject commit 72f52c045b551ae352052cc839f55a7d8be56499