/** * @file watchdog_manager.c * @brief Watchdog Manager for safety-critical applications */ #include "kernel.h" #include "task.h" #include /* Watchdog Configuration */ #define WATCHDOG_MAX_TASKS 16 #define WATCHDOG_DEFAULT_TIMEOUT 100 /* ms */ #define WATCHDOG_MAX_ALIVE_COUNT 5 /* Watchdog Task Status */ typedef enum { WATCHDOG_TASK_ALIVE = 0, WATCHDOG_TASK_TIMEOUT = 1, WATCHDOG_TASK_SUSPENDED = 2 } WatchdogTaskStatus_t; /* Watchdog Task Entry */ typedef struct { TaskHandle_t task; char task_name[16]; uint32_t timeout_ms; uint32_t last_alive_time; uint32_t alive_count; WatchdogTaskStatus_t status; bool is_supervised; } WatchdogTaskEntry_t; /* Watchdog Manager State */ typedef struct { bool initialized; bool enabled; WatchdogTaskEntry_t tasks[WATCHDOG_MAX_TASKS]; uint8_t task_count; uint32_t global_timeout_ms; uint32_t last_service_time; Mutex_t mutex; void (*system_reset_callback)(void); void (*task_timeout_callback)(TaskHandle_t task); } WatchdogManagerState_t; static WatchdogManagerState_t watchdog_manager; /* Initialize Watchdog Manager */ KernelStatus_t watchdog_manager_init(uint32_t global_timeout_ms) { if (watchdog_manager.initialized) { return KERNEL_ERROR; } memset(&watchdog_manager, 0, sizeof(WatchdogManagerState_t)); watchdog_manager.global_timeout_ms = global_timeout_ms; watchdog_manager.enabled = false; watchdog_manager.last_service_time = kernel_get_tick_count(); mutex_create(&watchdog_manager.mutex, false); watchdog_manager.initialized = true; return KERNEL_OK; } /* Register Task for Supervision */ KernelStatus_t watchdog_register_task(TaskHandle_t task, const char* name, uint32_t timeout_ms) { if (!watchdog_manager.initialized || task == NULL) { return KERNEL_ERROR; } if (watchdog_manager.task_count >= WATCHDOG_MAX_TASKS) { return KERNEL_OUT_OF_MEMORY; } mutex_lock(&watchdog_manager.mutex, 100); WatchdogTaskEntry_t* entry = &watchdog_manager.tasks[watchdog_manager.task_count]; entry->task = task; strncpy(entry->task_name, name, sizeof(entry->task_name) - 1); entry->timeout_ms = timeout_ms; entry->last_alive_time = kernel_get_tick_count(); entry->alive_count = 0; entry->status = WATCHDOG_TASK_ALIVE; entry->is_supervised = true; watchdog_manager.task_count++; mutex_unlock(&watchdog_manager.mutex); return KERNEL_OK; } /* Task Alive Indication */ KernelStatus_t watchdog_task_alive(TaskHandle_t task) { if (!watchdog_manager.initialized || task == NULL) { return KERNEL_ERROR; } mutex_lock(&watchdog_manager.mutex, 100); for (uint8_t i = 0; i < watchdog_manager.task_count; i++) { if (watchdog_manager.tasks[i].task == task) { watchdog_manager.tasks[i].last_alive_time = kernel_get_tick_count(); watchdog_manager.tasks[i].alive_count++; watchdog_manager.tasks[i].status = WATCHDOG_TASK_ALIVE; break; } } mutex_unlock(&watchdog_manager.mutex); return KERNEL_OK; } /* Enable Watchdog */ KernelStatus_t watchdog_enable(void) { if (!watchdog_manager.initialized) { return KERNEL_ERROR; } watchdog_manager.enabled = true; watchdog_manager.last_service_time = kernel_get_tick_count(); /* Enable hardware watchdog */ hal_watchdog_enable(watchdog_manager.global_timeout_ms); return KERNEL_OK; } /* Disable Watchdog */ KernelStatus_t watchdog_disable(void) { if (!watchdog_manager.initialized) { return KERNEL_ERROR; } watchdog_manager.enabled = false; /* Disable hardware watchdog */ hal_watchdog_disable(); return KERNEL_OK; } /* Service Watchdog */ KernelStatus_t watchdog_service(void) { if (!watchdog_manager.initialized || !watchdog_manager.enabled) { return KERNEL_ERROR; } /* Check all supervised tasks */ uint32_t current_time = kernel_get_tick_count(); bool all_tasks_alive = true; mutex_lock(&watchdog_manager.mutex, 100); for (uint8_t i = 0; i < watchdog_manager.task_count; i++) { WatchdogTaskEntry_t* entry = &watchdog_manager.tasks[i]; if (!entry->is_supervised) { continue; } /* Check if task is alive */ if ((current_time - entry->last_alive_time) > entry->timeout_ms) { entry->status = WATCHDOG_TASK_TIMEOUT; all_tasks_alive = false; /* Call task timeout callback */ if (watchdog_manager.task_timeout_callback != NULL) { watchdog_manager.task_timeout_callback(entry->task); } } } mutex_unlock(&watchdog_manager.mutex); if (all_tasks_alive) { /* Service hardware watchdog */ hal_watchdog_service(); watchdog_manager.last_service_time = current_time; return KERNEL_OK; } else { /* Don't service watchdog - will trigger reset */ return KERNEL_ERROR; } } /* Register Callbacks */ KernelStatus_t watchdog_register_callbacks( void (*system_reset_callback)(void), void (*task_timeout_callback)(TaskHandle_t task)) { if (!watchdog_manager.initialized) { return KERNEL_ERROR; } watchdog_manager.system_reset_callback = system_reset_callback; watchdog_manager.task_timeout_callback = task_timeout_callback; return KERNEL_OK; } /* Watchdog Main Function */ void watchdog_manager_main_function(void) { if (!watchdog_manager.initialized || !watchdog_manager.enabled) { return; } /* Service watchdog periodically */ watchdog_service(); }