/** * @file control.c * @brief Control module implementation */ #include "control.h" #include "led.h" #include "rcsignal.h" #include "localbtn.h" #include "animation.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_log.h" #include "esp_system.h" #include "nvs_flash.h" #include "nvs.h" #include "esp_timer.h" #include static const char *TAG = "CONTROL"; #define NVS_NAMESPACE "led_ctrl" #define CONFIG_MAGIC 0xDEADBEEF #define DEFAULT_NUM_LEDS_A 7 #define DEFAULT_NUM_LEDS_B 7 // Global state static controller_config_t current_config = { .led_pin_strip_a = -1, .led_pin_strip_b = -1, .pwm_pin = -1, .magic = CONFIG_MAGIC}; static uint8_t current_animation_mode = 0; // Forward declarations static void on_mode_change(uint8_t new_mode); // NVS Functions static esp_err_t load_config_from_nvs(void) { nvs_handle_t nvs_handle; esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &nvs_handle); if (err != ESP_OK) { ESP_LOGW(TAG, "NVS not found, using defaults"); return ESP_ERR_NOT_FOUND; } size_t required_size = sizeof(controller_config_t); err = nvs_get_blob(nvs_handle, "config", ¤t_config, &required_size); nvs_close(nvs_handle); if (err != ESP_OK || current_config.magic != CONFIG_MAGIC) { ESP_LOGW(TAG, "Invalid config in NVS, using defaults"); return ESP_ERR_INVALID_STATE; } ESP_LOGI(TAG, "Loaded config from NVS"); ESP_LOGI(TAG, " Strip A: GPIO%d", current_config.led_pin_strip_a); ESP_LOGI(TAG, " Strip B: GPIO%d", current_config.led_pin_strip_b); ESP_LOGI(TAG, " PWM Pin: GPIO%d", current_config.pwm_pin); return ESP_OK; } static esp_err_t save_config_to_nvs(void) { nvs_handle_t nvs_handle; esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle); if (err != ESP_OK) { return err; } current_config.magic = CONFIG_MAGIC; err = nvs_set_blob(nvs_handle, "config", ¤t_config, sizeof(controller_config_t)); if (err == ESP_OK) { err = nvs_commit(nvs_handle); } nvs_close(nvs_handle); if (err == ESP_OK) { ESP_LOGI(TAG, "Config saved to NVS"); } else { ESP_LOGE(TAG, "Failed to save config: %s", esp_err_to_name(err)); } return err; } esp_err_t control_reset_config(void) { current_config.led_pin_strip_a = 12; current_config.led_pin_strip_b = 14; current_config.pwm_pin = 13; current_config.magic = CONFIG_MAGIC; return save_config_to_nvs(); } const controller_config_t *control_get_config(void) { return ¤t_config; } esp_err_t control_update_config(const controller_config_t *config) { if (!config) { return ESP_ERR_INVALID_ARG; } // Reinitialize if pins changed bool pins_changed = (current_config.led_pin_strip_a != config->led_pin_strip_a) || (current_config.led_pin_strip_b != config->led_pin_strip_b) || (current_config.pwm_pin != config->pwm_pin); memcpy(¤t_config, config, sizeof(controller_config_t)); esp_err_t err = save_config_to_nvs(); if (err == ESP_OK && pins_changed) { ESP_LOGI(TAG, "Restarting to apply new pin configuration..."); vTaskDelay(pdMS_TO_TICKS(1000)); esp_restart(); } return err; } // Animation mode change callback static void on_mode_change(uint8_t new_mode) { current_animation_mode = new_mode; animation_set_mode((animation_mode_t)new_mode); } void control_set_animation_mode(uint8_t mode) { if (mode >= ANIM_MODE_COUNT) { mode = 0; } on_mode_change(mode); } uint8_t control_get_animation_mode(void) { return current_animation_mode; } void control_emulate_pwm_pulse(void) { rcsignal_trigger_mode_change(); } // Main initialization esp_err_t control_init(void) { esp_err_t ret; ESP_LOGI(TAG, "Initializing LED Controller..."); // Initialize NVS ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK(ret); // Load configuration load_config_from_nvs(); // Initialize LED strips ret = led_init(current_config.led_pin_strip_a, current_config.led_pin_strip_b, DEFAULT_NUM_LEDS_A, DEFAULT_NUM_LEDS_B); if (ret != ESP_OK) { ESP_LOGE(TAG, "LED init failed: %s", esp_err_to_name(ret)); return ret; } // Initialize animation system ret = animation_init(); if (ret != ESP_OK) { ESP_LOGE(TAG, "Animation init failed: %s", esp_err_to_name(ret)); return ret; } // Initialize RC signal ret = rcsignal_init(current_config.pwm_pin); if (ret != ESP_OK) { ESP_LOGE(TAG, "RC signal init failed: %s", esp_err_to_name(ret)); return ret; } // Initialize local BTN ret = localbtn_init(); if (ret != ESP_OK) { ESP_LOGE(TAG, "Local BTN init failed: %s", esp_err_to_name(ret)); return ret; } // Register mode change callback rcsignal_register_callback(on_mode_change); localbtn_register_callback(on_mode_change); ESP_LOGI(TAG, "Control system initialized successfully"); return ESP_OK; }