From a30ea5429fc1a4f26d3e8f451b5d26e8d8ff15af Mon Sep 17 00:00:00 2001 From: Rasmus Date: Mon, 14 Sep 2026 00:02:59 +0200 Subject: [PATCH] Settings: disable onboard LED --- main/CMakeLists.txt | 1 + main/board_led.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ main/board_led.h | 27 +++++++++++++++++++++ main/hw_pins.h | 5 +++- main/main.c | 4 ++++ main/ui_task.c | 37 +++++++++++++++++++++-------- 6 files changed, 120 insertions(+), 11 deletions(-) create mode 100644 main/board_led.c create mode 100644 main/board_led.h diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 9bd74ac..8ce4e3f 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -12,5 +12,6 @@ idf_component_register(SRCS "app_state.c" "ota_manager.c" "dns_server.c" + "board_led.c" INCLUDE_DIRS "." ) \ No newline at end of file diff --git a/main/board_led.c b/main/board_led.c new file mode 100644 index 0000000..d23b182 --- /dev/null +++ b/main/board_led.c @@ -0,0 +1,57 @@ +#include "board_led.h" +#include "hw_pins.h" +#include "driver/gpio.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include "nvs.h" + +static const char *TAG = "board_led"; +static bool s_led_enabled = false; + +esp_err_t board_led_init(void) +{ + /* Configure GPIO */ + gpio_config_t io_conf = { + .pin_bit_mask = (1ULL << HW_STATUS_LED_GPIO), + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE, + }; + gpio_config(&io_conf); + + /* Load persisted preference from NVS (default: false / OFF) */ + nvs_handle_t h; + if (nvs_open("mtg_cfg", NVS_READONLY, &h) == ESP_OK) { + uint8_t val = 0; + if (nvs_get_u8(h, "led_en", &val) == ESP_OK) { + s_led_enabled = (val != 0); + } + nvs_close(h); + } + + gpio_set_level(HW_STATUS_LED_GPIO, s_led_enabled ? 1 : 0); + ESP_LOGI(TAG, "Onboard status LED initialized on GPIO %d (state: %s)", + HW_STATUS_LED_GPIO, s_led_enabled ? "ON" : "OFF"); + return ESP_OK; +} + +bool board_led_get_enabled(void) +{ + return s_led_enabled; +} + +void board_led_set_enabled(bool enabled) +{ + s_led_enabled = enabled; + gpio_set_level(HW_STATUS_LED_GPIO, s_led_enabled ? 1 : 0); + + /* Persist to NVS */ + nvs_handle_t h; + if (nvs_open("mtg_cfg", NVS_READWRITE, &h) == ESP_OK) { + nvs_set_u8(h, "led_en", enabled ? 1 : 0); + nvs_commit(h); + nvs_close(h); + } + ESP_LOGI(TAG, "Onboard status LED set to %s", enabled ? "ON" : "OFF"); +} diff --git a/main/board_led.h b/main/board_led.h new file mode 100644 index 0000000..ef79105 --- /dev/null +++ b/main/board_led.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize onboard LED GPIO and apply saved NVS state (default: OFF). + */ +esp_err_t board_led_init(void); + +/** + * @brief Get current onboard LED enabled state. + */ +bool board_led_get_enabled(void); + +/** + * @brief Set onboard LED state and persist to NVS. + */ +void board_led_set_enabled(bool enabled); + +#ifdef __cplusplus +} +#endif diff --git a/main/hw_pins.h b/main/hw_pins.h index 54d7a6c..2aea12d 100644 --- a/main/hw_pins.h +++ b/main/hw_pins.h @@ -47,4 +47,7 @@ #define HW_ENC_SW_GPIO (GPIO_NUM_25) /* Piezo buzzer */ -#define HW_BUZZER_GPIO (GPIO_NUM_14) \ No newline at end of file +#define HW_BUZZER_GPIO (GPIO_NUM_14) + +/* Onboard status LED (GPIO 2 on standard ESP32 DevKit boards) */ +#define HW_STATUS_LED_GPIO (GPIO_NUM_2) \ No newline at end of file diff --git a/main/main.c b/main/main.c index 1519924..eb74dea 100644 --- a/main/main.c +++ b/main/main.c @@ -10,6 +10,7 @@ #include "scryfall_client.h" #include "web_server.h" #include "ota_manager.h" +#include "board_led.h" static const char *TAG = "MAIN"; @@ -17,6 +18,9 @@ void app_main(void) { ESP_LOGI(TAG, "MTG RFID Companion booting..."); + /* Initialize onboard status LED early (turns off red LED per user setting) */ + board_led_init(); + /* Validate OTA partition & cancel rollback if just updated */ ota_manager_init(); diff --git a/main/ui_task.c b/main/ui_task.c index 3219e21..819bc7b 100644 --- a/main/ui_task.c +++ b/main/ui_task.c @@ -21,6 +21,7 @@ #include "buzzer.h" #include "jpeg_decoder.h" #include "ota_manager.h" +#include "board_led.h" #include "ui_task.h" static const char *TAG = "ui"; @@ -55,14 +56,15 @@ static const char *s_menu_labels[MAIN_MENU_ITEM_COUNT] = { "6. SETTINGS & TOOLS" }; -#define SETTINGS_MENU_ITEM_COUNT 5 +#define SETTINGS_MENU_ITEM_COUNT 6 static int s_settings_idx = 0; static const char *s_settings_labels[SETTINGS_MENU_ITEM_COUNT] = { "< BACK TO MAIN MENU", "1. AUDIO: CHIPTUNE", - "2. DECK STORAGE", - "3. DEVICE & WIFI INFO", - "4. UPDATE FIRMWARE" + "2. RED LED: OFF", + "3. DECK STORAGE", + "4. DEVICE & WIFI INFO", + "5. UPDATE FIRMWARE" }; /* Life & Counters */ @@ -381,9 +383,12 @@ static void view_settings_menu(void) char audio_lbl_buf[36]; snprintf(audio_lbl_buf, sizeof(audio_lbl_buf), "1. AUDIO: %s", buzzer_get_profile_name(buzzer_get_profile())); - int start_y = 50; + char led_lbl_buf[36]; + snprintf(led_lbl_buf, sizeof(led_lbl_buf), "2. RED LED: %s", board_led_get_enabled() ? "ON" : "OFF"); + + int start_y = 44; int row_height = 34; - int row_gap = 8; + int row_gap = 7; for (int i = 0; i < SETTINGS_MENU_ITEM_COUNT; i++) { bool selected = (i == s_settings_idx); @@ -404,7 +409,12 @@ static void view_settings_menu(void) lv_obj_set_style_border_width(item_box, 1, 0); } - const char *item_txt = (i == 1) ? audio_lbl_buf : s_settings_labels[i]; + const char *item_txt = s_settings_labels[i]; + if (i == 1) { + item_txt = audio_lbl_buf; + } else if (i == 2) { + item_txt = led_lbl_buf; + } lv_obj_t *lbl = lv_label_create(item_box); if (i == 0) { /* Back button item */ @@ -2020,17 +2030,24 @@ static void handle_encoder_click(void) view_settings_menu(); break; } - case 2: /* DECK STORAGE */ + case 2: { /* RED LED inline toggle */ + bool new_state = !board_led_get_enabled(); + board_led_set_enabled(new_state); + buzzer_sound_tick(); + view_settings_menu(); + break; + } + case 3: /* DECK STORAGE */ app_set_view(APP_STATE_STORAGE_MANAGER); s_storage_confirm_dialog = false; s_storage_option_idx = 0; view_storage(); break; - case 3: /* DEVICE & WIFI INFO */ + case 4: /* DEVICE & WIFI INFO */ app_set_view(APP_STATE_DEVICE_INFO); view_device_info(); break; - case 4: /* UPDATE FIRMWARE */ + case 5: /* UPDATE FIRMWARE */ app_set_view(APP_STATE_OTA_UPDATE); buzzer_chirp(988, 40); ota_manager_check_update_async();