From a25627232cb651ae480ab1e75e62d72aa582cdea Mon Sep 17 00:00:00 2001 From: Joe Kearney Date: Thu, 8 Jan 2026 18:53:29 -0600 Subject: [PATCH 1/7] Initial console implementation. --- components/Console/CMakeLists.txt | 13 ++ components/Console/Console.c | 325 ++++++++++++++++++++++++++++++ components/Console/Console.h | 23 +++ components/SystemK | 2 +- main/main.c | 3 + sdkconfig | 12 +- 6 files changed, 371 insertions(+), 7 deletions(-) create mode 100644 components/Console/CMakeLists.txt create mode 100644 components/Console/Console.c create mode 100644 components/Console/Console.h diff --git a/components/Console/CMakeLists.txt b/components/Console/CMakeLists.txt new file mode 100644 index 0000000..ee99750 --- /dev/null +++ b/components/Console/CMakeLists.txt @@ -0,0 +1,13 @@ +idf_component_register( + SRCS + "Console.c" + INCLUDE_DIRS + "." + REQUIRES + "SystemK" + "System_Events" + "console" + "log" + "nvs_flash" + "vfs" +) diff --git a/components/Console/Console.c b/components/Console/Console.c new file mode 100644 index 0000000..3289ae2 --- /dev/null +++ b/components/Console/Console.c @@ -0,0 +1,325 @@ +#include "esp_console.h" +#include "esp_log.h" +#include "nvs.h" +#include "nvs_flash.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "linenoise/linenoise.h" +#include "esp_vfs_dev.h" +#include +#include + +#define LOG_NVS_NS "logcfg" +#define MAX_TAGS 16 +#define MAX_TAGLEN 16 + +typedef struct +{ + char tag[MAX_TAGLEN]; + uint8_t level; +} tag_entry_t; + +static esp_log_level_t Saved_Global_Level = ESP_LOG_INFO; +static tag_entry_t Tag_Table[MAX_TAGS]; +static size_t Tag_Count = 0; + +/* ---------------- Utility ---------------- */ + +static bool parse_level(const char *s, esp_log_level_t *out) +{ + if (!strcmp(s, "none")) + *out = ESP_LOG_NONE; + else if (!strcmp(s, "error")) + *out = ESP_LOG_ERROR; + else if (!strcmp(s, "warn")) + *out = ESP_LOG_WARN; + else if (!strcmp(s, "info")) + *out = ESP_LOG_INFO; + else if (!strcmp(s, "debug")) + *out = ESP_LOG_DEBUG; + else if (!strcmp(s, "verbose")) + *out = ESP_LOG_VERBOSE; + else + return false; + return true; +} + +static const char *level_str(esp_log_level_t lvl) +{ + switch (lvl) + { + case ESP_LOG_NONE: + return "none"; + case ESP_LOG_ERROR: + return "error"; + case ESP_LOG_WARN: + return "warn"; + case ESP_LOG_INFO: + return "info"; + case ESP_LOG_DEBUG: + return "debug"; + case ESP_LOG_VERBOSE: + return "verbose"; + default: + return "?"; + } +} + +/* ---------------- NVS ---------------- */ + +static void nvs_save(void) +{ + nvs_handle_t h; + esp_err_t err = nvs_open(LOG_NVS_NS, NVS_READWRITE, &h); + + if (err == ESP_ERR_NVS_NOT_INITIALIZED) { + ESP_LOGW("Console", "NVS not initialized, cannot save"); + return; + } + else if (err != ESP_OK) { + ESP_LOGE("Console", "Failed to open NVS: %s", esp_err_to_name(err)); + return; + } + + uint8_t lvl = esp_log_get_default_level(); + nvs_set_u8(h, "global", lvl); + + nvs_set_u8(h, "tagcnt", Tag_Count); + nvs_set_blob(h, "tags", Tag_Table, + Tag_Count * sizeof(tag_entry_t)); + + nvs_commit(h); + nvs_close(h); +} + +static void log_config_load(void) +{ + nvs_handle_t h; + esp_err_t err = nvs_open(LOG_NVS_NS, NVS_READONLY, &h); + + if (err == ESP_ERR_NVS_NOT_INITIALIZED) { + ESP_LOGW("Console", "NVS not initialized, cannot load"); + return; + } + else if (err != ESP_OK) { + ESP_LOGE("Console", "Failed to open NVS: %s", esp_err_to_name(err)); + return; + } + + uint8_t lvl; + if (nvs_get_u8(h, "global", &lvl) == ESP_OK) + { + esp_log_level_set("*", lvl); + Saved_Global_Level = lvl; + } + + uint8_t cnt = 0; + if (nvs_get_u8(h, "tagcnt", &cnt) == ESP_OK && cnt <= MAX_TAGS) + { + size_t sz = cnt * sizeof(tag_entry_t); + if (nvs_get_blob(h, "tags", Tag_Table, &sz) == ESP_OK) + { + Tag_Count = cnt; + for (size_t i = 0; i < Tag_Count; i++) + { + esp_log_level_set(Tag_Table[i].tag, + Tag_Table[i].level); + } + } + } + + nvs_close(h); +} + +static void nvs_clear_tags(void) +{ + nvs_handle_t h; + esp_err_t err = nvs_open(LOG_NVS_NS, NVS_READWRITE, &h); + + if (err == ESP_ERR_NVS_NOT_INITIALIZED) { + ESP_LOGW("Console", "NVS not initialized, cannot clear tags"); + return; + } + else if (err != ESP_OK) { + ESP_LOGE("Console", "Failed to open NVS: %s", esp_err_to_name(err)); + return; + } + + nvs_erase_key(h, "tagcnt"); + nvs_erase_key(h, "tags"); + nvs_commit(h); + nvs_close(h); +} + +static void clear_tag_levels(void) +{ + esp_log_level_t default_level = esp_log_get_default_level(); + + for (size_t i = 0; i < Tag_Count; i++) + { + esp_log_level_set(Tag_Table[i].tag, default_level); + } + Tag_Count = 0; +} + +/* ---------------- Tag table ---------------- */ + +static void set_tag_level(const char *tag, esp_log_level_t level) +{ + for (size_t i = 0; i < Tag_Count; i++) + { + if (!strcmp(Tag_Table[i].tag, tag)) + { + Tag_Table[i].level = level; + return; + } + } + + if (Tag_Count < MAX_TAGS) + { + strncpy(Tag_Table[Tag_Count].tag, tag, MAX_TAGLEN - 1); + Tag_Table[Tag_Count].tag[MAX_TAGLEN - 1] = 0; + Tag_Table[Tag_Count].level = level; + Tag_Count++; + } +} + +/* ---------------- Console command ---------------- */ + +static void print_usage(void) +{ + printf( + "Usage:\n" + " log show\n" + " log clear\n" + " log off | on\n" + " log \n" + " log tag \n" + "Levels: none error warn info debug verbose\n"); +} + +static int cmd_log(int argc, char **argv) +{ + esp_log_level_t level; + + if (argc < 2) + { + print_usage(); + return 0; + } + + if (!strcmp(argv[1], "show")) + { + printf("Global level: %s\n", + level_str(esp_log_get_default_level())); + + if (Tag_Count == 0) + { + printf("No tag overrides\n"); + } + else + { + printf("Tag overrides:\n"); + for (size_t i = 0; i < Tag_Count; i++) + { + printf(" %-10s : %s\n", + Tag_Table[i].tag, + level_str(Tag_Table[i].level)); + } + } + return 0; + } + + if (!strcmp(argv[1], "clear")) + { + clear_tag_levels(); + nvs_clear_tags(); + printf("All tag overrides cleared\n"); + return 0; + } + + if (!strcmp(argv[1], "off")) + { + Saved_Global_Level = esp_log_get_default_level(); + esp_log_level_set("*", ESP_LOG_NONE); + nvs_save(); + printf("Global logging disabled\n"); + return 0; + } + + if (!strcmp(argv[1], "on")) + { + esp_log_level_set("*", Saved_Global_Level); + printf("Global logging restored\n"); + return 0; + } + + if (!strcmp(argv[1], "tag")) + { + if (argc != 4) + { + print_usage(); + return 0; + } + + const char *tag = argv[2]; + const char *lvl = argv[3]; + + if (!strcmp(lvl, "off")) + { + level = ESP_LOG_NONE; + } + else if (!parse_level(lvl, &level)) + { + printf("Invalid level\n"); + return 0; + } + + esp_log_level_set(tag, level); + set_tag_level(tag, level); + nvs_save(); + + printf("Tag '%s' set to %s\n", tag, lvl); + return 0; + } + + if (!parse_level(argv[1], &level)) + { + print_usage(); + return 0; + } + + esp_log_level_set("*", level); + nvs_save(); + printf("Global level set to %s\n", argv[1]); + return 0; +} + +/* ---------------- Registration ---------------- */ + +static void register_log_command(void) +{ + const esp_console_cmd_t cmd = { + .command = "log", + .help = "Control logging levels", + .func = &cmd_log, + }; + + ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); +} + +void Initialize_Console(void) +{ + esp_console_repl_t *repl = NULL; + esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); + repl_config.prompt = "KTag>"; + repl_config.max_cmdline_length = 1024; + + log_config_load(); + register_log_command(); + esp_console_register_help_command(); + + esp_console_dev_uart_config_t hw_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_console_new_repl_uart(&hw_config, &repl_config, &repl)); + ESP_ERROR_CHECK(esp_console_start_repl(repl)); +} \ No newline at end of file diff --git a/components/Console/Console.h b/components/Console/Console.h new file mode 100644 index 0000000..deeb08e --- /dev/null +++ b/components/Console/Console.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 Initialize_Console(void); \ No newline at end of file diff --git a/components/SystemK b/components/SystemK index f80cb59..3b2718e 160000 --- a/components/SystemK +++ b/components/SystemK @@ -1 +1 @@ -Subproject commit f80cb59828aca6f784adcc898aa2603303c5cf2f +Subproject commit 3b2718e6f41070de1db08f9d173de94e90cc372a diff --git a/main/main.c b/main/main.c index 9b0069e..0a7856b 100644 --- a/main/main.c +++ b/main/main.c @@ -48,6 +48,7 @@ #include #include #include +#include #include "nvs_flash.h" #include "HW_NeoPixels.h" #include "Version.h" @@ -82,6 +83,8 @@ void app_main(void) KLOG_ERROR(TAG, "Error initializing NVS: %s", esp_err_to_name(ret)); } + Initialize_Console(); + Initialize_SPIFFS(); Wait_For_System_Event(SYS_SPIFFS_READY, "Timeout initializing SPIFFS!", INITIALIZATION_TIMEOUT_IN_ms); diff --git a/sdkconfig b/sdkconfig index 34cfba1..2b22974 100644 --- a/sdkconfig +++ b/sdkconfig @@ -390,7 +390,7 @@ CONFIG_IDF_TOOLCHAIN_GCC=y CONFIG_IDF_TARGET_ARCH_XTENSA=y CONFIG_IDF_TARGET_ARCH="xtensa" CONFIG_IDF_TARGET="esp32s3" -CONFIG_IDF_INIT_VERSION="5.5.1" +CONFIG_IDF_INIT_VERSION="5.5.2" CONFIG_IDF_TARGET_ESP32S3=y CONFIG_IDF_FIRMWARE_CHIP_ID=0x0009 @@ -998,7 +998,7 @@ CONFIG_BT_ALARM_MAX_NUM=50 # # Console Library # -# CONFIG_CONSOLE_SORTED_HELP is not set +CONFIG_CONSOLE_SORTED_HELP=y # end of Console Library # @@ -1957,14 +1957,14 @@ CONFIG_LOG_DEFAULT_LEVEL_INFO=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=y -# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set -CONFIG_LOG_MAXIMUM_LEVEL=4 +# 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 is not set +CONFIG_LOG_MASTER_LEVEL=y 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 From e47fdd38d4d262cee2785b896ad9b690cee91501 Mon Sep 17 00:00:00 2001 From: Joe Kearney Date: Thu, 8 Jan 2026 21:41:40 -0600 Subject: [PATCH 2/7] WIP: Debug-level logs. --- components/Console/Console.c | 364 +++++++++++++++++++++-------------- components/SystemK | 2 +- sdkconfig | 19 +- 3 files changed, 233 insertions(+), 152 deletions(-) diff --git a/components/Console/Console.c b/components/Console/Console.c index 3289ae2..ea8d457 100644 --- a/components/Console/Console.c +++ b/components/Console/Console.c @@ -1,3 +1,25 @@ +/* + * 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_log.h" #include "nvs.h" @@ -8,8 +30,10 @@ #include "esp_vfs_dev.h" #include #include +#include #define LOG_NVS_NS "logcfg" +#define LOGCFG_VERSION 1 #define MAX_TAGS 16 #define MAX_TAGLEN 16 @@ -65,44 +89,57 @@ static const char *level_str(esp_log_level_t lvl) } } +static void normalize_tag(char *dst, const char *src) +{ + size_t i; + for (i = 0; i < MAX_TAGLEN - 1 && src[i]; i++) + { + //dst[i] = toupper((unsigned char)src[i]); + dst[i] = src[i]; + } + dst[i] = 0; +} + /* ---------------- NVS ---------------- */ static void nvs_save(void) { nvs_handle_t h; esp_err_t err = nvs_open(LOG_NVS_NS, NVS_READWRITE, &h); - - if (err == ESP_ERR_NVS_NOT_INITIALIZED) { - ESP_LOGW("Console", "NVS not initialized, cannot save"); + if (err != ESP_OK) return; - } - else if (err != ESP_OK) { - ESP_LOGE("Console", "Failed to open NVS: %s", esp_err_to_name(err)); - return; - } - - uint8_t lvl = esp_log_get_default_level(); - nvs_set_u8(h, "global", lvl); + nvs_set_u8(h, "ver", LOGCFG_VERSION); + nvs_set_u8(h, "global", esp_log_get_default_level()); nvs_set_u8(h, "tagcnt", Tag_Count); - nvs_set_blob(h, "tags", Tag_Table, - Tag_Count * sizeof(tag_entry_t)); + nvs_set_blob(h, "tags", Tag_Table, Tag_Count * sizeof(tag_entry_t)); nvs_commit(h); nvs_close(h); } +static void nvs_clear_tags(void) +{ + nvs_handle_t h; + if (nvs_open(LOG_NVS_NS, NVS_READWRITE, &h) != ESP_OK) + return; + nvs_erase_key(h, "tagcnt"); + nvs_erase_key(h, "tags"); + nvs_commit(h); + nvs_close(h); +} + static void log_config_load(void) { nvs_handle_t h; - esp_err_t err = nvs_open(LOG_NVS_NS, NVS_READONLY, &h); - - if (err == ESP_ERR_NVS_NOT_INITIALIZED) { - ESP_LOGW("Console", "NVS not initialized, cannot load"); + if (nvs_open(LOG_NVS_NS, NVS_READONLY, &h) != ESP_OK) return; - } - else if (err != ESP_OK) { - ESP_LOGE("Console", "Failed to open NVS: %s", esp_err_to_name(err)); + + uint8_t ver; + if (nvs_get_u8(h, "ver", &ver) != ESP_OK || ver != LOGCFG_VERSION) + { + nvs_close(h); + nvs_clear_tags(); return; } @@ -113,7 +150,7 @@ static void log_config_load(void) Saved_Global_Level = lvl; } - uint8_t cnt = 0; + uint8_t cnt; if (nvs_get_u8(h, "tagcnt", &cnt) == ESP_OK && cnt <= MAX_TAGS) { size_t sz = cnt * sizeof(tag_entry_t); @@ -122,8 +159,7 @@ static void log_config_load(void) Tag_Count = cnt; for (size_t i = 0; i < Tag_Count; i++) { - esp_log_level_set(Tag_Table[i].tag, - Tag_Table[i].level); + esp_log_level_set(Tag_Table[i].tag, Tag_Table[i].level); } } } @@ -131,60 +167,40 @@ static void log_config_load(void) nvs_close(h); } -static void nvs_clear_tags(void) -{ - nvs_handle_t h; - esp_err_t err = nvs_open(LOG_NVS_NS, NVS_READWRITE, &h); - - if (err == ESP_ERR_NVS_NOT_INITIALIZED) { - ESP_LOGW("Console", "NVS not initialized, cannot clear tags"); - return; - } - else if (err != ESP_OK) { - ESP_LOGE("Console", "Failed to open NVS: %s", esp_err_to_name(err)); - return; - } - - nvs_erase_key(h, "tagcnt"); - nvs_erase_key(h, "tags"); - nvs_commit(h); - nvs_close(h); -} +/* ---------------- Tag table ---------------- */ static void clear_tag_levels(void) { - esp_log_level_t default_level = esp_log_get_default_level(); - + esp_log_level_t def = esp_log_get_default_level(); for (size_t i = 0; i < Tag_Count; i++) { - esp_log_level_set(Tag_Table[i].tag, default_level); + esp_log_level_set(Tag_Table[i].tag, def); } Tag_Count = 0; } -/* ---------------- Tag table ---------------- */ - -static void set_tag_level(const char *tag, esp_log_level_t level) +static bool set_tag_level(const char *tag, esp_log_level_t level) { for (size_t i = 0; i < Tag_Count; i++) { if (!strcmp(Tag_Table[i].tag, tag)) { Tag_Table[i].level = level; - return; + return true; } } - if (Tag_Count < MAX_TAGS) - { - strncpy(Tag_Table[Tag_Count].tag, tag, MAX_TAGLEN - 1); - Tag_Table[Tag_Count].tag[MAX_TAGLEN - 1] = 0; - Tag_Table[Tag_Count].level = level; - Tag_Count++; - } + if (Tag_Count >= MAX_TAGS) + return false; + + strncpy(Tag_Table[Tag_Count].tag, tag, MAX_TAGLEN - 1); + Tag_Table[Tag_Count].tag[MAX_TAGLEN - 1] = 0; + Tag_Table[Tag_Count].level = level; + Tag_Count++; + return true; } -/* ---------------- Console command ---------------- */ +/* ---------------- Command helpers ---------------- */ static void print_usage(void) { @@ -192,16 +208,127 @@ static void print_usage(void) "Usage:\n" " log show\n" " log clear\n" + " log reset\n" " log off | on\n" " log \n" - " log tag \n" + " log tag [level|off]\n" "Levels: none error warn info debug verbose\n"); } -static int cmd_log(int argc, char **argv) +static int log_cmd_show(void) +{ + printf("Global level: %s\n", + level_str(esp_log_get_default_level())); + + if (Tag_Count == 0) + { + printf("No tag overrides\n"); + } + else + { + printf("Tag overrides:\n"); + for (size_t i = 0; i < Tag_Count; i++) + { + printf(" %-10s : %s\n", + Tag_Table[i].tag, + level_str(Tag_Table[i].level)); + } + } + return 0; +} + +static int log_cmd_clear(void) +{ + clear_tag_levels(); + nvs_clear_tags(); + printf("All tag overrides cleared\n"); + return 0; +} + +static int log_cmd_reset(void) +{ + esp_log_level_set("*", ESP_LOG_INFO); + Saved_Global_Level = ESP_LOG_INFO; + clear_tag_levels(); + nvs_clear_tags(); + nvs_save(); + printf("Logging reset to defaults\n"); + return 0; +} + +static int log_cmd_off(void) +{ + Saved_Global_Level = esp_log_get_default_level(); + esp_log_level_set("*", ESP_LOG_NONE); + nvs_save(); + printf("Global logging disabled\n"); + return 0; +} + +static int log_cmd_on(void) +{ + esp_log_level_set("*", Saved_Global_Level); + nvs_save(); + printf("Global logging restored\n"); + return 0; +} + +static int log_cmd_tag(int argc, char **argv) +{ + char tag[MAX_TAGLEN]; + normalize_tag(tag, argv[2]); + + if (argc == 3) + { + printf("Tag '%s' is %s\n", + tag, + level_str(esp_log_level_get(tag))); + return 0; + } + + esp_log_level_t level; + if (!strcmp(argv[3], "off")) + { + level = ESP_LOG_NONE; + } + else if (!parse_level(argv[3], &level)) + { + printf("Invalid level\n"); + return 0; + } + + if (!set_tag_level(tag, level)) + { + printf("Tag table full (%d max)\n", MAX_TAGS); + return 0; + } + + esp_log_level_set(tag, level); + nvs_save(); + printf("Tag '%s' set to %s\n", tag, argv[3]); + return 0; +} + +static int log_cmd_set_global(const char *lvl) { esp_log_level_t level; + if (!parse_level(lvl, &level)) + { + print_usage(); + return 0; + } + esp_log_level_set("*", level); + Saved_Global_Level = level; + nvs_save(); + printf("Global level set to %s\n", lvl); + return 0; +} + +/* ---------------- Dispatcher ---------------- */ + +static int cmd_log(int argc, char **argv) +{ if (argc < 2) { print_usage(); @@ -209,96 +336,42 @@ static int cmd_log(int argc, char **argv) } if (!strcmp(argv[1], "show")) - { - printf("Global level: %s\n", - level_str(esp_log_get_default_level())); - - if (Tag_Count == 0) - { - printf("No tag overrides\n"); - } - else - { - printf("Tag overrides:\n"); - for (size_t i = 0; i < Tag_Count; i++) - { - printf(" %-10s : %s\n", - Tag_Table[i].tag, - level_str(Tag_Table[i].level)); - } - } - return 0; - } - + return log_cmd_show(); if (!strcmp(argv[1], "clear")) - { - clear_tag_levels(); - nvs_clear_tags(); - printf("All tag overrides cleared\n"); - return 0; - } - + return log_cmd_clear(); + if (!strcmp(argv[1], "reset")) + return log_cmd_reset(); if (!strcmp(argv[1], "off")) - { - Saved_Global_Level = esp_log_get_default_level(); - esp_log_level_set("*", ESP_LOG_NONE); - nvs_save(); - printf("Global logging disabled\n"); - return 0; - } - + return log_cmd_off(); if (!strcmp(argv[1], "on")) - { - esp_log_level_set("*", Saved_Global_Level); - printf("Global logging restored\n"); - return 0; - } - + return log_cmd_on(); if (!strcmp(argv[1], "tag")) - { - if (argc != 4) - { - print_usage(); - return 0; - } + return log_cmd_tag(argc, argv); - const char *tag = argv[2]; - const char *lvl = argv[3]; - - if (!strcmp(lvl, "off")) - { - level = ESP_LOG_NONE; - } - else if (!parse_level(lvl, &level)) - { - printf("Invalid level\n"); - return 0; - } - - esp_log_level_set(tag, level); - set_tag_level(tag, level); - nvs_save(); - - printf("Tag '%s' set to %s\n", tag, lvl); - return 0; - } - - if (!parse_level(argv[1], &level)) - { - print_usage(); - return 0; - } - - esp_log_level_set("*", level); - nvs_save(); - printf("Global level set to %s\n", argv[1]); - return 0; + return log_cmd_set_global(argv[1]); } /* ---------------- Registration ---------------- */ +static void log_completion(const char *buf, linenoiseCompletions *lc) +{ + if (!strncmp(buf, "log", 3)) + { + linenoiseAddCompletion(lc, "log show"); + linenoiseAddCompletion(lc, "log clear"); + linenoiseAddCompletion(lc, "log reset"); + linenoiseAddCompletion(lc, "log off"); + linenoiseAddCompletion(lc, "log on"); + linenoiseAddCompletion(lc, "log info"); + linenoiseAddCompletion(lc, "log debug"); + linenoiseAddCompletion(lc, "log warn"); + } +} + static void register_log_command(void) { + linenoiseSetCompletionCallback(log_completion); + const esp_console_cmd_t cmd = { .command = "log", .help = "Control logging levels", @@ -311,15 +384,18 @@ static void register_log_command(void) void Initialize_Console(void) { esp_console_repl_t *repl = NULL; - esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); - repl_config.prompt = "KTag>"; - repl_config.max_cmdline_length = 1024; + esp_console_repl_config_t repl_cfg = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); + repl_cfg.prompt = "KTag>"; + repl_cfg.max_cmdline_length = 1024; log_config_load(); register_log_command(); esp_console_register_help_command(); - esp_console_dev_uart_config_t hw_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); - ESP_ERROR_CHECK(esp_console_new_repl_uart(&hw_config, &repl_config, &repl)); + esp_console_dev_uart_config_t hw_cfg = + ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); + + ESP_ERROR_CHECK( + esp_console_new_repl_uart(&hw_cfg, &repl_cfg, &repl)); ESP_ERROR_CHECK(esp_console_start_repl(repl)); -} \ No newline at end of file +} diff --git a/components/SystemK b/components/SystemK index 3b2718e..e62f243 160000 --- a/components/SystemK +++ b/components/SystemK @@ -1 +1 @@ -Subproject commit 3b2718e6f41070de1db08f9d173de94e90cc372a +Subproject commit e62f243e86ab0636121ded3f8197da2a8be40976 diff --git a/sdkconfig b/sdkconfig index 2b22974..03ea0d5 100644 --- a/sdkconfig +++ b/sdkconfig @@ -1952,13 +1952,11 @@ 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=y +# CONFIG_LOG_DEFAULT_LEVEL_INFO is not set # CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set -# 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_DEFAULT_LEVEL_VERBOSE=y +CONFIG_LOG_DEFAULT_LEVEL=5 +CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y CONFIG_LOG_MAXIMUM_LEVEL=5 # @@ -1978,7 +1976,7 @@ CONFIG_LOG_TAG_LEVEL_IMPL_CACHE_SIZE=31 # # Format # -CONFIG_LOG_COLORS=y +# CONFIG_LOG_COLORS is not set CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y # CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set # end of Format @@ -2638,6 +2636,13 @@ CONFIG_KTAG_ANIMATION_STEP_TIME_IN_ms=10 CONFIG_KTAG_T_DEFAULT_START_GAME_in_ms=30000 CONFIG_KTAG_MAX_AUDIO_VOLUME=100 CONFIG_KTAG_MIN_AUDIO_VOLUME=0 +CONFIG_SYSTEMK_LOG_LEVEL=5 +# CONFIG_SYSTEMK_LOG_LEVEL_NONE is not set +# CONFIG_SYSTEMK_LOG_LEVEL_ERROR is not set +# CONFIG_SYSTEMK_LOG_LEVEL_WARN is not set +# CONFIG_SYSTEMK_LOG_LEVEL_INFO is not set +# CONFIG_SYSTEMK_LOG_LEVEL_DEBUG is not set +CONFIG_SYSTEMK_LOG_LEVEL_VERBOSE=y # end of KTag SystemK # From bf3b42204cac442914e6a54450f4e971a52a8ad9 Mon Sep 17 00:00:00 2001 From: Joe Kearney Date: Sat, 10 Jan 2026 13:39:30 -0600 Subject: [PATCH 3/7] Tried to add command history. --- components/Console/Console.c | 1 + sdkconfig | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/components/Console/Console.c b/components/Console/Console.c index ea8d457..8790cb7 100644 --- a/components/Console/Console.c +++ b/components/Console/Console.c @@ -387,6 +387,7 @@ void Initialize_Console(void) esp_console_repl_config_t repl_cfg = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); repl_cfg.prompt = "KTag>"; repl_cfg.max_cmdline_length = 1024; + repl_cfg.max_history_len = 16; log_config_load(); register_log_command(); diff --git a/sdkconfig b/sdkconfig index 03ea0d5..1613bf3 100644 --- a/sdkconfig +++ b/sdkconfig @@ -450,7 +450,7 @@ CONFIG_BOOTLOADER_LOG_LEVEL=3 # # Format # -# CONFIG_BOOTLOADER_LOG_COLORS is not set +CONFIG_BOOTLOADER_LOG_COLORS=y CONFIG_BOOTLOADER_LOG_TIMESTAMP_SOURCE_CPU_TICKS=y # end of Format @@ -1976,7 +1976,7 @@ CONFIG_LOG_TAG_LEVEL_IMPL_CACHE_SIZE=31 # # Format # -# CONFIG_LOG_COLORS is not set +CONFIG_LOG_COLORS=y CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y # CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set # end of Format From 20a8576106fbdff3610a6a15f0eb5b81b17d0dec Mon Sep 17 00:00:00 2001 From: Joe Kearney Date: Sat, 10 Jan 2026 15:25:55 -0600 Subject: [PATCH 4/7] Bugfixes. --- components/Console/Console.c | 50 +++++++++--------------------------- 1 file changed, 12 insertions(+), 38 deletions(-) diff --git a/components/Console/Console.c b/components/Console/Console.c index 8790cb7..4f2be68 100644 --- a/components/Console/Console.c +++ b/components/Console/Console.c @@ -44,11 +44,9 @@ typedef struct } tag_entry_t; static esp_log_level_t Saved_Global_Level = ESP_LOG_INFO; -static tag_entry_t Tag_Table[MAX_TAGS]; +static tag_entry_t Tag_Table[MAX_TAGS] = {0}; static size_t Tag_Count = 0; -/* ---------------- Utility ---------------- */ - static bool parse_level(const char *s, esp_log_level_t *out) { if (!strcmp(s, "none")) @@ -89,19 +87,6 @@ static const char *level_str(esp_log_level_t lvl) } } -static void normalize_tag(char *dst, const char *src) -{ - size_t i; - for (i = 0; i < MAX_TAGLEN - 1 && src[i]; i++) - { - //dst[i] = toupper((unsigned char)src[i]); - dst[i] = src[i]; - } - dst[i] = 0; -} - -/* ---------------- NVS ---------------- */ - static void nvs_save(void) { nvs_handle_t h; @@ -167,8 +152,6 @@ static void log_config_load(void) nvs_close(h); } -/* ---------------- Tag table ---------------- */ - static void clear_tag_levels(void) { esp_log_level_t def = esp_log_get_default_level(); @@ -183,7 +166,7 @@ static bool set_tag_level(const char *tag, esp_log_level_t level) { for (size_t i = 0; i < Tag_Count; i++) { - if (!strcmp(Tag_Table[i].tag, tag)) + if (Tag_Table[i].tag[0] != '\0' && !strcmp(Tag_Table[i].tag, tag)) { Tag_Table[i].level = level; return true; @@ -200,14 +183,11 @@ static bool set_tag_level(const char *tag, esp_log_level_t level) return true; } -/* ---------------- Command helpers ---------------- */ - static void print_usage(void) { printf( "Usage:\n" " log show\n" - " log clear\n" " log reset\n" " log off | on\n" " log \n" @@ -237,14 +217,6 @@ static int log_cmd_show(void) return 0; } -static int log_cmd_clear(void) -{ - clear_tag_levels(); - nvs_clear_tags(); - printf("All tag overrides cleared\n"); - return 0; -} - static int log_cmd_reset(void) { esp_log_level_set("*", ESP_LOG_INFO); @@ -275,8 +247,16 @@ static int log_cmd_on(void) static int log_cmd_tag(int argc, char **argv) { + if (argc < 3) + { + printf("Usage: log tag [level|off]\n"); + return 0; + } + + // Ensure tag is null-terminated and within bounds char tag[MAX_TAGLEN]; - normalize_tag(tag, argv[2]); + strncpy(tag, argv[2], MAX_TAGLEN - 1); + tag[MAX_TAGLEN - 1] = '\0'; if (argc == 3) { @@ -325,8 +305,6 @@ static int log_cmd_set_global(const char *lvl) return 0; } -/* ---------------- Dispatcher ---------------- */ - static int cmd_log(int argc, char **argv) { if (argc < 2) @@ -337,8 +315,6 @@ static int cmd_log(int argc, char **argv) if (!strcmp(argv[1], "show")) return log_cmd_show(); - if (!strcmp(argv[1], "clear")) - return log_cmd_clear(); if (!strcmp(argv[1], "reset")) return log_cmd_reset(); if (!strcmp(argv[1], "off")) @@ -351,8 +327,6 @@ static int cmd_log(int argc, char **argv) return log_cmd_set_global(argv[1]); } -/* ---------------- Registration ---------------- */ - static void log_completion(const char *buf, linenoiseCompletions *lc) { if (!strncmp(buf, "log", 3)) @@ -399,4 +373,4 @@ void Initialize_Console(void) ESP_ERROR_CHECK( esp_console_new_repl_uart(&hw_cfg, &repl_cfg, &repl)); ESP_ERROR_CHECK(esp_console_start_repl(repl)); -} +} \ No newline at end of file From 0272e3a2ab68f69e784cad02a9ea40bbc98e3392 Mon Sep 17 00:00:00 2001 From: Joe Kearney Date: Sat, 10 Jan 2026 15:45:00 -0600 Subject: [PATCH 5/7] Refactored --- components/Console/CMakeLists.txt | 2 + components/Console/Commands/Log_Command.c | 358 ++++++++++++++++++++++ components/Console/Commands/Log_Command.h | 23 ++ components/Console/Console.c | 338 +------------------- 4 files changed, 388 insertions(+), 333 deletions(-) create mode 100644 components/Console/Commands/Log_Command.c create mode 100644 components/Console/Commands/Log_Command.h diff --git a/components/Console/CMakeLists.txt b/components/Console/CMakeLists.txt index ee99750..b4fbae4 100644 --- a/components/Console/CMakeLists.txt +++ b/components/Console/CMakeLists.txt @@ -1,8 +1,10 @@ idf_component_register( SRCS "Console.c" + "Commands/Log_Command.c" INCLUDE_DIRS "." + "./Commands" REQUIRES "SystemK" "System_Events" diff --git a/components/Console/Commands/Log_Command.c b/components/Console/Commands/Log_Command.c new file mode 100644 index 0000000..df5c3d4 --- /dev/null +++ b/components/Console/Commands/Log_Command.c @@ -0,0 +1,358 @@ +/* + * 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_log.h" +#include "nvs.h" +#include "nvs_flash.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "linenoise/linenoise.h" +#include "esp_vfs_dev.h" +#include +#include +#include + +#define LOG_NVS_NS "logcfg" +#define LOGCFG_VERSION 1 +#define MAX_TAGS 16 +#define MAX_TAGLEN 16 + +typedef struct +{ + char tag[MAX_TAGLEN]; + uint8_t level; +} tag_entry_t; + +static esp_log_level_t Saved_Global_Level = ESP_LOG_INFO; +static tag_entry_t Tag_Table[MAX_TAGS] = {0}; +static size_t Tag_Count = 0; + +static bool parse_level(const char *s, esp_log_level_t *out) +{ + if (!strcmp(s, "none")) + *out = ESP_LOG_NONE; + else if (!strcmp(s, "error")) + *out = ESP_LOG_ERROR; + else if (!strcmp(s, "warn")) + *out = ESP_LOG_WARN; + else if (!strcmp(s, "info")) + *out = ESP_LOG_INFO; + else if (!strcmp(s, "debug")) + *out = ESP_LOG_DEBUG; + else if (!strcmp(s, "verbose")) + *out = ESP_LOG_VERBOSE; + else + return false; + return true; +} + +static const char *level_str(esp_log_level_t lvl) +{ + switch (lvl) + { + case ESP_LOG_NONE: + return "none"; + case ESP_LOG_ERROR: + return "error"; + case ESP_LOG_WARN: + return "warn"; + case ESP_LOG_INFO: + return "info"; + case ESP_LOG_DEBUG: + return "debug"; + case ESP_LOG_VERBOSE: + return "verbose"; + default: + return "?"; + } +} + +static void nvs_save(void) +{ + nvs_handle_t h; + esp_err_t err = nvs_open(LOG_NVS_NS, NVS_READWRITE, &h); + if (err != ESP_OK) + return; + + nvs_set_u8(h, "ver", LOGCFG_VERSION); + nvs_set_u8(h, "global", esp_log_get_default_level()); + nvs_set_u8(h, "tagcnt", Tag_Count); + nvs_set_blob(h, "tags", Tag_Table, Tag_Count * sizeof(tag_entry_t)); + + nvs_commit(h); + nvs_close(h); +} + +static void nvs_clear_tags(void) +{ + nvs_handle_t h; + if (nvs_open(LOG_NVS_NS, NVS_READWRITE, &h) != ESP_OK) + return; + nvs_erase_key(h, "tagcnt"); + nvs_erase_key(h, "tags"); + nvs_commit(h); + nvs_close(h); +} + +static void log_config_load(void) +{ + nvs_handle_t h; + if (nvs_open(LOG_NVS_NS, NVS_READONLY, &h) != ESP_OK) + return; + + uint8_t ver; + if (nvs_get_u8(h, "ver", &ver) != ESP_OK || ver != LOGCFG_VERSION) + { + nvs_close(h); + nvs_clear_tags(); + return; + } + + uint8_t lvl; + if (nvs_get_u8(h, "global", &lvl) == ESP_OK) + { + esp_log_level_set("*", lvl); + Saved_Global_Level = lvl; + } + + uint8_t cnt; + if (nvs_get_u8(h, "tagcnt", &cnt) == ESP_OK && cnt <= MAX_TAGS) + { + size_t sz = cnt * sizeof(tag_entry_t); + if (nvs_get_blob(h, "tags", Tag_Table, &sz) == ESP_OK) + { + Tag_Count = cnt; + for (size_t i = 0; i < Tag_Count; i++) + { + esp_log_level_set(Tag_Table[i].tag, Tag_Table[i].level); + } + } + } + + nvs_close(h); +} + +static void clear_tag_levels(void) +{ + esp_log_level_t def = esp_log_get_default_level(); + for (size_t i = 0; i < Tag_Count; i++) + { + esp_log_level_set(Tag_Table[i].tag, def); + } + Tag_Count = 0; +} + +static bool set_tag_level(const char *tag, esp_log_level_t level) +{ + for (size_t i = 0; i < Tag_Count; i++) + { + if (Tag_Table[i].tag[0] != '\0' && !strcmp(Tag_Table[i].tag, tag)) + { + Tag_Table[i].level = level; + return true; + } + } + + if (Tag_Count >= MAX_TAGS) + return false; + + strncpy(Tag_Table[Tag_Count].tag, tag, MAX_TAGLEN - 1); + Tag_Table[Tag_Count].tag[MAX_TAGLEN - 1] = 0; + Tag_Table[Tag_Count].level = level; + Tag_Count++; + return true; +} + +static void print_usage(void) +{ + printf( + "Usage:\n" + " log show\n" + " log reset\n" + " log off | on\n" + " log \n" + " log tag [level|off]\n" + "Levels: none error warn info debug verbose\n"); +} + +static int log_cmd_show(void) +{ + printf("Global level: %s\n", + level_str(esp_log_get_default_level())); + + if (Tag_Count == 0) + { + printf("No tag overrides\n"); + } + else + { + printf("Tag overrides:\n"); + for (size_t i = 0; i < Tag_Count; i++) + { + printf(" %-10s : %s\n", + Tag_Table[i].tag, + level_str(Tag_Table[i].level)); + } + } + return 0; +} + +static int log_cmd_reset(void) +{ + esp_log_level_set("*", ESP_LOG_INFO); + Saved_Global_Level = ESP_LOG_INFO; + clear_tag_levels(); + nvs_clear_tags(); + nvs_save(); + printf("Logging reset to defaults\n"); + return 0; +} + +static int log_cmd_off(void) +{ + Saved_Global_Level = esp_log_get_default_level(); + esp_log_level_set("*", ESP_LOG_NONE); + nvs_save(); + printf("Global logging disabled\n"); + return 0; +} + +static int log_cmd_on(void) +{ + esp_log_level_set("*", Saved_Global_Level); + nvs_save(); + printf("Global logging restored\n"); + return 0; +} + +static int log_cmd_tag(int argc, char **argv) +{ + if (argc < 3) + { + printf("Usage: log tag [level|off]\n"); + return 0; + } + + // Ensure tag is null-terminated and within bounds + char tag[MAX_TAGLEN]; + strncpy(tag, argv[2], MAX_TAGLEN - 1); + tag[MAX_TAGLEN - 1] = '\0'; + + if (argc == 3) + { + printf("Tag '%s' is %s\n", + tag, + level_str(esp_log_level_get(tag))); + return 0; + } + + esp_log_level_t level; + if (!strcmp(argv[3], "off")) + { + level = ESP_LOG_NONE; + } + else if (!parse_level(argv[3], &level)) + { + printf("Invalid level\n"); + return 0; + } + + if (!set_tag_level(tag, level)) + { + printf("Tag table full (%d max)\n", MAX_TAGS); + return 0; + } + + esp_log_level_set(tag, level); + nvs_save(); + printf("Tag '%s' set to %s\n", tag, argv[3]); + return 0; +} + +static int log_cmd_set_global(const char *lvl) +{ + esp_log_level_t level; + if (!parse_level(lvl, &level)) + { + print_usage(); + return 0; + } + + esp_log_level_set("*", level); + Saved_Global_Level = level; + nvs_save(); + printf("Global level set to %s\n", lvl); + return 0; +} + +static int cmd_log(int argc, char **argv) +{ + if (argc < 2) + { + print_usage(); + return 0; + } + + if (!strcmp(argv[1], "show")) + return log_cmd_show(); + if (!strcmp(argv[1], "reset")) + return log_cmd_reset(); + if (!strcmp(argv[1], "off")) + return log_cmd_off(); + if (!strcmp(argv[1], "on")) + return log_cmd_on(); + if (!strcmp(argv[1], "tag")) + return log_cmd_tag(argc, argv); + + return log_cmd_set_global(argv[1]); +} + +static void log_completion(const char *buf, linenoiseCompletions *lc) +{ + if (!strncmp(buf, "log", 3)) + { + linenoiseAddCompletion(lc, "log show"); + linenoiseAddCompletion(lc, "log clear"); + linenoiseAddCompletion(lc, "log reset"); + linenoiseAddCompletion(lc, "log off"); + linenoiseAddCompletion(lc, "log on"); + linenoiseAddCompletion(lc, "log info"); + linenoiseAddCompletion(lc, "log debug"); + linenoiseAddCompletion(lc, "log warn"); + } +} + +void Register_Log_Command(void) +{ + log_config_load(); + + linenoiseSetCompletionCallback(log_completion); + + const esp_console_cmd_t cmd = { + .command = "log", + .help = "Control logging levels", + .func = &cmd_log, + }; + + ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); +} diff --git a/components/Console/Commands/Log_Command.h b/components/Console/Commands/Log_Command.h new file mode 100644 index 0000000..c82db17 --- /dev/null +++ b/components/Console/Commands/Log_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_Log_Command(void); \ No newline at end of file diff --git a/components/Console/Console.c b/components/Console/Console.c index 4f2be68..0afef82 100644 --- a/components/Console/Console.c +++ b/components/Console/Console.c @@ -21,338 +21,12 @@ */ #include "esp_console.h" -#include "esp_log.h" -#include "nvs.h" -#include "nvs_flash.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "linenoise/linenoise.h" -#include "esp_vfs_dev.h" -#include -#include -#include +#include -#define LOG_NVS_NS "logcfg" -#define LOGCFG_VERSION 1 -#define MAX_TAGS 16 -#define MAX_TAGLEN 16 - -typedef struct +static void register_commands() { - char tag[MAX_TAGLEN]; - uint8_t level; -} tag_entry_t; - -static esp_log_level_t Saved_Global_Level = ESP_LOG_INFO; -static tag_entry_t Tag_Table[MAX_TAGS] = {0}; -static size_t Tag_Count = 0; - -static bool parse_level(const char *s, esp_log_level_t *out) -{ - if (!strcmp(s, "none")) - *out = ESP_LOG_NONE; - else if (!strcmp(s, "error")) - *out = ESP_LOG_ERROR; - else if (!strcmp(s, "warn")) - *out = ESP_LOG_WARN; - else if (!strcmp(s, "info")) - *out = ESP_LOG_INFO; - else if (!strcmp(s, "debug")) - *out = ESP_LOG_DEBUG; - else if (!strcmp(s, "verbose")) - *out = ESP_LOG_VERBOSE; - else - return false; - return true; -} - -static const char *level_str(esp_log_level_t lvl) -{ - switch (lvl) - { - case ESP_LOG_NONE: - return "none"; - case ESP_LOG_ERROR: - return "error"; - case ESP_LOG_WARN: - return "warn"; - case ESP_LOG_INFO: - return "info"; - case ESP_LOG_DEBUG: - return "debug"; - case ESP_LOG_VERBOSE: - return "verbose"; - default: - return "?"; - } -} - -static void nvs_save(void) -{ - nvs_handle_t h; - esp_err_t err = nvs_open(LOG_NVS_NS, NVS_READWRITE, &h); - if (err != ESP_OK) - return; - - nvs_set_u8(h, "ver", LOGCFG_VERSION); - nvs_set_u8(h, "global", esp_log_get_default_level()); - nvs_set_u8(h, "tagcnt", Tag_Count); - nvs_set_blob(h, "tags", Tag_Table, Tag_Count * sizeof(tag_entry_t)); - - nvs_commit(h); - nvs_close(h); -} - -static void nvs_clear_tags(void) -{ - nvs_handle_t h; - if (nvs_open(LOG_NVS_NS, NVS_READWRITE, &h) != ESP_OK) - return; - nvs_erase_key(h, "tagcnt"); - nvs_erase_key(h, "tags"); - nvs_commit(h); - nvs_close(h); -} - -static void log_config_load(void) -{ - nvs_handle_t h; - if (nvs_open(LOG_NVS_NS, NVS_READONLY, &h) != ESP_OK) - return; - - uint8_t ver; - if (nvs_get_u8(h, "ver", &ver) != ESP_OK || ver != LOGCFG_VERSION) - { - nvs_close(h); - nvs_clear_tags(); - return; - } - - uint8_t lvl; - if (nvs_get_u8(h, "global", &lvl) == ESP_OK) - { - esp_log_level_set("*", lvl); - Saved_Global_Level = lvl; - } - - uint8_t cnt; - if (nvs_get_u8(h, "tagcnt", &cnt) == ESP_OK && cnt <= MAX_TAGS) - { - size_t sz = cnt * sizeof(tag_entry_t); - if (nvs_get_blob(h, "tags", Tag_Table, &sz) == ESP_OK) - { - Tag_Count = cnt; - for (size_t i = 0; i < Tag_Count; i++) - { - esp_log_level_set(Tag_Table[i].tag, Tag_Table[i].level); - } - } - } - - nvs_close(h); -} - -static void clear_tag_levels(void) -{ - esp_log_level_t def = esp_log_get_default_level(); - for (size_t i = 0; i < Tag_Count; i++) - { - esp_log_level_set(Tag_Table[i].tag, def); - } - Tag_Count = 0; -} - -static bool set_tag_level(const char *tag, esp_log_level_t level) -{ - for (size_t i = 0; i < Tag_Count; i++) - { - if (Tag_Table[i].tag[0] != '\0' && !strcmp(Tag_Table[i].tag, tag)) - { - Tag_Table[i].level = level; - return true; - } - } - - if (Tag_Count >= MAX_TAGS) - return false; - - strncpy(Tag_Table[Tag_Count].tag, tag, MAX_TAGLEN - 1); - Tag_Table[Tag_Count].tag[MAX_TAGLEN - 1] = 0; - Tag_Table[Tag_Count].level = level; - Tag_Count++; - return true; -} - -static void print_usage(void) -{ - printf( - "Usage:\n" - " log show\n" - " log reset\n" - " log off | on\n" - " log \n" - " log tag [level|off]\n" - "Levels: none error warn info debug verbose\n"); -} - -static int log_cmd_show(void) -{ - printf("Global level: %s\n", - level_str(esp_log_get_default_level())); - - if (Tag_Count == 0) - { - printf("No tag overrides\n"); - } - else - { - printf("Tag overrides:\n"); - for (size_t i = 0; i < Tag_Count; i++) - { - printf(" %-10s : %s\n", - Tag_Table[i].tag, - level_str(Tag_Table[i].level)); - } - } - return 0; -} - -static int log_cmd_reset(void) -{ - esp_log_level_set("*", ESP_LOG_INFO); - Saved_Global_Level = ESP_LOG_INFO; - clear_tag_levels(); - nvs_clear_tags(); - nvs_save(); - printf("Logging reset to defaults\n"); - return 0; -} - -static int log_cmd_off(void) -{ - Saved_Global_Level = esp_log_get_default_level(); - esp_log_level_set("*", ESP_LOG_NONE); - nvs_save(); - printf("Global logging disabled\n"); - return 0; -} - -static int log_cmd_on(void) -{ - esp_log_level_set("*", Saved_Global_Level); - nvs_save(); - printf("Global logging restored\n"); - return 0; -} - -static int log_cmd_tag(int argc, char **argv) -{ - if (argc < 3) - { - printf("Usage: log tag [level|off]\n"); - return 0; - } - - // Ensure tag is null-terminated and within bounds - char tag[MAX_TAGLEN]; - strncpy(tag, argv[2], MAX_TAGLEN - 1); - tag[MAX_TAGLEN - 1] = '\0'; - - if (argc == 3) - { - printf("Tag '%s' is %s\n", - tag, - level_str(esp_log_level_get(tag))); - return 0; - } - - esp_log_level_t level; - if (!strcmp(argv[3], "off")) - { - level = ESP_LOG_NONE; - } - else if (!parse_level(argv[3], &level)) - { - printf("Invalid level\n"); - return 0; - } - - if (!set_tag_level(tag, level)) - { - printf("Tag table full (%d max)\n", MAX_TAGS); - return 0; - } - - esp_log_level_set(tag, level); - nvs_save(); - printf("Tag '%s' set to %s\n", tag, argv[3]); - return 0; -} - -static int log_cmd_set_global(const char *lvl) -{ - esp_log_level_t level; - if (!parse_level(lvl, &level)) - { - print_usage(); - return 0; - } - - esp_log_level_set("*", level); - Saved_Global_Level = level; - nvs_save(); - printf("Global level set to %s\n", lvl); - return 0; -} - -static int cmd_log(int argc, char **argv) -{ - if (argc < 2) - { - print_usage(); - return 0; - } - - if (!strcmp(argv[1], "show")) - return log_cmd_show(); - if (!strcmp(argv[1], "reset")) - return log_cmd_reset(); - if (!strcmp(argv[1], "off")) - return log_cmd_off(); - if (!strcmp(argv[1], "on")) - return log_cmd_on(); - if (!strcmp(argv[1], "tag")) - return log_cmd_tag(argc, argv); - - return log_cmd_set_global(argv[1]); -} - -static void log_completion(const char *buf, linenoiseCompletions *lc) -{ - if (!strncmp(buf, "log", 3)) - { - linenoiseAddCompletion(lc, "log show"); - linenoiseAddCompletion(lc, "log clear"); - linenoiseAddCompletion(lc, "log reset"); - linenoiseAddCompletion(lc, "log off"); - linenoiseAddCompletion(lc, "log on"); - linenoiseAddCompletion(lc, "log info"); - linenoiseAddCompletion(lc, "log debug"); - linenoiseAddCompletion(lc, "log warn"); - } -} - -static void register_log_command(void) -{ - linenoiseSetCompletionCallback(log_completion); - - const esp_console_cmd_t cmd = { - .command = "log", - .help = "Control logging levels", - .func = &cmd_log, - }; - - ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); + Register_Log_Command(); + esp_console_register_help_command(); } void Initialize_Console(void) @@ -363,9 +37,7 @@ void Initialize_Console(void) repl_cfg.max_cmdline_length = 1024; repl_cfg.max_history_len = 16; - log_config_load(); - register_log_command(); - esp_console_register_help_command(); + register_commands(); esp_console_dev_uart_config_t hw_cfg = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); From d87ac6451d95936b4c8069a25d60bc9f93a30428 Mon Sep 17 00:00:00 2001 From: Joe Kearney Date: Sat, 10 Jan 2026 16:07:28 -0600 Subject: [PATCH 6/7] Reworked log levels. --- components/Audio/I2S_Audio.c | 2 +- components/IR/IR.c | 2 +- components/SystemK | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/Audio/I2S_Audio.c b/components/Audio/I2S_Audio.c index 007528c..0601fbf 100644 --- a/components/Audio/I2S_Audio.c +++ b/components/Audio/I2S_Audio.c @@ -91,7 +91,7 @@ static esp_err_t I2S_Audio_Write(void *audio_buffer, size_t len, size_t *bytes_w static esp_err_t I2S_Audio_Reconfigure_Clock(uint32_t rate, uint32_t bits_cfg, i2s_slot_mode_t ch) { - KLOG_INFO(TAG, "Reconfiguring clock for %lu sps, %lu bps, %d channels.", rate, bits_cfg, ch); + KLOG_DEBUG(TAG, "Reconfiguring clock for %lu sps, %lu bps, %d channels.", rate, bits_cfg, ch); esp_err_t ret = ESP_OK; i2s_std_config_t std_cfg = { diff --git a/components/IR/IR.c b/components/IR/IR.c index e4e4e67..4fc752a 100644 --- a/components/IR/IR.c +++ b/components/IR/IR.c @@ -384,7 +384,7 @@ static inline void PrintPulseTrainToConsole(TimedPulseTrain_T *train) { for (uint_fast16_t i = 0; i < train->count; i += 2) { - KLOG_INFO(TAG, "%2d: (%d, %4d) (%d, %4d)", i + 1, train->bitstream[i].symbol, train->bitstream[i].duration, train->bitstream[i + 1].symbol, train->bitstream[i + 1].duration); + KLOG_DEBUG(TAG, "%2d: (%d, %4d) (%d, %4d)", i + 1, train->bitstream[i].symbol, train->bitstream[i].duration, train->bitstream[i + 1].symbol, train->bitstream[i + 1].duration); vTaskDelay(pdMS_TO_TICKS(10)); } } diff --git a/components/SystemK b/components/SystemK index e62f243..3d87f2b 160000 --- a/components/SystemK +++ b/components/SystemK @@ -1 +1 @@ -Subproject commit e62f243e86ab0636121ded3f8197da2a8be40976 +Subproject commit 3d87f2b53070b181d9811f19daf606d5896e3932 From 65c33a00fcf9c7b460748d73d770789ce4b0cbd1 Mon Sep 17 00:00:00 2001 From: Joe Kearney Date: Sat, 10 Jan 2026 16:27:57 -0600 Subject: [PATCH 7/7] Repin SystemK --- components/SystemK | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/SystemK b/components/SystemK index 3d87f2b..c4350eb 160000 --- a/components/SystemK +++ b/components/SystemK @@ -1 +1 @@ -Subproject commit 3d87f2b53070b181d9811f19daf606d5896e3932 +Subproject commit c4350ebd2700a7d52f84b3783f945ddf4ac54963