refactor #12
@ -1,2 +1,2 @@
|
|||||||
idf_component_register(SRCS "maxxfan-controller.c" "motor_control.c"
|
idf_component_register(SRCS "maxxfan-controller.c" "motor_control.c" "state_manager.c"
|
||||||
INCLUDE_DIRS ".")
|
INCLUDE_DIRS ".")
|
||||||
@ -9,13 +9,13 @@
|
|||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_http_server.h"
|
#include "esp_http_server.h"
|
||||||
#include "esp_task_wdt.h"
|
#include "esp_task_wdt.h"
|
||||||
#include "nvs_flash.h"
|
|
||||||
#include "nvs.h"
|
#include "nvs.h"
|
||||||
#include "cJSON.h"
|
#include "cJSON.h"
|
||||||
|
|
||||||
// Project modules
|
// Project modules
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "motor_control.h"
|
#include "motor_control.h"
|
||||||
|
#include "state_manager.h"
|
||||||
|
|
||||||
// WiFi event group
|
// WiFi event group
|
||||||
static EventGroupHandle_t s_wifi_event_group;
|
static EventGroupHandle_t s_wifi_event_group;
|
||||||
@ -84,11 +84,6 @@ static const char* html_page =
|
|||||||
"function startUpdates(){if(updateInterval)clearInterval(updateInterval);updateInterval=setInterval(getStatus,1000)}"
|
"function startUpdates(){if(updateInterval)clearInterval(updateInterval);updateInterval=setInterval(getStatus,1000)}"
|
||||||
"document.addEventListener('DOMContentLoaded',function(){getStatus();startUpdates()})</script></body></html>";
|
"document.addEventListener('DOMContentLoaded',function(){getStatus();startUpdates()})</script></body></html>";
|
||||||
|
|
||||||
// Forward declarations
|
|
||||||
static esp_err_t save_motor_state_to_nvs(void);
|
|
||||||
static esp_err_t load_motor_state_from_nvs(void);
|
|
||||||
static bool is_watchdog_reset(void);
|
|
||||||
|
|
||||||
// Initialize watchdog timer
|
// Initialize watchdog timer
|
||||||
void init_watchdog(void) {
|
void init_watchdog(void) {
|
||||||
ESP_LOGI(SYSTEM_TAG, "Setting up watchdog monitoring...");
|
ESP_LOGI(SYSTEM_TAG, "Setting up watchdog monitoring...");
|
||||||
@ -117,165 +112,6 @@ void feed_watchdog(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this was a watchdog reset
|
|
||||||
static bool is_watchdog_reset(void) {
|
|
||||||
esp_reset_reason_t reset_reason = esp_reset_reason();
|
|
||||||
|
|
||||||
// Only consider TASK_WDT and INT_WDT as true watchdog resets
|
|
||||||
// ESP_RST_WDT can be triggered by power disconnection, so we exclude it
|
|
||||||
return (reset_reason == ESP_RST_TASK_WDT ||
|
|
||||||
reset_reason == ESP_RST_INT_WDT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save motor state to NVS
|
|
||||||
static esp_err_t save_motor_state_to_nvs(void) {
|
|
||||||
nvs_handle_t nvs_handle;
|
|
||||||
esp_err_t err;
|
|
||||||
|
|
||||||
err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
ESP_LOGE(SYSTEM_TAG, "Error opening NVS handle: %s", esp_err_to_name(err));
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get current motor state
|
|
||||||
const motor_state_t* state = motor_get_state();
|
|
||||||
motor_mode_t last_on_mode;
|
|
||||||
int last_on_speed;
|
|
||||||
motor_get_last_on_state(&last_on_mode, &last_on_speed);
|
|
||||||
bool user_turned_off = motor_get_user_turned_off();
|
|
||||||
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "=== SAVING STATE TO NVS ===");
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "Mode: %d, Speed: %d%%, Last ON: %d@%d%%, User OFF: %s",
|
|
||||||
state->mode, state->target_speed,
|
|
||||||
last_on_mode, last_on_speed,
|
|
||||||
user_turned_off ? "YES" : "NO");
|
|
||||||
|
|
||||||
// Save current motor state
|
|
||||||
err = nvs_set_u8(nvs_handle, NVS_KEY_MODE, (uint8_t)state->mode);
|
|
||||||
if (err == ESP_OK) {
|
|
||||||
err = nvs_set_u8(nvs_handle, NVS_KEY_SPEED, (uint8_t)state->target_speed);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save last ON state
|
|
||||||
if (err == ESP_OK) {
|
|
||||||
err = nvs_set_u8(nvs_handle, NVS_KEY_LAST_ON_MODE, (uint8_t)last_on_mode);
|
|
||||||
}
|
|
||||||
if (err == ESP_OK) {
|
|
||||||
err = nvs_set_u8(nvs_handle, NVS_KEY_LAST_ON_SPEED, (uint8_t)last_on_speed);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save power state (whether user turned off manually)
|
|
||||||
if (err == ESP_OK) {
|
|
||||||
err = nvs_set_u8(nvs_handle, NVS_KEY_POWER_STATE, user_turned_off ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err == ESP_OK) {
|
|
||||||
err = nvs_commit(nvs_handle);
|
|
||||||
if (err == ESP_OK) {
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "✓ Motor state successfully saved to NVS");
|
|
||||||
} else {
|
|
||||||
ESP_LOGE(SYSTEM_TAG, "✗ NVS commit failed: %s", esp_err_to_name(err));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ESP_LOGE(SYSTEM_TAG, "✗ Error saving to NVS: %s", esp_err_to_name(err));
|
|
||||||
}
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "===========================");
|
|
||||||
|
|
||||||
nvs_close(nvs_handle);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load motor state from NVS
|
|
||||||
static esp_err_t load_motor_state_from_nvs(void) {
|
|
||||||
nvs_handle_t nvs_handle;
|
|
||||||
esp_err_t err;
|
|
||||||
|
|
||||||
err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &nvs_handle);
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "NVS not found, using default state");
|
|
||||||
return ESP_ERR_NVS_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t stored_mode = 0;
|
|
||||||
uint8_t stored_speed = 0;
|
|
||||||
uint8_t stored_last_mode = 1; // Default to MOTOR_EXHAUST
|
|
||||||
uint8_t stored_last_speed = 50;
|
|
||||||
uint8_t stored_power_state = 0;
|
|
||||||
|
|
||||||
// Load current motor state
|
|
||||||
err = nvs_get_u8(nvs_handle, NVS_KEY_MODE, &stored_mode);
|
|
||||||
if (err == ESP_OK) {
|
|
||||||
nvs_get_u8(nvs_handle, NVS_KEY_SPEED, &stored_speed);
|
|
||||||
nvs_get_u8(nvs_handle, NVS_KEY_LAST_ON_MODE, &stored_last_mode);
|
|
||||||
nvs_get_u8(nvs_handle, NVS_KEY_LAST_ON_SPEED, &stored_last_speed);
|
|
||||||
nvs_get_u8(nvs_handle, NVS_KEY_POWER_STATE, &stored_power_state);
|
|
||||||
|
|
||||||
// Validate ranges using config macros
|
|
||||||
if (stored_mode > MOTOR_INTAKE) stored_mode = MOTOR_OFF;
|
|
||||||
if (!IS_VALID_SPEED(stored_speed)) stored_speed = 0;
|
|
||||||
if (stored_last_mode < MOTOR_EXHAUST || stored_last_mode > MOTOR_INTAKE) stored_last_mode = MOTOR_EXHAUST;
|
|
||||||
if (!IS_VALID_SPEED(stored_last_speed)) stored_last_speed = 50;
|
|
||||||
|
|
||||||
// Set the last ON state in motor control module
|
|
||||||
motor_set_last_on_state((motor_mode_t)stored_last_mode, stored_last_speed);
|
|
||||||
motor_set_user_turned_off(stored_power_state == 1);
|
|
||||||
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "Loaded state from NVS - Mode: %d, Speed: %d%%, Last ON: %d@%d%%, User OFF: %s",
|
|
||||||
stored_mode, stored_speed, stored_last_mode, stored_last_speed,
|
|
||||||
stored_power_state ? "YES" : "NO");
|
|
||||||
|
|
||||||
// Check reset reason to decide whether to restore state
|
|
||||||
bool was_watchdog_reset = is_watchdog_reset();
|
|
||||||
esp_reset_reason_t reset_reason = esp_reset_reason();
|
|
||||||
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "=== RESET ANALYSIS ===");
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "Reset reason: %d", reset_reason);
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "Reset reason name: %s",
|
|
||||||
reset_reason == ESP_RST_POWERON ? "POWERON" :
|
|
||||||
reset_reason == ESP_RST_EXT ? "EXTERNAL" :
|
|
||||||
reset_reason == ESP_RST_SW ? "SOFTWARE" :
|
|
||||||
reset_reason == ESP_RST_PANIC ? "PANIC" :
|
|
||||||
reset_reason == ESP_RST_INT_WDT ? "INT_WDT" :
|
|
||||||
reset_reason == ESP_RST_TASK_WDT ? "TASK_WDT" :
|
|
||||||
reset_reason == ESP_RST_WDT ? "WDT" :
|
|
||||||
reset_reason == ESP_RST_DEEPSLEEP ? "DEEPSLEEP" :
|
|
||||||
reset_reason == ESP_RST_BROWNOUT ? "BROWNOUT" :
|
|
||||||
reset_reason == ESP_RST_SDIO ? "SDIO" : "UNKNOWN");
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "Watchdog reset: %s", was_watchdog_reset ? "YES" : "NO");
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "Stored mode: %d, speed: %d", stored_mode, stored_speed);
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "User turned off: %s", stored_power_state ? "YES" : "NO");
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "====================");
|
|
||||||
|
|
||||||
// Store the restored state for potential motor restoration
|
|
||||||
if (was_watchdog_reset) {
|
|
||||||
// True watchdog reset (TASK_WDT or INT_WDT) - don't restore state, start fresh
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "⚠️ TRUE watchdog reset detected - starting in OFF state for safety");
|
|
||||||
// Motor module is already initialized in OFF state, no action needed
|
|
||||||
} else if (stored_power_state) {
|
|
||||||
// User manually turned off - stay off
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "🔒 User had turned off manually - staying OFF");
|
|
||||||
// Motor module is already initialized in OFF state, no action needed
|
|
||||||
} else if (stored_mode != MOTOR_OFF && stored_speed > 0) {
|
|
||||||
// Normal power loss or general WDT (which can be power-related) - restore previous state
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "🔋 Power restored - will resume previous state: %s @ %d%%",
|
|
||||||
stored_mode == MOTOR_EXHAUST ? "EXHAUST" : "INTAKE", stored_speed);
|
|
||||||
|
|
||||||
// Set the motor to the restored state (will be applied after initialization)
|
|
||||||
motor_set_speed((motor_mode_t)stored_mode, stored_speed);
|
|
||||||
} else {
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "❌ No valid state to restore (mode=%d, speed=%d)", stored_mode, stored_speed);
|
|
||||||
// Motor module is already initialized in OFF state, no action needed
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "No saved state found, using defaults");
|
|
||||||
err = ESP_ERR_NVS_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
nvs_close(nvs_handle);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// WiFi event handler
|
// WiFi event handler
|
||||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||||
int32_t event_id, void* event_data)
|
int32_t event_id, void* event_data)
|
||||||
@ -444,8 +280,11 @@ static esp_err_t fan_post_handler(httpd_req_t *req)
|
|||||||
ESP_LOGI(SYSTEM_TAG, "ON button pressed - resuming last state");
|
ESP_LOGI(SYSTEM_TAG, "ON button pressed - resuming last state");
|
||||||
motor_resume_last_state();
|
motor_resume_last_state();
|
||||||
|
|
||||||
// Save state after ON button
|
// Save state after ON button using state manager
|
||||||
save_motor_state_to_nvs();
|
esp_err_t save_result = state_manager_save();
|
||||||
|
if (save_result != ESP_OK) {
|
||||||
|
ESP_LOGW(SYSTEM_TAG, "Failed to save state after ON button: %s", esp_err_to_name(save_result));
|
||||||
|
}
|
||||||
|
|
||||||
cJSON_Delete(json);
|
cJSON_Delete(json);
|
||||||
return status_get_handler(req);
|
return status_get_handler(req);
|
||||||
@ -458,8 +297,11 @@ static esp_err_t fan_post_handler(httpd_req_t *req)
|
|||||||
ESP_LOGI(SYSTEM_TAG, "HTTP Request: mode=%s, speed=%d", mode_str, speed);
|
ESP_LOGI(SYSTEM_TAG, "HTTP Request: mode=%s, speed=%d", mode_str, speed);
|
||||||
motor_set_speed(mode, speed);
|
motor_set_speed(mode, speed);
|
||||||
|
|
||||||
// Save state after any motor command
|
// Save state after any motor command using state manager
|
||||||
save_motor_state_to_nvs();
|
esp_err_t save_result = state_manager_save();
|
||||||
|
if (save_result != ESP_OK) {
|
||||||
|
ESP_LOGW(SYSTEM_TAG, "Failed to save state after motor command: %s", esp_err_to_name(save_result));
|
||||||
|
}
|
||||||
|
|
||||||
cJSON_Delete(json);
|
cJSON_Delete(json);
|
||||||
|
|
||||||
@ -600,13 +442,13 @@ void app_main(void)
|
|||||||
{
|
{
|
||||||
ESP_LOGI(SYSTEM_TAG, "Starting Maxxfan HTTP Controller with State Preservation!");
|
ESP_LOGI(SYSTEM_TAG, "Starting Maxxfan HTTP Controller with State Preservation!");
|
||||||
|
|
||||||
// Initialize NVS
|
// Initialize state manager (includes NVS initialization)
|
||||||
esp_err_t ret = nvs_flash_init();
|
ESP_LOGI(SYSTEM_TAG, "Initializing state manager...");
|
||||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
esp_err_t ret = state_manager_init();
|
||||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
if (ret != ESP_OK) {
|
||||||
ret = nvs_flash_init();
|
ESP_LOGE(SYSTEM_TAG, "Failed to initialize state manager: %s", esp_err_to_name(ret));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
ESP_ERROR_CHECK(ret);
|
|
||||||
|
|
||||||
// Initialize watchdog timer
|
// Initialize watchdog timer
|
||||||
init_watchdog();
|
init_watchdog();
|
||||||
@ -619,9 +461,16 @@ void app_main(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load saved state from NVS and potentially restore motor state
|
// Load saved state and restore motor if appropriate
|
||||||
ESP_LOGI(SYSTEM_TAG, "Loading saved state...");
|
ESP_LOGI(SYSTEM_TAG, "Loading saved state and applying restoration logic...");
|
||||||
load_motor_state_from_nvs();
|
esp_err_t load_result = state_manager_load_and_restore();
|
||||||
|
if (load_result == ESP_OK) {
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "✓ State loaded and restoration logic applied");
|
||||||
|
} else if (load_result == ESP_ERR_NVS_NOT_FOUND) {
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "ℹ️ No saved state found, using defaults");
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(SYSTEM_TAG, "⚠️ Failed to load state: %s", esp_err_to_name(load_result));
|
||||||
|
}
|
||||||
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "Connecting to WiFi network: %s", WIFI_SSID);
|
ESP_LOGI(SYSTEM_TAG, "Connecting to WiFi network: %s", WIFI_SSID);
|
||||||
wifi_init_sta();
|
wifi_init_sta();
|
||||||
@ -629,25 +478,36 @@ void app_main(void)
|
|||||||
// Start HTTP server
|
// Start HTTP server
|
||||||
start_webserver();
|
start_webserver();
|
||||||
|
|
||||||
// Report final motor state after initialization
|
// Report final system state after initialization
|
||||||
const motor_state_t* final_state = motor_get_state();
|
const motor_state_t* final_state = motor_get_state();
|
||||||
ESP_LOGI(SYSTEM_TAG, "=== MOTOR STATE AFTER INITIALIZATION ===");
|
ESP_LOGI(SYSTEM_TAG, "=== SYSTEM INITIALIZATION COMPLETE ===");
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "Reset Reason: %s", state_manager_get_reset_reason_string());
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "Watchdog Reset: %s", state_manager_was_watchdog_reset() ? "YES" : "NO");
|
||||||
ESP_LOGI(SYSTEM_TAG, "Final motor state: mode=%s, target=%d%%, current=%d%%, state=%s",
|
ESP_LOGI(SYSTEM_TAG, "Final motor state: mode=%s, target=%d%%, current=%d%%, state=%s",
|
||||||
motor_mode_to_string(final_state->mode), final_state->target_speed,
|
motor_mode_to_string(final_state->mode), final_state->target_speed,
|
||||||
final_state->current_speed, motor_state_to_string(final_state->state));
|
final_state->current_speed, motor_state_to_string(final_state->state));
|
||||||
|
|
||||||
if (final_state->mode != MOTOR_OFF && final_state->target_speed > 0) {
|
if (final_state->mode != MOTOR_OFF && final_state->target_speed > 0) {
|
||||||
ESP_LOGI(SYSTEM_TAG, "Motor restored to: %s @ %d%%",
|
ESP_LOGI(SYSTEM_TAG, "🔄 Motor restored to: %s @ %d%%",
|
||||||
motor_mode_to_string(final_state->mode), final_state->target_speed);
|
motor_mode_to_string(final_state->mode), final_state->target_speed);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGI(SYSTEM_TAG, "Motor remains OFF");
|
ESP_LOGI(SYSTEM_TAG, "⏸️ Motor remains OFF");
|
||||||
}
|
}
|
||||||
ESP_LOGI(SYSTEM_TAG, "=======================================");
|
|
||||||
|
motor_mode_t last_on_mode;
|
||||||
|
int last_on_speed;
|
||||||
|
motor_get_last_on_state(&last_on_mode, &last_on_speed);
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "Last ON state: %s @ %d%%",
|
||||||
|
motor_mode_to_string(last_on_mode), last_on_speed);
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "User turned off: %s", motor_get_user_turned_off() ? "YES" : "NO");
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "Saved state exists: %s", state_manager_has_saved_state() ? "YES" : "NO");
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "=====================================");
|
||||||
|
|
||||||
ESP_LOGI(SYSTEM_TAG, "=== Enhanced Maxxfan Controller Ready! ===");
|
ESP_LOGI(SYSTEM_TAG, "=== Enhanced Maxxfan Controller Ready! ===");
|
||||||
ESP_LOGI(SYSTEM_TAG, "Features: State Preservation, Direction Safety, Motor Ramping, ON Button");
|
ESP_LOGI(SYSTEM_TAG, "Features: State Preservation, Direction Safety, Motor Ramping, ON Button");
|
||||||
ESP_LOGI(SYSTEM_TAG, "Safety: %d-second cooldown for direction changes", DIRECTION_CHANGE_COOLDOWN_MS / 1000);
|
ESP_LOGI(SYSTEM_TAG, "Safety: %d-second cooldown for direction changes", DIRECTION_CHANGE_COOLDOWN_MS / 1000);
|
||||||
ESP_LOGI(SYSTEM_TAG, "Memory: Remembers settings after power loss (except watchdog resets)");
|
ESP_LOGI(SYSTEM_TAG, "Memory: Remembers settings after power loss (except watchdog resets)");
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "State Manager: Enhanced NVS operations with validation and recovery");
|
||||||
ESP_LOGI(SYSTEM_TAG, "Open your browser and go to: http://[ESP32_IP_ADDRESS]");
|
ESP_LOGI(SYSTEM_TAG, "Open your browser and go to: http://[ESP32_IP_ADDRESS]");
|
||||||
ESP_LOGI(SYSTEM_TAG, "Check the monitor output above for your IP address");
|
ESP_LOGI(SYSTEM_TAG, "Check the monitor output above for your IP address");
|
||||||
|
|
||||||
|
|||||||
422
main/state_manager.c
Normal file
422
main/state_manager.c
Normal file
@ -0,0 +1,422 @@
|
|||||||
|
#include "state_manager.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "motor_control.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
#include "nvs.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// Private functions
|
||||||
|
static esp_err_t validate_and_clamp_values(uint8_t* mode, uint8_t* speed, uint8_t* last_mode, uint8_t* last_speed);
|
||||||
|
static void log_reset_analysis(void);
|
||||||
|
static esp_err_t should_restore_state(bool* should_restore, motor_mode_t stored_mode, int stored_speed);
|
||||||
|
|
||||||
|
// Validate and clamp loaded values to safe ranges
|
||||||
|
static esp_err_t validate_and_clamp_values(uint8_t* mode, uint8_t* speed, uint8_t* last_mode, uint8_t* last_speed) {
|
||||||
|
// Validate and clamp motor mode
|
||||||
|
if (*mode > MOTOR_INTAKE) {
|
||||||
|
ESP_LOGW(SYSTEM_TAG, "Invalid stored mode %d, clamping to OFF", *mode);
|
||||||
|
*mode = MOTOR_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate and clamp speed
|
||||||
|
if (!IS_VALID_SPEED(*speed)) {
|
||||||
|
ESP_LOGW(SYSTEM_TAG, "Invalid stored speed %d, clamping to 0", *speed);
|
||||||
|
*speed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate and clamp last ON mode
|
||||||
|
if (*last_mode < MOTOR_EXHAUST || *last_mode > MOTOR_INTAKE) {
|
||||||
|
ESP_LOGW(SYSTEM_TAG, "Invalid stored last mode %d, defaulting to EXHAUST", *last_mode);
|
||||||
|
*last_mode = MOTOR_EXHAUST;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate and clamp last ON speed
|
||||||
|
if (!IS_VALID_SPEED(*last_speed) || *last_speed == 0) {
|
||||||
|
ESP_LOGW(SYSTEM_TAG, "Invalid stored last speed %d, defaulting to 50", *last_speed);
|
||||||
|
*last_speed = 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log detailed reset analysis
|
||||||
|
static void log_reset_analysis(void) {
|
||||||
|
esp_reset_reason_t reset_reason = esp_reset_reason();
|
||||||
|
bool was_watchdog = state_manager_was_watchdog_reset();
|
||||||
|
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "=== RESET ANALYSIS ===");
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "Reset reason code: %d", reset_reason);
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "Reset reason: %s", state_manager_get_reset_reason_string());
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "Watchdog reset: %s", was_watchdog ? "YES" : "NO");
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "====================");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if state should be restored based on reset reason and user preferences
|
||||||
|
static esp_err_t should_restore_state(bool* should_restore, motor_mode_t stored_mode, int stored_speed) {
|
||||||
|
if (!should_restore) return ESP_ERR_INVALID_ARG;
|
||||||
|
|
||||||
|
*should_restore = false;
|
||||||
|
|
||||||
|
bool was_watchdog = state_manager_was_watchdog_reset();
|
||||||
|
bool user_turned_off = motor_get_user_turned_off();
|
||||||
|
|
||||||
|
if (was_watchdog) {
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "⚠️ TRUE watchdog reset detected - starting in OFF state for safety");
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_turned_off) {
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "🔒 User had turned off manually - staying OFF");
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stored_mode != MOTOR_OFF && stored_speed > 0) {
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "🔋 Power restored - will resume previous state: %s @ %d%%",
|
||||||
|
motor_mode_to_string(stored_mode), stored_speed);
|
||||||
|
*should_restore = true;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "❌ No valid state to restore (mode=%s, speed=%d)",
|
||||||
|
motor_mode_to_string(stored_mode), stored_speed);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public API Implementation
|
||||||
|
|
||||||
|
esp_err_t state_manager_init(void) {
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "Initializing state manager...");
|
||||||
|
|
||||||
|
esp_err_t ret = nvs_flash_init();
|
||||||
|
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||||
|
ESP_LOGW(SYSTEM_TAG, "NVS partition was truncated, erasing...");
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
|
ret = nvs_flash_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(SYSTEM_TAG, "Failed to initialize NVS: %s", esp_err_to_name(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "State manager initialized successfully");
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t state_manager_save(void) {
|
||||||
|
nvs_handle_t nvs_handle;
|
||||||
|
esp_err_t err;
|
||||||
|
|
||||||
|
err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(SYSTEM_TAG, "Error opening NVS handle: %s", esp_err_to_name(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get current motor state
|
||||||
|
const motor_state_t* state = motor_get_state();
|
||||||
|
motor_mode_t last_on_mode;
|
||||||
|
int last_on_speed;
|
||||||
|
motor_get_last_on_state(&last_on_mode, &last_on_speed);
|
||||||
|
bool user_turned_off = motor_get_user_turned_off();
|
||||||
|
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "=== SAVING STATE TO NVS ===");
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "Mode: %s, Speed: %d%%, Last ON: %s@%d%%, User OFF: %s",
|
||||||
|
motor_mode_to_string(state->mode), state->target_speed,
|
||||||
|
motor_mode_to_string(last_on_mode), last_on_speed,
|
||||||
|
user_turned_off ? "YES" : "NO");
|
||||||
|
|
||||||
|
// Save current motor state
|
||||||
|
err = nvs_set_u8(nvs_handle, NVS_KEY_MODE, (uint8_t)state->mode);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
err = nvs_set_u8(nvs_handle, NVS_KEY_SPEED, (uint8_t)state->target_speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save last ON state
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
err = nvs_set_u8(nvs_handle, NVS_KEY_LAST_ON_MODE, (uint8_t)last_on_mode);
|
||||||
|
}
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
err = nvs_set_u8(nvs_handle, NVS_KEY_LAST_ON_SPEED, (uint8_t)last_on_speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save power state (whether user turned off manually)
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
err = nvs_set_u8(nvs_handle, NVS_KEY_POWER_STATE, user_turned_off ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
err = nvs_commit(nvs_handle);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "✓ Motor state successfully saved to NVS");
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(SYSTEM_TAG, "✗ NVS commit failed: %s", esp_err_to_name(err));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(SYSTEM_TAG, "✗ Error saving to NVS: %s", esp_err_to_name(err));
|
||||||
|
}
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "===========================");
|
||||||
|
|
||||||
|
nvs_close(nvs_handle);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t state_manager_load_and_restore(void) {
|
||||||
|
nvs_handle_t nvs_handle;
|
||||||
|
esp_err_t err;
|
||||||
|
|
||||||
|
err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &nvs_handle);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "NVS not found, using default state");
|
||||||
|
return ESP_ERR_NVS_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t stored_mode = 0;
|
||||||
|
uint8_t stored_speed = 0;
|
||||||
|
uint8_t stored_last_mode = MOTOR_EXHAUST; // Default to MOTOR_EXHAUST
|
||||||
|
uint8_t stored_last_speed = 50;
|
||||||
|
uint8_t stored_power_state = 0;
|
||||||
|
|
||||||
|
// Load current motor state
|
||||||
|
err = nvs_get_u8(nvs_handle, NVS_KEY_MODE, &stored_mode);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
nvs_get_u8(nvs_handle, NVS_KEY_SPEED, &stored_speed);
|
||||||
|
nvs_get_u8(nvs_handle, NVS_KEY_LAST_ON_MODE, &stored_last_mode);
|
||||||
|
nvs_get_u8(nvs_handle, NVS_KEY_LAST_ON_SPEED, &stored_last_speed);
|
||||||
|
nvs_get_u8(nvs_handle, NVS_KEY_POWER_STATE, &stored_power_state);
|
||||||
|
|
||||||
|
// Validate and clamp all values
|
||||||
|
validate_and_clamp_values(&stored_mode, &stored_speed, &stored_last_mode, &stored_last_speed);
|
||||||
|
|
||||||
|
// Set the loaded state in motor control module
|
||||||
|
motor_set_last_on_state((motor_mode_t)stored_last_mode, stored_last_speed);
|
||||||
|
motor_set_user_turned_off(stored_power_state == 1);
|
||||||
|
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "Loaded state from NVS - Mode: %s, Speed: %d%%, Last ON: %s@%d%%, User OFF: %s",
|
||||||
|
motor_mode_to_string((motor_mode_t)stored_mode), stored_speed,
|
||||||
|
motor_mode_to_string((motor_mode_t)stored_last_mode), stored_last_speed,
|
||||||
|
stored_power_state ? "YES" : "NO");
|
||||||
|
|
||||||
|
// Log reset analysis
|
||||||
|
log_reset_analysis();
|
||||||
|
|
||||||
|
// Determine if we should restore the motor state
|
||||||
|
bool should_restore = false;
|
||||||
|
should_restore_state(&should_restore, (motor_mode_t)stored_mode, stored_speed);
|
||||||
|
|
||||||
|
if (should_restore) {
|
||||||
|
// Restore the motor to its previous state
|
||||||
|
motor_set_speed((motor_mode_t)stored_mode, stored_speed);
|
||||||
|
}
|
||||||
|
// Note: If should_restore is false, motor remains in default OFF state
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "No saved state found, using defaults");
|
||||||
|
err = ESP_ERR_NVS_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_close(nvs_handle);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool state_manager_was_watchdog_reset(void) {
|
||||||
|
esp_reset_reason_t reset_reason = esp_reset_reason();
|
||||||
|
|
||||||
|
// Only consider TASK_WDT and INT_WDT as true watchdog resets
|
||||||
|
// ESP_RST_WDT can be triggered by power disconnection, so we exclude it
|
||||||
|
return (reset_reason == ESP_RST_TASK_WDT ||
|
||||||
|
reset_reason == ESP_RST_INT_WDT);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* state_manager_get_reset_reason_string(void) {
|
||||||
|
esp_reset_reason_t reset_reason = esp_reset_reason();
|
||||||
|
|
||||||
|
switch (reset_reason) {
|
||||||
|
case ESP_RST_POWERON: return "POWER_ON";
|
||||||
|
case ESP_RST_EXT: return "EXTERNAL";
|
||||||
|
case ESP_RST_SW: return "SOFTWARE";
|
||||||
|
case ESP_RST_PANIC: return "PANIC";
|
||||||
|
case ESP_RST_INT_WDT: return "INT_WDT";
|
||||||
|
case ESP_RST_TASK_WDT: return "TASK_WDT";
|
||||||
|
case ESP_RST_WDT: return "WDT";
|
||||||
|
case ESP_RST_DEEPSLEEP: return "DEEPSLEEP";
|
||||||
|
case ESP_RST_BROWNOUT: return "BROWNOUT";
|
||||||
|
case ESP_RST_SDIO: return "SDIO";
|
||||||
|
default: return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t state_manager_clear_all(void) {
|
||||||
|
nvs_handle_t nvs_handle;
|
||||||
|
esp_err_t err;
|
||||||
|
|
||||||
|
err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(SYSTEM_TAG, "Error opening NVS handle for clear: %s", esp_err_to_name(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "Clearing all saved state from NVS...");
|
||||||
|
|
||||||
|
err = nvs_erase_all(nvs_handle);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
err = nvs_commit(nvs_handle);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "✓ All state cleared from NVS");
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(SYSTEM_TAG, "✗ Failed to commit NVS clear: %s", esp_err_to_name(err));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(SYSTEM_TAG, "✗ Failed to clear NVS: %s", esp_err_to_name(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_close(nvs_handle);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t state_manager_save_last_on_state(motor_mode_t mode, int speed) {
|
||||||
|
if (mode == MOTOR_OFF || !IS_VALID_SPEED(speed) || speed == 0) {
|
||||||
|
ESP_LOGW(SYSTEM_TAG, "Invalid last ON state: mode=%s, speed=%d",
|
||||||
|
motor_mode_to_string(mode), speed);
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_handle_t nvs_handle;
|
||||||
|
esp_err_t err;
|
||||||
|
|
||||||
|
err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(SYSTEM_TAG, "Error opening NVS handle: %s", esp_err_to_name(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save only the last ON state
|
||||||
|
err = nvs_set_u8(nvs_handle, NVS_KEY_LAST_ON_MODE, (uint8_t)mode);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
err = nvs_set_u8(nvs_handle, NVS_KEY_LAST_ON_SPEED, (uint8_t)speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
err = nvs_commit(nvs_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_close(nvs_handle);
|
||||||
|
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
ESP_LOGI(SYSTEM_TAG, "Last ON state saved: %s @ %d%%",
|
||||||
|
motor_mode_to_string(mode), speed);
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(SYSTEM_TAG, "Failed to save last ON state: %s", esp_err_to_name(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t state_manager_load_last_on_state(motor_mode_t* mode, int* speed) {
|
||||||
|
if (!mode || !speed) return ESP_ERR_INVALID_ARG;
|
||||||
|
|
||||||
|
nvs_handle_t nvs_handle;
|
||||||
|
esp_err_t err;
|
||||||
|
|
||||||
|
err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &nvs_handle);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return ESP_ERR_NVS_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t stored_mode = MOTOR_EXHAUST;
|
||||||
|
uint8_t stored_speed = 50;
|
||||||
|
|
||||||
|
err = nvs_get_u8(nvs_handle, NVS_KEY_LAST_ON_MODE, &stored_mode);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
nvs_get_u8(nvs_handle, NVS_KEY_LAST_ON_SPEED, &stored_speed);
|
||||||
|
|
||||||
|
// Validate values
|
||||||
|
if (stored_mode < MOTOR_EXHAUST || stored_mode > MOTOR_INTAKE) {
|
||||||
|
stored_mode = MOTOR_EXHAUST;
|
||||||
|
}
|
||||||
|
if (!IS_VALID_SPEED(stored_speed) || stored_speed == 0) {
|
||||||
|
stored_speed = 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
*mode = (motor_mode_t)stored_mode;
|
||||||
|
*speed = stored_speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_close(nvs_handle);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool state_manager_get_user_turned_off(void) {
|
||||||
|
return motor_get_user_turned_off();
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t state_manager_set_user_turned_off(bool turned_off) {
|
||||||
|
motor_set_user_turned_off(turned_off);
|
||||||
|
|
||||||
|
// Save just this flag to NVS
|
||||||
|
nvs_handle_t nvs_handle;
|
||||||
|
esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = nvs_set_u8(nvs_handle, NVS_KEY_POWER_STATE, turned_off ? 1 : 0);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
err = nvs_commit(nvs_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_close(nvs_handle);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t state_manager_get_debug_info(char* info_buffer, size_t buffer_size) {
|
||||||
|
if (!info_buffer || buffer_size == 0) return ESP_ERR_INVALID_ARG;
|
||||||
|
|
||||||
|
const motor_state_t* state = motor_get_state();
|
||||||
|
motor_mode_t last_on_mode;
|
||||||
|
int last_on_speed;
|
||||||
|
motor_get_last_on_state(&last_on_mode, &last_on_speed);
|
||||||
|
|
||||||
|
int written = snprintf(info_buffer, buffer_size,
|
||||||
|
"=== STATE MANAGER DEBUG INFO ===\n"
|
||||||
|
"Reset Reason: %s\n"
|
||||||
|
"Watchdog Reset: %s\n"
|
||||||
|
"Current Mode: %s\n"
|
||||||
|
"Current Speed: %d%%\n"
|
||||||
|
"Target Speed: %d%%\n"
|
||||||
|
"Motor State: %s\n"
|
||||||
|
"Last ON: %s @ %d%%\n"
|
||||||
|
"User Turned Off: %s\n"
|
||||||
|
"Has Saved State: %s\n"
|
||||||
|
"===============================",
|
||||||
|
state_manager_get_reset_reason_string(),
|
||||||
|
state_manager_was_watchdog_reset() ? "YES" : "NO",
|
||||||
|
motor_mode_to_string(state->mode),
|
||||||
|
state->current_speed,
|
||||||
|
state->target_speed,
|
||||||
|
motor_state_to_string(state->state),
|
||||||
|
motor_mode_to_string(last_on_mode),
|
||||||
|
last_on_speed,
|
||||||
|
motor_get_user_turned_off() ? "YES" : "NO",
|
||||||
|
state_manager_has_saved_state() ? "YES" : "NO"
|
||||||
|
);
|
||||||
|
|
||||||
|
return (written < buffer_size) ? ESP_OK : ESP_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool state_manager_has_saved_state(void) {
|
||||||
|
nvs_handle_t nvs_handle;
|
||||||
|
esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &nvs_handle);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t dummy;
|
||||||
|
err = nvs_get_u8(nvs_handle, NVS_KEY_MODE, &dummy);
|
||||||
|
nvs_close(nvs_handle);
|
||||||
|
|
||||||
|
return (err == ESP_OK);
|
||||||
|
}
|
||||||
126
main/state_manager.h
Normal file
126
main/state_manager.h
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
#ifndef STATE_MANAGER_H
|
||||||
|
#define STATE_MANAGER_H
|
||||||
|
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "motor_control.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the state manager
|
||||||
|
*
|
||||||
|
* Sets up NVS flash and prepares for state operations.
|
||||||
|
* Must be called before any other state manager functions.
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success, ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
esp_err_t state_manager_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Save current motor state to NVS
|
||||||
|
*
|
||||||
|
* Saves the current motor mode, speed, last ON state, and user preferences
|
||||||
|
* to non-volatile storage for persistence across power cycles.
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success, ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
esp_err_t state_manager_save(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load motor state from NVS and apply restoration logic
|
||||||
|
*
|
||||||
|
* Loads saved state from NVS and determines whether to restore the motor
|
||||||
|
* based on reset reason and user preferences. Handles:
|
||||||
|
* - Power loss recovery
|
||||||
|
* - Watchdog reset detection
|
||||||
|
* - User manual shutoff preference
|
||||||
|
*
|
||||||
|
* @return ESP_OK if state was loaded and applied, ESP_ERR_NVS_NOT_FOUND if no saved state
|
||||||
|
*/
|
||||||
|
esp_err_t state_manager_load_and_restore(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if the last reset was due to a watchdog timeout
|
||||||
|
*
|
||||||
|
* Distinguishes between true watchdog resets (software issues) and
|
||||||
|
* other resets like power loss or external reset.
|
||||||
|
*
|
||||||
|
* @return true if reset was due to watchdog timeout, false otherwise
|
||||||
|
*/
|
||||||
|
bool state_manager_was_watchdog_reset(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get human-readable reset reason string
|
||||||
|
*
|
||||||
|
* @return String describing the reset reason
|
||||||
|
*/
|
||||||
|
const char* state_manager_get_reset_reason_string(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear all saved state from NVS
|
||||||
|
*
|
||||||
|
* Removes all motor state data from NVS. Useful for factory reset
|
||||||
|
* or debugging purposes.
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success, ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
esp_err_t state_manager_clear_all(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Save only the "last ON" state to NVS
|
||||||
|
*
|
||||||
|
* Saves just the last known good motor state for the ON button functionality.
|
||||||
|
* This is lighter weight than saving the full state.
|
||||||
|
*
|
||||||
|
* @param mode Motor mode (MOTOR_EXHAUST or MOTOR_INTAKE)
|
||||||
|
* @param speed Speed percentage (1-100)
|
||||||
|
* @return ESP_OK on success, ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
esp_err_t state_manager_save_last_on_state(motor_mode_t mode, int speed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load only the "last ON" state from NVS
|
||||||
|
*
|
||||||
|
* @param mode Pointer to store the loaded mode
|
||||||
|
* @param speed Pointer to store the loaded speed
|
||||||
|
* @return ESP_OK if loaded successfully, ESP_ERR_NVS_NOT_FOUND if not found
|
||||||
|
*/
|
||||||
|
esp_err_t state_manager_load_last_on_state(motor_mode_t* mode, int* speed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if user manually turned off the motor
|
||||||
|
*
|
||||||
|
* Used to determine restoration behavior - if user manually turned off,
|
||||||
|
* the motor should stay off after power restoration.
|
||||||
|
*
|
||||||
|
* @return true if user manually turned off, false otherwise
|
||||||
|
*/
|
||||||
|
bool state_manager_get_user_turned_off(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the user turned off flag
|
||||||
|
*
|
||||||
|
* @param turned_off true if user manually turned off, false otherwise
|
||||||
|
* @return ESP_OK on success, ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
esp_err_t state_manager_set_user_turned_off(bool turned_off);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get detailed state information for debugging
|
||||||
|
*
|
||||||
|
* Provides comprehensive information about the saved state and
|
||||||
|
* reset conditions for troubleshooting.
|
||||||
|
*
|
||||||
|
* @param info_buffer Buffer to store the information string
|
||||||
|
* @param buffer_size Size of the info buffer
|
||||||
|
* @return ESP_OK on success, ESP_FAIL on error
|
||||||
|
*/
|
||||||
|
esp_err_t state_manager_get_debug_info(char* info_buffer, size_t buffer_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if NVS contains any saved motor state
|
||||||
|
*
|
||||||
|
* @return true if saved state exists, false otherwise
|
||||||
|
*/
|
||||||
|
bool state_manager_has_saved_state(void);
|
||||||
|
|
||||||
|
#endif // STATE_MANAGER_H
|
||||||
Reference in New Issue
Block a user