ca13734bf0
Add kernel (Cortex-M0/M3/M4, Tricore, S32K, RISC-V ports), drivers, middleware (CAN stack, diagnostics, safety), applications, board support, build/test tooling, and documentation.
213 lines
5.6 KiB
C
213 lines
5.6 KiB
C
/**
|
|
* @file watchdog_manager.c
|
|
* @brief Watchdog Manager for safety-critical applications
|
|
*/
|
|
|
|
#include "kernel.h"
|
|
#include "task.h"
|
|
#include <string.h>
|
|
|
|
/* 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();
|
|
}
|