From b0bd0ab9ece86d26d02995f5af41e688e1489fc3 Mon Sep 17 00:00:00 2001 From: Joe Kearney Date: Fri, 16 Jan 2026 18:42:06 -0600 Subject: [PATCH 1/5] Added serial command "system". --- components/Serial_Console/CMakeLists.txt | 18 + .../Serial_Console/Commands/System_Command.c | 653 ++++++++++++++++++ .../Serial_Console/Commands/System_Command.h | 23 + components/Serial_Console/Console.c | 2 + .../Serial_Console/generate_git_version.cmake | 34 + sdkconfig | 9 +- 6 files changed, 737 insertions(+), 2 deletions(-) create mode 100644 components/Serial_Console/Commands/System_Command.c create mode 100644 components/Serial_Console/Commands/System_Command.h create mode 100644 components/Serial_Console/generate_git_version.cmake diff --git a/components/Serial_Console/CMakeLists.txt b/components/Serial_Console/CMakeLists.txt index b4fbae4..571fe1f 100644 --- a/components/Serial_Console/CMakeLists.txt +++ b/components/Serial_Console/CMakeLists.txt @@ -2,14 +2,32 @@ idf_component_register( SRCS "Console.c" "Commands/Log_Command.c" + "Commands/System_Command.c" INCLUDE_DIRS "." "./Commands" REQUIRES "SystemK" "System_Events" + "app_update" "console" + "espcoredump" + "esp_netif" + "esp_pm" + "esp_timer" "log" "nvs_flash" + "spi_flash" "vfs" ) + +add_custom_target(generate_git_version ALL + COMMAND ${CMAKE_COMMAND} + -DSOURCE_DIR=${CMAKE_SOURCE_DIR} + -DOUTPUT_FILE=${CMAKE_CURRENT_BINARY_DIR}/git_version.h + -P ${CMAKE_CURRENT_SOURCE_DIR}/generate_git_version.cmake + BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/git_version.h +) + +add_dependencies(${COMPONENT_LIB} generate_git_version) +target_include_directories(${COMPONENT_LIB} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/components/Serial_Console/Commands/System_Command.c b/components/Serial_Console/Commands/System_Command.c new file mode 100644 index 0000000..b79cfe7 --- /dev/null +++ b/components/Serial_Console/Commands/System_Command.c @@ -0,0 +1,653 @@ +/* + * This program source code file is part of the KTag project, a DIY laser tag + * game with customizable features and wide interoperability. + * + * 🛡 🃞 + * + * Copyright © 2026 Joseph P. Kearney and the KTag developers. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * There should be a copy of the GNU Affero General Public License in the LICENSE + * file in the root of this repository. If not, see . + */ + +#include "esp_console.h" +#include "esp_system.h" +#include "esp_chip_info.h" +#include "esp_flash.h" +#include "esp_partition.h" +#include "esp_ota_ops.h" +#include "esp_app_desc.h" +#include "esp_idf_version.h" +#include "esp_pm.h" +#include "esp_sleep.h" +#include "esp_timer.h" +#include "esp_heap_caps.h" +#include "esp_mac.h" +#include "esp_netif.h" +#include "esp_core_dump.h" +#include "nvs_flash.h" +#include "linenoise/linenoise.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "git_version.h" // Generated during the build process. +#include +#include +#include +#include + +static void print_usage(void) +{ + printf( + "Usage:\n" + " system chip-info - Show chip and system information\n" + " system uptime - Display system uptime\n" + " system tasks - List FreeRTOS tasks\n" + " system reset-reason - Show last reset reason\n" + " system RAM - Display heap memory usage\n" + " system flash - Show flash information\n" + " system partition - List partition table\n" + " system heap-caps - Show heap by capability\n" + " system stats - Combined system statistics\n" + " system backtrace - Print current backtrace\n" + " system coredump - Check coredump status\n" + " system sleep - Enter light sleep\n" + " system mac - Show MAC addresses\n" + " system hostname [name]- Show/set hostname\n" + " system version - Show firmware version\n" + " system idf-version - Show ESP-IDF version\n" + " system factory-reset - Clear NVS and restart\n" + " system reboot - Reboot the device\n"); +} + +static int system_cmd_chip_info(void) +{ + esp_chip_info_t chip_info; + esp_chip_info(&chip_info); + + printf("Chip Information:\n"); + printf(" Model: %s\n", CONFIG_IDF_TARGET); + printf(" Cores: %d\n", chip_info.cores); + printf(" Revision: %d\n", chip_info.revision); + printf(" Features: %s%s%s%s\n", + (chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi " : "", + (chip_info.features & CHIP_FEATURE_BT) ? "BT " : "", + (chip_info.features & CHIP_FEATURE_BLE) ? "BLE " : "", + (chip_info.features & CHIP_FEATURE_IEEE802154) ? "802.15.4 " : ""); + + uint32_t flash_size; + if (esp_flash_get_size(NULL, &flash_size) == ESP_OK) + { + printf(" Flash: %lu MB %s\n", + flash_size / (1024 * 1024), + (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "(embedded)" : "(external)"); + } + + return 0; +} + +static int system_cmd_uptime(void) +{ + int64_t uptime_us = esp_timer_get_time(); + int64_t uptime_s = uptime_us / 1000000; + + int days = uptime_s / 86400; + int hours = (uptime_s % 86400) / 3600; + int minutes = (uptime_s % 3600) / 60; + int seconds = uptime_s % 60; + + printf("Uptime: %d days, %02d:%02d:%02d\n", days, hours, minutes, seconds); + printf(" (%lld seconds)\n", uptime_s); + + return 0; +} + +static int system_cmd_tasks(void) +{ +#if (configUSE_TRACE_FACILITY == 1) + uint32_t task_count = uxTaskGetNumberOfTasks(); + TaskStatus_t *task_array = malloc(task_count * sizeof(TaskStatus_t)); + + if (task_array == NULL) + { + printf("Failed to allocate memory for task list\n"); + return 1; + } + + uint32_t total_runtime; + task_count = uxTaskGetSystemState(task_array, task_count, &total_runtime); + + printf("Tasks (%lu total):\n", task_count); + printf("%-16s %5s %8s %5s", "Name", "State", "Priority", "Stack"); +#if (configGENERATE_RUN_TIME_STATS == 1) + printf(" %s", "CPU%%"); +#endif + printf("\n"); + printf("-----------------------------------------------------------\n"); + + for (uint32_t i = 0; i < task_count; i++) + { + const char *state_str; + switch (task_array[i].eCurrentState) + { + case eRunning: state_str = "RUN "; break; + case eReady: state_str = "READY"; break; + case eBlocked: state_str = "BLOCK"; break; + case eSuspended: state_str = "SUSP "; break; + case eDeleted: state_str = "DEL "; break; + default: state_str = "? "; break; + } + + uint32_t stack_remaining = task_array[i].usStackHighWaterMark; + + printf("%-16s %5s %8u %5lu", + task_array[i].pcTaskName, + state_str, + task_array[i].uxCurrentPriority, + stack_remaining); + +#if (configGENERATE_RUN_TIME_STATS == 1) + float cpu_percent = 0.0; + if (total_runtime > 0) + { + cpu_percent = (100.0 * task_array[i].ulRunTimeCounter) / total_runtime; + } + printf(" %5.1f%%", cpu_percent); +#endif + printf("\n"); + } + + free(task_array); +#else + printf("Task listing not available (configUSE_TRACE_FACILITY not enabled)\n"); + printf("Enable in menuconfig: Component config -> FreeRTOS -> Kernel\n"); +#endif + return 0; +} + +static int system_cmd_reset_reason(void) +{ + esp_reset_reason_t reason = esp_reset_reason(); + + printf("Reset reason: "); + switch (reason) + { + case ESP_RST_UNKNOWN: printf("Unknown\n"); break; + case ESP_RST_POWERON: printf("Power-on reset\n"); break; + case ESP_RST_EXT: printf("External pin reset\n"); break; + case ESP_RST_SW: printf("Software reset\n"); break; + case ESP_RST_PANIC: printf("Exception/panic\n"); break; + case ESP_RST_INT_WDT: printf("Interrupt watchdog\n"); break; + case ESP_RST_TASK_WDT: printf("Task watchdog\n"); break; + case ESP_RST_WDT: printf("Other watchdog\n"); break; + case ESP_RST_DEEPSLEEP: printf("Deep sleep reset\n"); break; + case ESP_RST_BROWNOUT: printf("Brownout reset\n"); break; + case ESP_RST_SDIO: printf("SDIO reset\n"); break; + default: printf("Code %d\n", reason); break; + } + + return 0; +} + +static int system_cmd_ram(void) +{ + size_t free_heap = esp_get_free_heap_size(); + size_t min_free_heap = esp_get_minimum_free_heap_size(); + size_t largest_block = heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT); + + printf("Heap Memory:\n"); + printf(" Free: %u bytes (%.2f KB)\n", free_heap, free_heap / 1024.0); + printf(" Minimum free: %u bytes (%.2f KB)\n", min_free_heap, min_free_heap / 1024.0); + printf(" Largest free block: %u bytes (%.2f KB)\n", largest_block, largest_block / 1024.0); + + return 0; +} + +static int system_cmd_flash(void) +{ + uint32_t flash_size; + if (esp_flash_get_size(NULL, &flash_size) != ESP_OK) + { + printf("Failed to get flash size\n"); + return 1; + } + + printf("Flash Information:\n"); + printf(" Total size: %lu bytes (%.2f MB)\n", flash_size, flash_size / (1024.0 * 1024.0)); + + const esp_partition_t *running = esp_ota_get_running_partition(); + if (running) + { + printf(" Running partition: %s (offset 0x%lx, size %lu KB)\n", + running->label, running->address, running->size / 1024); + } + + return 0; +} + +static int system_cmd_partition(void) +{ + printf("Partition Table:\n"); + printf("%-16s %-10s %-10s %10s %10s\n", "Label", "Type", "SubType", "Offset", "Size"); + printf("------------------------------------------------------------------------\n"); + + esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL); + + while (it != NULL) + { + const esp_partition_t *part = esp_partition_get(it); + + const char *type_str = "?"; + if (part->type == ESP_PARTITION_TYPE_APP) type_str = "app"; + else if (part->type == ESP_PARTITION_TYPE_DATA) type_str = "data"; + + printf("%-16s %-10s 0x%-8x 0x%08lx %8lu KB\n", + part->label, + type_str, + part->subtype, + part->address, + part->size / 1024); + + it = esp_partition_next(it); + } + + esp_partition_iterator_release(it); + return 0; +} + +static int system_cmd_heap_caps(void) +{ + printf("Heap by Capability:\n"); + + size_t internal_free = heap_caps_get_free_size(MALLOC_CAP_INTERNAL); + size_t internal_total = heap_caps_get_total_size(MALLOC_CAP_INTERNAL); + printf(" Internal: %u / %u bytes free (%.1f%%)\n", + internal_free, internal_total, + internal_total > 0 ? 100.0 * internal_free / internal_total : 0); + + size_t spiram_free = heap_caps_get_free_size(MALLOC_CAP_SPIRAM); + size_t spiram_total = heap_caps_get_total_size(MALLOC_CAP_SPIRAM); + if (spiram_total > 0) + { + printf(" SPIRAM: %u / %u bytes free (%.1f%%)\n", + spiram_free, spiram_total, 100.0 * spiram_free / spiram_total); + } + + size_t dma_free = heap_caps_get_free_size(MALLOC_CAP_DMA); + size_t dma_total = heap_caps_get_total_size(MALLOC_CAP_DMA); + printf(" DMA capable: %u / %u bytes free (%.1f%%)\n", + dma_free, dma_total, + dma_total > 0 ? 100.0 * dma_free / dma_total : 0); + + size_t exec_free = heap_caps_get_free_size(MALLOC_CAP_EXEC); + size_t exec_total = heap_caps_get_total_size(MALLOC_CAP_EXEC); + printf(" Executable: %u / %u bytes free (%.1f%%)\n", + exec_free, exec_total, + exec_total > 0 ? 100.0 * exec_free / exec_total : 0); + + return 0; +} + +static int system_cmd_stats(void) +{ + printf("=== System Statistics ===\n\n"); + + system_cmd_uptime(); + printf("\n"); + system_cmd_ram(); + printf("\n"); + + uint32_t task_count = uxTaskGetNumberOfTasks(); + printf("Active tasks: %lu\n\n", task_count); + + system_cmd_reset_reason(); + + return 0; +} + +static int system_cmd_coredump(void) +{ + esp_core_dump_summary_t summary; + esp_err_t err = esp_core_dump_get_summary(&summary); + + if (err == ESP_ERR_NOT_FOUND) + { + printf("No coredump found in flash\n"); + return 0; + } + else if (err != ESP_OK) + { + printf("Failed to read coredump: %s\n", esp_err_to_name(err)); + return 1; + } + + printf("Coredump found:\n"); + printf(" Program counter: 0x%08lx\n", summary.exc_pc); + printf(" Exception cause: %lu\n", summary.ex_info.exc_cause); + printf(" Exception vaddr: 0x%08lx\n", summary.ex_info.exc_vaddr); + + return 0; +} + +static int system_cmd_sleep(int argc, char **argv) +{ + if (argc < 3) + { + printf("Usage: system sleep \n"); + return 0; + } + + int sleep_ms = atoi(argv[2]); + printf("Entering light sleep for %d ms...\n", sleep_ms); + + esp_sleep_enable_timer_wakeup(sleep_ms * 1000); + esp_light_sleep_start(); + + printf("Woke up from sleep\n"); + return 0; +} + +static int system_cmd_mac(void) +{ + uint8_t mac[6]; + + printf("MAC Addresses:\n"); + + if (esp_read_mac(mac, ESP_MAC_WIFI_STA) == ESP_OK) + { + printf(" WiFi STA: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } + + if (esp_read_mac(mac, ESP_MAC_WIFI_SOFTAP) == ESP_OK) + { + printf(" WiFi AP: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } + + if (esp_read_mac(mac, ESP_MAC_BT) == ESP_OK) + { + printf(" BT: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } + + if (esp_read_mac(mac, ESP_MAC_ETH) == ESP_OK) + { + printf(" Ethernet: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } + + return 0; +} +typedef struct { + const char **hostname_out; + bool success; +} hostname_get_ctx_t; + +typedef struct { + const char *hostname_in; + esp_err_t result; +} hostname_set_ctx_t; + +static esp_err_t get_hostname_tcpip(void *ctx) +{ + hostname_get_ctx_t *context = (hostname_get_ctx_t *)ctx; + esp_netif_t *netif = esp_netif_next_unsafe(NULL); + + if (netif) + { + esp_netif_get_hostname(netif, context->hostname_out); + context->success = true; + } + else + { + context->success = false; + } + + return ESP_OK; +} + +static esp_err_t set_hostname_tcpip(void *ctx) +{ + hostname_set_ctx_t *context = (hostname_set_ctx_t *)ctx; + esp_netif_t *netif = esp_netif_next_unsafe(NULL); + + if (netif) + { + context->result = esp_netif_set_hostname(netif, context->hostname_in); + } + else + { + context->result = ESP_ERR_NOT_FOUND; + } + + return ESP_OK; +} + +static int system_cmd_hostname(int argc, char **argv) +{ + if (argc < 3) + { + const char *hostname = NULL; + hostname_get_ctx_t ctx = { + .hostname_out = &hostname, + .success = false + }; + + esp_err_t err = esp_netif_tcpip_exec(get_hostname_tcpip, &ctx); + + if (err != ESP_OK) + { + printf("Failed to access network interface: %s\n", esp_err_to_name(err)); + return 1; + } + + if (ctx.success) + { + if (hostname) + { + printf("Hostname: %s\n", hostname); + } + else + { + printf("No hostname set\n"); + } + } + else + { + printf("No network interface available\n"); + } + return 0; + } + + hostname_set_ctx_t ctx = { + .hostname_in = argv[2], + .result = ESP_FAIL + }; + + esp_err_t err = esp_netif_tcpip_exec(set_hostname_tcpip, &ctx); + + if (err != ESP_OK) + { + printf("Failed to access network interface: %s\n", esp_err_to_name(err)); + return 1; + } + + if (ctx.result == ESP_ERR_NOT_FOUND) + { + printf("No network interface available\n"); + } + else if (ctx.result == ESP_OK) + { + printf("Hostname set to: %s\n", argv[2]); + } + else + { + printf("Failed to set hostname: %s\n", esp_err_to_name(ctx.result)); + } + + return 0; +} + +static int system_cmd_version(void) +{ + const esp_app_desc_t *app_desc = esp_app_get_description(); + + printf("Firmware Information:\n"); + printf(" Version: %s\n", app_desc->version); + printf(" Project: %s\n", app_desc->project_name); + printf(" IDF version: %s\n", app_desc->idf_ver); + printf(" SystemK version: %s\n", SYSTEMK_VERSION_STRING); + printf(" Git commit: %s\n", GIT_COMMIT_HASH_LONG); + printf(" Compile time: %s %s\n", app_desc->date, app_desc->time); + + return 0; +} + +static int system_cmd_idf_version(void) +{ + printf("ESP-IDF Version: %s\n", IDF_VER); + printf(" Major: %d\n", ESP_IDF_VERSION_MAJOR); + printf(" Minor: %d\n", ESP_IDF_VERSION_MINOR); + printf(" Patch: %d\n", ESP_IDF_VERSION_PATCH); + + return 0; +} + +static int system_cmd_factory_reset(void) +{ + printf("WARNING: This will erase all NVS data!\n"); + printf("Type 'yes' to confirm: "); + + char confirm[10]; + if (fgets(confirm, sizeof(confirm), stdin) == NULL) + { + printf("\nCancelled\n"); + return 0; + } + + // Remove newline + confirm[strcspn(confirm, "\n")] = 0; + + if (strcmp(confirm, "yes") != 0) + { + printf("Cancelled\n"); + return 0; + } + + printf("Erasing NVS...\n"); + esp_err_t err = nvs_flash_erase(); + if (err != ESP_OK) + { + printf("Failed to erase NVS: %s\n", esp_err_to_name(err)); + return 1; + } + + printf("Factory reset complete. Rebooting...\n"); + vTaskDelay(pdMS_TO_TICKS(1000)); + esp_restart(); + + return 0; +} + +static int system_cmd_reboot(void) +{ + printf("Rebooting...\n"); + vTaskDelay(pdMS_TO_TICKS(100)); + esp_restart(); + return 0; +} + +static int cmd_system(int argc, char **argv) +{ + if (argc < 2) + { + print_usage(); + return 0; + } + + if (!strcmp(argv[1], "chip-info")) + return system_cmd_chip_info(); + if (!strcmp(argv[1], "uptime")) + return system_cmd_uptime(); + if (!strcmp(argv[1], "tasks")) + return system_cmd_tasks(); + if (!strcmp(argv[1], "reset-reason")) + return system_cmd_reset_reason(); + if (!strcmp(argv[1], "RAM")) + return system_cmd_ram(); + if (!strcmp(argv[1], "flash")) + return system_cmd_flash(); + if (!strcmp(argv[1], "partition")) + return system_cmd_partition(); + if (!strcmp(argv[1], "heap-caps")) + return system_cmd_heap_caps(); + if (!strcmp(argv[1], "stats")) + return system_cmd_stats(); + if (!strcmp(argv[1], "coredump")) + return system_cmd_coredump(); + if (!strcmp(argv[1], "sleep")) + return system_cmd_sleep(argc, argv); + if (!strcmp(argv[1], "mac")) + return system_cmd_mac(); + if (!strcmp(argv[1], "hostname")) + return system_cmd_hostname(argc, argv); + if (!strcmp(argv[1], "version")) + return system_cmd_version(); + if (!strcmp(argv[1], "idf-version")) + return system_cmd_idf_version(); + if (!strcmp(argv[1], "factory-reset")) + return system_cmd_factory_reset(); + if (!strcmp(argv[1], "reboot")) + return system_cmd_reboot(); + + printf("Unknown command\n"); + print_usage(); + return 0; +} + +static void system_completion(const char *buf, linenoiseCompletions *lc) +{ + if (!strncmp(buf, "system", 6)) + { + linenoiseAddCompletion(lc, "system chip-info"); + linenoiseAddCompletion(lc, "system uptime"); + linenoiseAddCompletion(lc, "system tasks"); + linenoiseAddCompletion(lc, "system reset-reason"); + linenoiseAddCompletion(lc, "system RAM"); + linenoiseAddCompletion(lc, "system flash"); + linenoiseAddCompletion(lc, "system partition"); + linenoiseAddCompletion(lc, "system heap-caps"); + linenoiseAddCompletion(lc, "system stats"); + linenoiseAddCompletion(lc, "system coredump"); + linenoiseAddCompletion(lc, "system sleep"); + linenoiseAddCompletion(lc, "system mac"); + linenoiseAddCompletion(lc, "system hostname"); + linenoiseAddCompletion(lc, "system version"); + linenoiseAddCompletion(lc, "system idf-version"); + linenoiseAddCompletion(lc, "system factory-reset"); + linenoiseAddCompletion(lc, "system reboot"); + } +} + +void Register_System_Command(void) +{ + linenoiseSetCompletionCallback(system_completion); + + const esp_console_cmd_t cmd = { + .command = "system", + .help = "System management and diagnostic commands", + .func = &cmd_system, + }; + + ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); +} \ No newline at end of file diff --git a/components/Serial_Console/Commands/System_Command.h b/components/Serial_Console/Commands/System_Command.h new file mode 100644 index 0000000..f34f331 --- /dev/null +++ b/components/Serial_Console/Commands/System_Command.h @@ -0,0 +1,23 @@ +/* + * This program source code file is part of the KTag project, a DIY laser tag + * game with customizable features and wide interoperability. + * + * 🛡 🃞 + * + * Copyright © 2026 Joseph P. Kearney and the KTag developers. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * There should be a copy of the GNU Affero General Public License in the LICENSE + * file in the root of this repository. If not, see . + */ + +void Register_System_Command(void); \ No newline at end of file diff --git a/components/Serial_Console/Console.c b/components/Serial_Console/Console.c index af2a29e..80e59d5 100644 --- a/components/Serial_Console/Console.c +++ b/components/Serial_Console/Console.c @@ -22,10 +22,12 @@ #include "esp_console.h" #include +#include static void register_commands() { Register_Log_Command(); + Register_System_Command(); esp_console_register_help_command(); } diff --git a/components/Serial_Console/generate_git_version.cmake b/components/Serial_Console/generate_git_version.cmake new file mode 100644 index 0000000..6058a58 --- /dev/null +++ b/components/Serial_Console/generate_git_version.cmake @@ -0,0 +1,34 @@ +execute_process( + COMMAND git rev-parse --short HEAD + WORKING_DIRECTORY ${SOURCE_DIR} + OUTPUT_VARIABLE GIT_HASH_SHORT + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +execute_process( + COMMAND git rev-parse HEAD + WORKING_DIRECTORY ${SOURCE_DIR} + OUTPUT_VARIABLE GIT_HASH_LONG + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +# Check for uncommitted changes +execute_process( + COMMAND git diff-index --quiet HEAD -- + WORKING_DIRECTORY ${SOURCE_DIR} + RESULT_VARIABLE GIT_DIRTY +) + +# If GIT_DIRTY is non-zero, there are local modifications +if(NOT GIT_DIRTY EQUAL 0) + set(GIT_HASH_SHORT "${GIT_HASH_SHORT}+") + set(GIT_HASH_LONG "${GIT_HASH_LONG}+") +endif() + +file(WRITE ${OUTPUT_FILE} +"#ifndef GIT_VERSION_H +#define GIT_VERSION_H +#define GIT_COMMIT_HASH_SHORT \"${GIT_HASH_SHORT}\" +#define GIT_COMMIT_HASH_LONG \"${GIT_HASH_LONG}\" +#endif +") \ No newline at end of file diff --git a/sdkconfig b/sdkconfig index 1613bf3..766acd6 100644 --- a/sdkconfig +++ b/sdkconfig @@ -1871,9 +1871,13 @@ CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=4096 CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=1 -# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y # CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES is not set -# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set +# CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID is not set +CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y +CONFIG_FREERTOS_RUN_TIME_COUNTER_TYPE_U32=y +# CONFIG_FREERTOS_RUN_TIME_COUNTER_TYPE_U64 is not set # CONFIG_FREERTOS_USE_APPLICATION_TASK_TAG is not set # end of Kernel @@ -1893,6 +1897,7 @@ CONFIG_FREERTOS_TICK_SUPPORT_SYSTIMER=y CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL1=y # CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3 is not set CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER=y +CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER=y # CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set # CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set # end of Port -- 2.47.3 From 8efd5fdbff4cda05e0d0e47ceaf678a5aba15f7a Mon Sep 17 00:00:00 2001 From: Joe Kearney Date: Fri, 16 Jan 2026 22:02:58 -0600 Subject: [PATCH 2/5] Better log behavior. --- sdkconfig | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/sdkconfig b/sdkconfig index 766acd6..9b2ab6c 100644 --- a/sdkconfig +++ b/sdkconfig @@ -441,11 +441,11 @@ CONFIG_BOOTLOADER_LOG_VERSION_1=y CONFIG_BOOTLOADER_LOG_VERSION=1 # CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set # CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set -# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set -CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y +CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y +# CONFIG_BOOTLOADER_LOG_LEVEL_INFO is not set # CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set # CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set -CONFIG_BOOTLOADER_LOG_LEVEL=3 +CONFIG_BOOTLOADER_LOG_LEVEL=2 # # Format @@ -1957,17 +1957,19 @@ CONFIG_LOG_VERSION=1 # CONFIG_LOG_DEFAULT_LEVEL_NONE is not set # CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set # CONFIG_LOG_DEFAULT_LEVEL_WARN is not set -# CONFIG_LOG_DEFAULT_LEVEL_INFO is not set +CONFIG_LOG_DEFAULT_LEVEL_INFO=y # CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set -CONFIG_LOG_DEFAULT_LEVEL_VERBOSE=y -CONFIG_LOG_DEFAULT_LEVEL=5 -CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y +# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set +CONFIG_LOG_DEFAULT_LEVEL=3 +# CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT is not set +# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set +CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE=y CONFIG_LOG_MAXIMUM_LEVEL=5 # # Level Settings # -CONFIG_LOG_MASTER_LEVEL=y +# CONFIG_LOG_MASTER_LEVEL is not set CONFIG_LOG_DYNAMIC_LEVEL_CONTROL=y # CONFIG_LOG_TAG_LEVEL_IMPL_NONE is not set # CONFIG_LOG_TAG_LEVEL_IMPL_LINKED_LIST is not set @@ -2733,11 +2735,11 @@ CONFIG_MDNS_PREDEF_NETIF_ETH=y # CONFIG_APP_ROLLBACK_ENABLE is not set # CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set # CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set -# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set -CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y +CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y +# CONFIG_LOG_BOOTLOADER_LEVEL_INFO is not set # CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set # CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set -CONFIG_LOG_BOOTLOADER_LEVEL=3 +CONFIG_LOG_BOOTLOADER_LEVEL=2 # CONFIG_FLASH_ENCRYPTION_ENABLED is not set # CONFIG_FLASHMODE_QIO is not set # CONFIG_FLASHMODE_QOUT is not set -- 2.47.3 From 2b77c011256ddf8727d48b52b5d959bf0340fd67 Mon Sep 17 00:00:00 2001 From: Joe Kearney Date: Fri, 16 Jan 2026 22:03:22 -0600 Subject: [PATCH 3/5] Added git versions. --- components/Serial_Console/CMakeLists.txt | 12 +- .../Serial_Console/Commands/System_Command.c | 284 +++++++++--------- .../Serial_Console/generate_git_version.cmake | 34 --- .../generate_git_versions.cmake | 72 +++++ 4 files changed, 228 insertions(+), 174 deletions(-) delete mode 100644 components/Serial_Console/generate_git_version.cmake create mode 100644 components/Serial_Console/generate_git_versions.cmake diff --git a/components/Serial_Console/CMakeLists.txt b/components/Serial_Console/CMakeLists.txt index 571fe1f..94c73e9 100644 --- a/components/Serial_Console/CMakeLists.txt +++ b/components/Serial_Console/CMakeLists.txt @@ -21,13 +21,15 @@ idf_component_register( "vfs" ) -add_custom_target(generate_git_version ALL +target_compile_definitions(${COMPONENT_LIB} PRIVATE HAS_SYSTEMK_GIT_VERSION) + +add_custom_target(generate_git_versions ALL COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR} - -DOUTPUT_FILE=${CMAKE_CURRENT_BINARY_DIR}/git_version.h - -P ${CMAKE_CURRENT_SOURCE_DIR}/generate_git_version.cmake - BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/git_version.h + -DOUTPUT_FILE=${CMAKE_CURRENT_BINARY_DIR}/git_versions.h + -P ${CMAKE_CURRENT_SOURCE_DIR}/generate_git_versions.cmake + BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/git_versions.h ) -add_dependencies(${COMPONENT_LIB} generate_git_version) +add_dependencies(${COMPONENT_LIB} generate_git_versions) target_include_directories(${COMPONENT_LIB} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/components/Serial_Console/Commands/System_Command.c b/components/Serial_Console/Commands/System_Command.c index b79cfe7..a35f3ef 100644 --- a/components/Serial_Console/Commands/System_Command.c +++ b/components/Serial_Console/Commands/System_Command.c @@ -39,7 +39,7 @@ #include "linenoise/linenoise.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "git_version.h" // Generated during the build process. +#include "git_versions.h" // Generated during the build process. #include #include #include @@ -64,7 +64,6 @@ static void print_usage(void) " system mac - Show MAC addresses\n" " system hostname [name]- Show/set hostname\n" " system version - Show firmware version\n" - " system idf-version - Show ESP-IDF version\n" " system factory-reset - Clear NVS and restart\n" " system reboot - Reboot the device\n"); } @@ -73,7 +72,7 @@ static int system_cmd_chip_info(void) { esp_chip_info_t chip_info; esp_chip_info(&chip_info); - + printf("Chip Information:\n"); printf(" Model: %s\n", CONFIG_IDF_TARGET); printf(" Cores: %d\n", chip_info.cores); @@ -83,7 +82,7 @@ static int system_cmd_chip_info(void) (chip_info.features & CHIP_FEATURE_BT) ? "BT " : "", (chip_info.features & CHIP_FEATURE_BLE) ? "BLE " : "", (chip_info.features & CHIP_FEATURE_IEEE802154) ? "802.15.4 " : ""); - + uint32_t flash_size; if (esp_flash_get_size(NULL, &flash_size) == ESP_OK) { @@ -91,7 +90,7 @@ static int system_cmd_chip_info(void) flash_size / (1024 * 1024), (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "(embedded)" : "(external)"); } - + return 0; } @@ -99,15 +98,15 @@ static int system_cmd_uptime(void) { int64_t uptime_us = esp_timer_get_time(); int64_t uptime_s = uptime_us / 1000000; - + int days = uptime_s / 86400; int hours = (uptime_s % 86400) / 3600; int minutes = (uptime_s % 3600) / 60; int seconds = uptime_s % 60; - + printf("Uptime: %d days, %02d:%02d:%02d\n", days, hours, minutes, seconds); - printf(" (%lld seconds)\n", uptime_s); - + printf(" (%lld seconds)\n", uptime_s); + return 0; } @@ -116,56 +115,77 @@ static int system_cmd_tasks(void) #if (configUSE_TRACE_FACILITY == 1) uint32_t task_count = uxTaskGetNumberOfTasks(); TaskStatus_t *task_array = malloc(task_count * sizeof(TaskStatus_t)); - + if (task_array == NULL) { printf("Failed to allocate memory for task list\n"); return 1; } - + uint32_t total_runtime; task_count = uxTaskGetSystemState(task_array, task_count, &total_runtime); - + printf("Tasks (%lu total):\n", task_count); - printf("%-16s %5s %8s %5s", "Name", "State", "Priority", "Stack"); + printf("%-16s %5s %6s %11s %8s", "Name", "State", "Core", "Priority", "Stack"); #if (configGENERATE_RUN_TIME_STATS == 1) - printf(" %s", "CPU%%"); + printf(" %7s", "CPU%"); #endif printf("\n"); - printf("-----------------------------------------------------------\n"); - + printf("----------------------------------------------------------------\n"); + for (uint32_t i = 0; i < task_count; i++) { const char *state_str; switch (task_array[i].eCurrentState) { - case eRunning: state_str = "RUN "; break; - case eReady: state_str = "READY"; break; - case eBlocked: state_str = "BLOCK"; break; - case eSuspended: state_str = "SUSP "; break; - case eDeleted: state_str = "DEL "; break; - default: state_str = "? "; break; + case eRunning: + state_str = "RUN "; + break; + case eReady: + state_str = "READY"; + break; + case eBlocked: + state_str = "BLOCK"; + break; + case eSuspended: + state_str = "SUSP "; + break; + case eDeleted: + state_str = "DEL "; + break; + default: + state_str = "? "; + break; } - + uint32_t stack_remaining = task_array[i].usStackHighWaterMark; - - printf("%-16s %5s %8u %5lu", - task_array[i].pcTaskName, - state_str, - task_array[i].uxCurrentPriority, - stack_remaining); - + + BaseType_t affinity = xTaskGetCoreID(task_array[i].xHandle); + + printf("%-16s %5s ", task_array[i].pcTaskName, state_str); + + if (affinity == tskNO_AFFINITY) + { + printf("%6s", "ANY"); + } + else + { + printf("%6d", (int)affinity); + } + + printf(" %11u %8lu", task_array[i].uxCurrentPriority, stack_remaining); + #if (configGENERATE_RUN_TIME_STATS == 1) float cpu_percent = 0.0; if (total_runtime > 0) { cpu_percent = (100.0 * task_array[i].ulRunTimeCounter) / total_runtime; } - printf(" %5.1f%%", cpu_percent); + printf(" %6.1f%%", cpu_percent); #endif printf("\n"); } - + free(task_array); #else printf("Task listing not available (configUSE_TRACE_FACILITY not enabled)\n"); @@ -177,24 +197,48 @@ static int system_cmd_tasks(void) static int system_cmd_reset_reason(void) { esp_reset_reason_t reason = esp_reset_reason(); - + printf("Reset reason: "); switch (reason) { - case ESP_RST_UNKNOWN: printf("Unknown\n"); break; - case ESP_RST_POWERON: printf("Power-on reset\n"); break; - case ESP_RST_EXT: printf("External pin reset\n"); break; - case ESP_RST_SW: printf("Software reset\n"); break; - case ESP_RST_PANIC: printf("Exception/panic\n"); break; - case ESP_RST_INT_WDT: printf("Interrupt watchdog\n"); break; - case ESP_RST_TASK_WDT: printf("Task watchdog\n"); break; - case ESP_RST_WDT: printf("Other watchdog\n"); break; - case ESP_RST_DEEPSLEEP: printf("Deep sleep reset\n"); break; - case ESP_RST_BROWNOUT: printf("Brownout reset\n"); break; - case ESP_RST_SDIO: printf("SDIO reset\n"); break; - default: printf("Code %d\n", reason); break; + case ESP_RST_UNKNOWN: + printf("Unknown\n"); + break; + case ESP_RST_POWERON: + printf("Power-on reset\n"); + break; + case ESP_RST_EXT: + printf("External pin reset\n"); + break; + case ESP_RST_SW: + printf("Software reset\n"); + break; + case ESP_RST_PANIC: + printf("Exception/panic\n"); + break; + case ESP_RST_INT_WDT: + printf("Interrupt watchdog\n"); + break; + case ESP_RST_TASK_WDT: + printf("Task watchdog\n"); + break; + case ESP_RST_WDT: + printf("Other watchdog\n"); + break; + case ESP_RST_DEEPSLEEP: + printf("Deep sleep reset\n"); + break; + case ESP_RST_BROWNOUT: + printf("Brownout reset\n"); + break; + case ESP_RST_SDIO: + printf("SDIO reset\n"); + break; + default: + printf("Code %d\n", reason); + break; } - + return 0; } @@ -203,12 +247,12 @@ static int system_cmd_ram(void) size_t free_heap = esp_get_free_heap_size(); size_t min_free_heap = esp_get_minimum_free_heap_size(); size_t largest_block = heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT); - + printf("Heap Memory:\n"); printf(" Free: %u bytes (%.2f KB)\n", free_heap, free_heap / 1024.0); printf(" Minimum free: %u bytes (%.2f KB)\n", min_free_heap, min_free_heap / 1024.0); printf(" Largest free block: %u bytes (%.2f KB)\n", largest_block, largest_block / 1024.0); - + return 0; } @@ -220,17 +264,17 @@ static int system_cmd_flash(void) printf("Failed to get flash size\n"); return 1; } - + printf("Flash Information:\n"); printf(" Total size: %lu bytes (%.2f MB)\n", flash_size, flash_size / (1024.0 * 1024.0)); - + const esp_partition_t *running = esp_ota_get_running_partition(); if (running) { printf(" Running partition: %s (offset 0x%lx, size %lu KB)\n", running->label, running->address, running->size / 1024); } - + return 0; } @@ -239,27 +283,29 @@ static int system_cmd_partition(void) printf("Partition Table:\n"); printf("%-16s %-10s %-10s %10s %10s\n", "Label", "Type", "SubType", "Offset", "Size"); printf("------------------------------------------------------------------------\n"); - + esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL); - + while (it != NULL) { const esp_partition_t *part = esp_partition_get(it); - + const char *type_str = "?"; - if (part->type == ESP_PARTITION_TYPE_APP) type_str = "app"; - else if (part->type == ESP_PARTITION_TYPE_DATA) type_str = "data"; - + if (part->type == ESP_PARTITION_TYPE_APP) + type_str = "app"; + else if (part->type == ESP_PARTITION_TYPE_DATA) + type_str = "data"; + printf("%-16s %-10s 0x%-8x 0x%08lx %8lu KB\n", part->label, type_str, part->subtype, part->address, part->size / 1024); - + it = esp_partition_next(it); } - + esp_partition_iterator_release(it); return 0; } @@ -267,13 +313,13 @@ static int system_cmd_partition(void) static int system_cmd_heap_caps(void) { printf("Heap by Capability:\n"); - + size_t internal_free = heap_caps_get_free_size(MALLOC_CAP_INTERNAL); size_t internal_total = heap_caps_get_total_size(MALLOC_CAP_INTERNAL); printf(" Internal: %u / %u bytes free (%.1f%%)\n", internal_free, internal_total, internal_total > 0 ? 100.0 * internal_free / internal_total : 0); - + size_t spiram_free = heap_caps_get_free_size(MALLOC_CAP_SPIRAM); size_t spiram_total = heap_caps_get_total_size(MALLOC_CAP_SPIRAM); if (spiram_total > 0) @@ -281,36 +327,36 @@ static int system_cmd_heap_caps(void) printf(" SPIRAM: %u / %u bytes free (%.1f%%)\n", spiram_free, spiram_total, 100.0 * spiram_free / spiram_total); } - + size_t dma_free = heap_caps_get_free_size(MALLOC_CAP_DMA); size_t dma_total = heap_caps_get_total_size(MALLOC_CAP_DMA); printf(" DMA capable: %u / %u bytes free (%.1f%%)\n", dma_free, dma_total, dma_total > 0 ? 100.0 * dma_free / dma_total : 0); - + size_t exec_free = heap_caps_get_free_size(MALLOC_CAP_EXEC); size_t exec_total = heap_caps_get_total_size(MALLOC_CAP_EXEC); printf(" Executable: %u / %u bytes free (%.1f%%)\n", exec_free, exec_total, exec_total > 0 ? 100.0 * exec_free / exec_total : 0); - + return 0; } static int system_cmd_stats(void) { printf("=== System Statistics ===\n\n"); - + system_cmd_uptime(); printf("\n"); system_cmd_ram(); printf("\n"); - + uint32_t task_count = uxTaskGetNumberOfTasks(); printf("Active tasks: %lu\n\n", task_count); - + system_cmd_reset_reason(); - + return 0; } @@ -318,7 +364,7 @@ static int system_cmd_coredump(void) { esp_core_dump_summary_t summary; esp_err_t err = esp_core_dump_get_summary(&summary); - + if (err == ESP_ERR_NOT_FOUND) { printf("No coredump found in flash\n"); @@ -329,71 +375,55 @@ static int system_cmd_coredump(void) printf("Failed to read coredump: %s\n", esp_err_to_name(err)); return 1; } - + printf("Coredump found:\n"); printf(" Program counter: 0x%08lx\n", summary.exc_pc); printf(" Exception cause: %lu\n", summary.ex_info.exc_cause); printf(" Exception vaddr: 0x%08lx\n", summary.ex_info.exc_vaddr); - - return 0; -} -static int system_cmd_sleep(int argc, char **argv) -{ - if (argc < 3) - { - printf("Usage: system sleep \n"); - return 0; - } - - int sleep_ms = atoi(argv[2]); - printf("Entering light sleep for %d ms...\n", sleep_ms); - - esp_sleep_enable_timer_wakeup(sleep_ms * 1000); - esp_light_sleep_start(); - - printf("Woke up from sleep\n"); return 0; } static int system_cmd_mac(void) { uint8_t mac[6]; - + printf("MAC Addresses:\n"); - + if (esp_read_mac(mac, ESP_MAC_WIFI_STA) == ESP_OK) { printf(" WiFi STA: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } - + if (esp_read_mac(mac, ESP_MAC_WIFI_SOFTAP) == ESP_OK) { printf(" WiFi AP: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } - + if (esp_read_mac(mac, ESP_MAC_BT) == ESP_OK) { printf(" BT: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } - + if (esp_read_mac(mac, ESP_MAC_ETH) == ESP_OK) { printf(" Ethernet: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } - + return 0; } -typedef struct { +typedef struct +{ const char **hostname_out; bool success; } hostname_get_ctx_t; -typedef struct { +typedef struct +{ const char *hostname_in; esp_err_t result; } hostname_set_ctx_t; @@ -402,7 +432,7 @@ static esp_err_t get_hostname_tcpip(void *ctx) { hostname_get_ctx_t *context = (hostname_get_ctx_t *)ctx; esp_netif_t *netif = esp_netif_next_unsafe(NULL); - + if (netif) { esp_netif_get_hostname(netif, context->hostname_out); @@ -412,7 +442,7 @@ static esp_err_t get_hostname_tcpip(void *ctx) { context->success = false; } - + return ESP_OK; } @@ -420,7 +450,7 @@ static esp_err_t set_hostname_tcpip(void *ctx) { hostname_set_ctx_t *context = (hostname_set_ctx_t *)ctx; esp_netif_t *netif = esp_netif_next_unsafe(NULL); - + if (netif) { context->result = esp_netif_set_hostname(netif, context->hostname_in); @@ -429,7 +459,7 @@ static esp_err_t set_hostname_tcpip(void *ctx) { context->result = ESP_ERR_NOT_FOUND; } - + return ESP_OK; } @@ -440,17 +470,16 @@ static int system_cmd_hostname(int argc, char **argv) const char *hostname = NULL; hostname_get_ctx_t ctx = { .hostname_out = &hostname, - .success = false - }; - + .success = false}; + esp_err_t err = esp_netif_tcpip_exec(get_hostname_tcpip, &ctx); - + if (err != ESP_OK) { printf("Failed to access network interface: %s\n", esp_err_to_name(err)); return 1; } - + if (ctx.success) { if (hostname) @@ -468,20 +497,19 @@ static int system_cmd_hostname(int argc, char **argv) } return 0; } - + hostname_set_ctx_t ctx = { .hostname_in = argv[2], - .result = ESP_FAIL - }; - + .result = ESP_FAIL}; + esp_err_t err = esp_netif_tcpip_exec(set_hostname_tcpip, &ctx); - + if (err != ESP_OK) { printf("Failed to access network interface: %s\n", esp_err_to_name(err)); return 1; } - + if (ctx.result == ESP_ERR_NOT_FOUND) { printf("No network interface available\n"); @@ -494,32 +522,22 @@ static int system_cmd_hostname(int argc, char **argv) { printf("Failed to set hostname: %s\n", esp_err_to_name(ctx.result)); } - + return 0; } static int system_cmd_version(void) { const esp_app_desc_t *app_desc = esp_app_get_description(); - + printf("Firmware Information:\n"); printf(" Version: %s\n", app_desc->version); printf(" Project: %s\n", app_desc->project_name); printf(" IDF version: %s\n", app_desc->idf_ver); - printf(" SystemK version: %s\n", SYSTEMK_VERSION_STRING); + printf(" SystemK version: %s (%s)\n", SYSTEMK_VERSION_STRING, SYSTEMK_GIT_COMMIT_HASH_SHORT); printf(" Git commit: %s\n", GIT_COMMIT_HASH_LONG); printf(" Compile time: %s %s\n", app_desc->date, app_desc->time); - - return 0; -} -static int system_cmd_idf_version(void) -{ - printf("ESP-IDF Version: %s\n", IDF_VER); - printf(" Major: %d\n", ESP_IDF_VERSION_MAJOR); - printf(" Minor: %d\n", ESP_IDF_VERSION_MINOR); - printf(" Patch: %d\n", ESP_IDF_VERSION_PATCH); - return 0; } @@ -527,23 +545,23 @@ static int system_cmd_factory_reset(void) { printf("WARNING: This will erase all NVS data!\n"); printf("Type 'yes' to confirm: "); - + char confirm[10]; if (fgets(confirm, sizeof(confirm), stdin) == NULL) { printf("\nCancelled\n"); return 0; } - + // Remove newline confirm[strcspn(confirm, "\n")] = 0; - + if (strcmp(confirm, "yes") != 0) { - printf("Cancelled\n"); + printf("Factory reset cancelled.\n"); return 0; } - + printf("Erasing NVS...\n"); esp_err_t err = nvs_flash_erase(); if (err != ESP_OK) @@ -551,11 +569,11 @@ static int system_cmd_factory_reset(void) printf("Failed to erase NVS: %s\n", esp_err_to_name(err)); return 1; } - + printf("Factory reset complete. Rebooting...\n"); vTaskDelay(pdMS_TO_TICKS(1000)); esp_restart(); - + return 0; } @@ -595,16 +613,12 @@ static int cmd_system(int argc, char **argv) return system_cmd_stats(); if (!strcmp(argv[1], "coredump")) return system_cmd_coredump(); - if (!strcmp(argv[1], "sleep")) - return system_cmd_sleep(argc, argv); if (!strcmp(argv[1], "mac")) return system_cmd_mac(); if (!strcmp(argv[1], "hostname")) return system_cmd_hostname(argc, argv); if (!strcmp(argv[1], "version")) return system_cmd_version(); - if (!strcmp(argv[1], "idf-version")) - return system_cmd_idf_version(); if (!strcmp(argv[1], "factory-reset")) return system_cmd_factory_reset(); if (!strcmp(argv[1], "reboot")) diff --git a/components/Serial_Console/generate_git_version.cmake b/components/Serial_Console/generate_git_version.cmake deleted file mode 100644 index 6058a58..0000000 --- a/components/Serial_Console/generate_git_version.cmake +++ /dev/null @@ -1,34 +0,0 @@ -execute_process( - COMMAND git rev-parse --short HEAD - WORKING_DIRECTORY ${SOURCE_DIR} - OUTPUT_VARIABLE GIT_HASH_SHORT - OUTPUT_STRIP_TRAILING_WHITESPACE -) - -execute_process( - COMMAND git rev-parse HEAD - WORKING_DIRECTORY ${SOURCE_DIR} - OUTPUT_VARIABLE GIT_HASH_LONG - OUTPUT_STRIP_TRAILING_WHITESPACE -) - -# Check for uncommitted changes -execute_process( - COMMAND git diff-index --quiet HEAD -- - WORKING_DIRECTORY ${SOURCE_DIR} - RESULT_VARIABLE GIT_DIRTY -) - -# If GIT_DIRTY is non-zero, there are local modifications -if(NOT GIT_DIRTY EQUAL 0) - set(GIT_HASH_SHORT "${GIT_HASH_SHORT}+") - set(GIT_HASH_LONG "${GIT_HASH_LONG}+") -endif() - -file(WRITE ${OUTPUT_FILE} -"#ifndef GIT_VERSION_H -#define GIT_VERSION_H -#define GIT_COMMIT_HASH_SHORT \"${GIT_HASH_SHORT}\" -#define GIT_COMMIT_HASH_LONG \"${GIT_HASH_LONG}\" -#endif -") \ No newline at end of file diff --git a/components/Serial_Console/generate_git_versions.cmake b/components/Serial_Console/generate_git_versions.cmake new file mode 100644 index 0000000..b66f862 --- /dev/null +++ b/components/Serial_Console/generate_git_versions.cmake @@ -0,0 +1,72 @@ +# Main repository hashes +execute_process( + COMMAND git rev-parse --short HEAD + WORKING_DIRECTORY ${SOURCE_DIR} + OUTPUT_VARIABLE GIT_HASH_SHORT + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +execute_process( + COMMAND git rev-parse HEAD + WORKING_DIRECTORY ${SOURCE_DIR} + OUTPUT_VARIABLE GIT_HASH_LONG + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +# Check for uncommitted changes in main repo +execute_process( + COMMAND git diff-index --quiet HEAD -- + WORKING_DIRECTORY ${SOURCE_DIR} + RESULT_VARIABLE GIT_DIRTY +) + +if(NOT GIT_DIRTY EQUAL 0) + set(GIT_HASH_SHORT "${GIT_HASH_SHORT}+") + set(GIT_HASH_LONG "${GIT_HASH_LONG}+") +endif() + +# SystemK hashes +set(SYSTEMK_PATH "${SOURCE_DIR}/components/SystemK") + +execute_process( + COMMAND git rev-parse --short HEAD + WORKING_DIRECTORY ${SYSTEMK_PATH} + OUTPUT_VARIABLE SYSTEMK_HASH_SHORT + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE SYSTEMK_RESULT +) + +execute_process( + COMMAND git rev-parse HEAD + WORKING_DIRECTORY ${SYSTEMK_PATH} + OUTPUT_VARIABLE SYSTEMK_HASH_LONG + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +# Check for uncommitted changes in SystemK. +execute_process( + COMMAND git diff-index --quiet HEAD -- + WORKING_DIRECTORY ${SYSTEMK_PATH} + RESULT_VARIABLE SYSTEMK_DIRTY +) + +# Handle the case where SystemK doesn't exist or is not a git repo. +if(SYSTEMK_RESULT EQUAL 0) + if(NOT SYSTEMK_DIRTY EQUAL 0) + set(SYSTEMK_HASH_SHORT "${SYSTEMK_HASH_SHORT}+") + set(SYSTEMK_HASH_LONG "${SYSTEMK_HASH_LONG}+") + endif() +else() + set(SYSTEMK_HASH_SHORT "unknown") + set(SYSTEMK_HASH_LONG "unknown") +endif() + +file(WRITE ${OUTPUT_FILE} +"#ifndef GIT_VERSION_H +#define GIT_VERSION_H +#define GIT_COMMIT_HASH_SHORT \"${GIT_HASH_SHORT}\" +#define GIT_COMMIT_HASH_LONG \"${GIT_HASH_LONG}\" +#define SYSTEMK_GIT_COMMIT_HASH_SHORT \"${SYSTEMK_HASH_SHORT}\" +#define SYSTEMK_GIT_COMMIT_HASH_LONG \"${SYSTEMK_HASH_LONG}\" +#endif +") \ No newline at end of file -- 2.47.3 From 815f2ae3a50e48920e4334364eb2f8fd466b0f5e Mon Sep 17 00:00:00 2001 From: Joe Kearney Date: Fri, 16 Jan 2026 22:31:09 -0600 Subject: [PATCH 4/5] NeoPixels stack was too large (typo?) --- main/HW_NeoPixels.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/HW_NeoPixels.c b/main/HW_NeoPixels.c index 6d4255e..2c0fde9 100644 --- a/main/HW_NeoPixels.c +++ b/main/HW_NeoPixels.c @@ -31,7 +31,7 @@ #include #include "HW_NeoPixels.h" -#define NEOPIXELS_STACK_SIZE (100 * 1024) +#define NEOPIXELS_STACK_SIZE (10 * 1024) #define NEOPIXELS_TASK_PRIORITY (tskIDLE_PRIORITY + 1) static StaticTask_t xTaskBuffer; StackType_t *xStack; -- 2.47.3 From f40392f3436827edef7a56853165e6655b5704a3 Mon Sep 17 00:00:00 2001 From: Joe Kearney Date: Sat, 17 Jan 2026 10:29:08 -0600 Subject: [PATCH 5/5] Cleanup --- .../Serial_Console/Commands/System_Command.c | 94 +++++++++---------- 1 file changed, 45 insertions(+), 49 deletions(-) diff --git a/components/Serial_Console/Commands/System_Command.c b/components/Serial_Console/Commands/System_Command.c index a35f3ef..feaf949 100644 --- a/components/Serial_Console/Commands/System_Command.c +++ b/components/Serial_Console/Commands/System_Command.c @@ -50,22 +50,20 @@ static void print_usage(void) printf( "Usage:\n" " system chip-info - Show chip and system information\n" - " system uptime - Display system uptime\n" - " system tasks - List FreeRTOS tasks\n" - " system reset-reason - Show last reset reason\n" - " system RAM - Display heap memory usage\n" - " system flash - Show flash information\n" - " system partition - List partition table\n" - " system heap-caps - Show heap by capability\n" - " system stats - Combined system statistics\n" - " system backtrace - Print current backtrace\n" " system coredump - Check coredump status\n" - " system sleep - Enter light sleep\n" - " system mac - Show MAC addresses\n" - " system hostname [name]- Show/set hostname\n" - " system version - Show firmware version\n" " system factory-reset - Clear NVS and restart\n" - " system reboot - Reboot the device\n"); + " system flash - Show flash information\n" + " system heap-caps - Show heap by capability\n" + " system hostname [name]- Show/set hostname\n" + " system mac - Show MAC addresses\n" + " system partition - List partition table\n" + " system RAM - Display heap memory usage\n" + " system reboot - Reboot the device\n" + " system reset-reason - Show last reset reason\n" + " system stats - Combined system statistics\n" + " system tasks - List FreeRTOS tasks\n" + " system uptime - Display system uptime\n" + " system version - Show firmware version\n"); } static int system_cmd_chip_info(void) @@ -595,34 +593,34 @@ static int cmd_system(int argc, char **argv) if (!strcmp(argv[1], "chip-info")) return system_cmd_chip_info(); - if (!strcmp(argv[1], "uptime")) - return system_cmd_uptime(); - if (!strcmp(argv[1], "tasks")) - return system_cmd_tasks(); - if (!strcmp(argv[1], "reset-reason")) - return system_cmd_reset_reason(); - if (!strcmp(argv[1], "RAM")) - return system_cmd_ram(); - if (!strcmp(argv[1], "flash")) - return system_cmd_flash(); - if (!strcmp(argv[1], "partition")) - return system_cmd_partition(); - if (!strcmp(argv[1], "heap-caps")) - return system_cmd_heap_caps(); - if (!strcmp(argv[1], "stats")) - return system_cmd_stats(); if (!strcmp(argv[1], "coredump")) return system_cmd_coredump(); - if (!strcmp(argv[1], "mac")) - return system_cmd_mac(); - if (!strcmp(argv[1], "hostname")) - return system_cmd_hostname(argc, argv); - if (!strcmp(argv[1], "version")) - return system_cmd_version(); if (!strcmp(argv[1], "factory-reset")) return system_cmd_factory_reset(); + if (!strcmp(argv[1], "flash")) + return system_cmd_flash(); + if (!strcmp(argv[1], "heap-caps")) + return system_cmd_heap_caps(); + if (!strcmp(argv[1], "hostname")) + return system_cmd_hostname(argc, argv); + if (!strcmp(argv[1], "mac")) + return system_cmd_mac(); + if (!strcmp(argv[1], "partition")) + return system_cmd_partition(); + if (!strcmp(argv[1], "RAM")) + return system_cmd_ram(); if (!strcmp(argv[1], "reboot")) return system_cmd_reboot(); + if (!strcmp(argv[1], "reset-reason")) + return system_cmd_reset_reason(); + if (!strcmp(argv[1], "stats")) + return system_cmd_stats(); + if (!strcmp(argv[1], "tasks")) + return system_cmd_tasks(); + if (!strcmp(argv[1], "uptime")) + return system_cmd_uptime(); + if (!strcmp(argv[1], "version")) + return system_cmd_version(); printf("Unknown command\n"); print_usage(); @@ -634,22 +632,20 @@ static void system_completion(const char *buf, linenoiseCompletions *lc) if (!strncmp(buf, "system", 6)) { linenoiseAddCompletion(lc, "system chip-info"); - linenoiseAddCompletion(lc, "system uptime"); - linenoiseAddCompletion(lc, "system tasks"); - linenoiseAddCompletion(lc, "system reset-reason"); - linenoiseAddCompletion(lc, "system RAM"); - linenoiseAddCompletion(lc, "system flash"); - linenoiseAddCompletion(lc, "system partition"); - linenoiseAddCompletion(lc, "system heap-caps"); - linenoiseAddCompletion(lc, "system stats"); linenoiseAddCompletion(lc, "system coredump"); - linenoiseAddCompletion(lc, "system sleep"); - linenoiseAddCompletion(lc, "system mac"); - linenoiseAddCompletion(lc, "system hostname"); - linenoiseAddCompletion(lc, "system version"); - linenoiseAddCompletion(lc, "system idf-version"); linenoiseAddCompletion(lc, "system factory-reset"); + linenoiseAddCompletion(lc, "system flash"); + linenoiseAddCompletion(lc, "system heap-caps"); + linenoiseAddCompletion(lc, "system hostname"); + linenoiseAddCompletion(lc, "system mac"); + linenoiseAddCompletion(lc, "system partition"); + linenoiseAddCompletion(lc, "system RAM"); linenoiseAddCompletion(lc, "system reboot"); + linenoiseAddCompletion(lc, "system reset-reason"); + linenoiseAddCompletion(lc, "system stats"); + linenoiseAddCompletion(lc, "system tasks"); + linenoiseAddCompletion(lc, "system uptime"); + linenoiseAddCompletion(lc, "system version"); } } -- 2.47.3