#include #include #include #include "driver/gpio.h" #include "esp_chip_info.h" #include "esp_err.h" #include "esp_flash.h" #include "esp_log.h" #include "esp_system.h" #include "esp_timer.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" static const char *const kLogTag = "bringup"; static const gpio_num_t kCandidateLedGpio = GPIO_NUM_8; static const uint32_t kLedProbeCount = 10; static const uint32_t kLedProbeIntervalMs = 500; static const uint32_t kHealthIntervalMs = 30000; static const uint32_t kStartupAttachmentDelayMs = 10000; static const char *reset_reason_name(esp_reset_reason_t reason) { switch (reason) { case ESP_RST_UNKNOWN: return "unknown"; case ESP_RST_POWERON: return "power_on"; case ESP_RST_EXT: return "external"; case ESP_RST_SW: return "software"; case ESP_RST_PANIC: return "panic"; case ESP_RST_INT_WDT: return "interrupt_watchdog"; case ESP_RST_TASK_WDT: return "task_watchdog"; case ESP_RST_WDT: return "other_watchdog"; case ESP_RST_DEEPSLEEP: return "deep_sleep"; case ESP_RST_BROWNOUT: return "brownout"; case ESP_RST_SDIO: return "sdio"; case ESP_RST_USB: return "usb"; case ESP_RST_JTAG: return "jtag"; case ESP_RST_EFUSE: return "efuse"; case ESP_RST_PWR_GLITCH: return "power_glitch"; case ESP_RST_CPU_LOCKUP: return "cpu_lockup"; } return "unrecognized"; } static void log_heap(uint64_t uptime_ms) { const size_t free_heap_bytes = esp_get_free_heap_size(); const size_t minimum_free_heap_bytes = esp_get_minimum_free_heap_size(); uint32_t flash_size_bytes = 0; const esp_err_t flash_result = esp_flash_get_size(NULL, &flash_size_bytes); if (flash_result == ESP_OK) { ESP_LOGI(kLogTag, "health uptime_ms=%" PRIu64 " reset_reason=%s flash_bytes=%" PRIu32 " free_heap_bytes=%u min_free_heap_bytes=%u", uptime_ms, reset_reason_name(esp_reset_reason()), flash_size_bytes, (unsigned int)free_heap_bytes, (unsigned int)minimum_free_heap_bytes); } else { ESP_LOGE(kLogTag, "health flash_size_failed=%s", esp_err_to_name(flash_result)); } } static void probe_candidate_led(void) { ESP_LOGI(kLogTag, "led_probe gpio=%d transitions=%" PRIu32 " interval_ms=%" PRIu32 "; visually confirm the LED", (int)kCandidateLedGpio, kLedProbeCount, kLedProbeIntervalMs); esp_err_t result = gpio_reset_pin(kCandidateLedGpio); if (result != ESP_OK) { ESP_LOGW(kLogTag, "led_probe gpio_reset_pin failed: %s", esp_err_to_name(result)); return; } result = gpio_set_direction(kCandidateLedGpio, GPIO_MODE_OUTPUT); if (result != ESP_OK) { ESP_LOGW(kLogTag, "led_probe gpio_set_direction failed: %s", esp_err_to_name(result)); return; } for (uint32_t transition = 0; transition < kLedProbeCount; ++transition) { gpio_set_level(kCandidateLedGpio, transition % 2U); vTaskDelay(pdMS_TO_TICKS(kLedProbeIntervalMs)); } gpio_set_level(kCandidateLedGpio, 0); ESP_LOGI(kLogTag, "led_probe complete; USB serial remained available during probe"); } static void log_startup(void) { esp_chip_info_t chip_info = {0}; uint32_t flash_size_bytes = 0; const esp_err_t flash_result = esp_flash_get_size(NULL, &flash_size_bytes); esp_chip_info(&chip_info); ESP_LOGI(kLogTag, "startup reset_reason=%s chip_model=%d chip_revision=%d cores=%d features=0x%08" PRIx32, reset_reason_name(esp_reset_reason()), (int)chip_info.model, chip_info.revision, chip_info.cores, chip_info.features); if (flash_result == ESP_OK) { ESP_LOGI(kLogTag, "startup flash_bytes=%" PRIu32, flash_size_bytes); } else { ESP_LOGE(kLogTag, "startup flash_size_failed=%s", esp_err_to_name(flash_result)); } log_heap(0); } void app_main(void) { vTaskDelay(pdMS_TO_TICKS(kStartupAttachmentDelayMs)); log_startup(); probe_candidate_led(); while (true) { log_heap((uint64_t)(esp_timer_get_time() / 1000)); vTaskDelay(pdMS_TO_TICKS(kHealthIntervalMs)); } }