Add full automotive RTOS project
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.
This commit is contained in:
@@ -0,0 +1,280 @@
|
||||
/**
|
||||
* @file e2e_protection.c
|
||||
* @brief End-to-End Protection for safety-critical communication
|
||||
*/
|
||||
|
||||
#include "kernel.h"
|
||||
#include "can_driver.h"
|
||||
#include <string.h>
|
||||
|
||||
/* E2E Protection Configuration */
|
||||
#define E2E_MAX_PROFILES 8
|
||||
#define E2E_MAX_DATA_LENGTH 64
|
||||
#define E2E_CRC_POLYNOMIAL 0x2F /* CRC-8 polynomial */
|
||||
|
||||
/* E2E Profile Types */
|
||||
typedef enum {
|
||||
E2E_PROFILE_1 = 1, /* CRC-8 */
|
||||
E2E_PROFILE_2 = 2, /* CRC-16 */
|
||||
E2E_PROFILE_4 = 4, /* CRC-32 */
|
||||
E2E_PROFILE_5 = 5, /* Custom */
|
||||
E2E_PROFILE_7 = 7 /* Counter + CRC */
|
||||
} E2eProfileType_t;
|
||||
|
||||
/* E2E Configuration */
|
||||
typedef struct {
|
||||
E2eProfileType_t profile_type;
|
||||
uint16_t data_id;
|
||||
uint8_t data_length;
|
||||
uint8_t counter_offset;
|
||||
uint8_t crc_offset;
|
||||
uint8_t timeout_ms;
|
||||
uint32_t max_delta_counter;
|
||||
} E2eConfig_t;
|
||||
|
||||
/* E2E State */
|
||||
typedef struct {
|
||||
bool initialized;
|
||||
E2eConfig_t profiles[E2E_MAX_PROFILES];
|
||||
uint8_t profile_count;
|
||||
uint8_t counters[E2E_MAX_PROFILES];
|
||||
uint32_t last_receive_time[E2E_MAX_PROFILES];
|
||||
uint32_t error_counters[E2E_MAX_PROFILES];
|
||||
Mutex_t mutex;
|
||||
} E2eState_t;
|
||||
|
||||
static E2eState_t e2e_state;
|
||||
|
||||
/* Initialize E2E Protection */
|
||||
KernelStatus_t e2e_protection_init(void) {
|
||||
if (e2e_state.initialized) {
|
||||
return KERNEL_ERROR;
|
||||
}
|
||||
|
||||
memset(&e2e_state, 0, sizeof(E2eState_t));
|
||||
mutex_create(&e2e_state.mutex, false);
|
||||
|
||||
e2e_state.initialized = true;
|
||||
return KERNEL_OK;
|
||||
}
|
||||
|
||||
/* Register E2E Profile */
|
||||
KernelStatus_t e2e_register_profile(const E2eConfig_t* config) {
|
||||
if (!e2e_state.initialized || config == NULL) {
|
||||
return KERNEL_ERROR;
|
||||
}
|
||||
|
||||
if (e2e_state.profile_count >= E2E_MAX_PROFILES) {
|
||||
return KERNEL_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
mutex_lock(&e2e_state.mutex, 100);
|
||||
|
||||
e2e_state.profiles[e2e_state.profile_count] = *config;
|
||||
e2e_state.counters[e2e_state.profile_count] = 0;
|
||||
e2e_state.last_receive_time[e2e_state.profile_count] = 0;
|
||||
e2e_state.error_counters[e2e_state.profile_count] = 0;
|
||||
|
||||
e2e_state.profile_count++;
|
||||
|
||||
mutex_unlock(&e2e_state.mutex);
|
||||
|
||||
return KERNEL_OK;
|
||||
}
|
||||
|
||||
/* Protect Message (Add E2E header) */
|
||||
KernelStatus_t e2e_protect_message(uint8_t profile_id, CanMessage_t* message) {
|
||||
if (!e2e_state.initialized || message == NULL) {
|
||||
return KERNEL_ERROR;
|
||||
}
|
||||
|
||||
if (profile_id >= e2e_state.profile_count) {
|
||||
return KERNEL_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
mutex_lock(&e2e_state.mutex, 100);
|
||||
|
||||
E2eConfig_t* config = &e2e_state.profiles[profile_id];
|
||||
|
||||
/* Add counter */
|
||||
message->data[config->counter_offset] = e2e_state.counters[profile_id];
|
||||
|
||||
/* Calculate CRC */
|
||||
uint8_t crc = e2e_calculate_crc8(message->data, config->data_length);
|
||||
|
||||
/* Add CRC */
|
||||
message->data[config->crc_offset] = crc;
|
||||
|
||||
/* Increment counter */
|
||||
e2e_state.counters[profile_id]++;
|
||||
|
||||
mutex_unlock(&e2e_state.mutex);
|
||||
|
||||
return KERNEL_OK;
|
||||
}
|
||||
|
||||
/* Check Message (Verify E2E header) */
|
||||
KernelStatus_t e2e_check_message(uint8_t profile_id, const CanMessage_t* message,
|
||||
bool* is_valid) {
|
||||
if (!e2e_state.initialized || message == NULL || is_valid == NULL) {
|
||||
return KERNEL_ERROR;
|
||||
}
|
||||
|
||||
if (profile_id >= e2e_state.profile_count) {
|
||||
return KERNEL_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
mutex_lock(&e2e_state.mutex, 100);
|
||||
|
||||
E2eConfig_t* config = &e2e_state.profiles[profile_id];
|
||||
*is_valid = false;
|
||||
|
||||
/* Check counter */
|
||||
uint8_t received_counter = message->data[config->counter_offset];
|
||||
uint8_t expected_counter = e2e_state.counters[profile_id];
|
||||
|
||||
uint32_t delta = (received_counter - expected_counter) & 0xFF;
|
||||
|
||||
if (delta > config->max_delta_counter) {
|
||||
/* Counter error */
|
||||
e2e_state.error_counters[profile_id]++;
|
||||
mutex_unlock(&e2e_state.mutex);
|
||||
return KERNEL_ERROR;
|
||||
}
|
||||
|
||||
/* Check CRC */
|
||||
uint8_t calculated_crc = e2e_calculate_crc8(message->data,
|
||||
config->data_length);
|
||||
uint8_t received_crc = message->data[config->crc_offset];
|
||||
|
||||
if (calculated_crc != received_crc) {
|
||||
/* CRC error */
|
||||
e2e_state.error_counters[profile_id]++;
|
||||
mutex_unlock(&e2e_state.mutex);
|
||||
return KERNEL_ERROR;
|
||||
}
|
||||
|
||||
/* Update state */
|
||||
e2e_state.counters[profile_id] = received_counter;
|
||||
e2e_state.last_receive_time[profile_id] = kernel_get_tick_count();
|
||||
|
||||
*is_valid = true;
|
||||
|
||||
mutex_unlock(&e2e_state.mutex);
|
||||
|
||||
return KERNEL_OK;
|
||||
}
|
||||
|
||||
/* Calculate CRC-8 */
|
||||
static uint8_t e2e_calculate_crc8(const uint8_t* data, uint8_t length) {
|
||||
uint8_t crc = 0xFF; /* Initial value */
|
||||
|
||||
for (uint8_t i = 0; i < length; i++) {
|
||||
crc ^= data[i];
|
||||
|
||||
for (uint8_t j = 0; j < 8; j++) {
|
||||
if (crc & 0x80) {
|
||||
crc = (crc << 1) ^ E2E_CRC_POLYNOMIAL;
|
||||
} else {
|
||||
crc <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/* Calculate CRC-16 */
|
||||
static uint16_t e2e_calculate_crc16(const uint8_t* data, uint8_t length) {
|
||||
uint16_t crc = 0xFFFF;
|
||||
|
||||
for (uint8_t i = 0; i < length; i++) {
|
||||
crc ^= (data[i] << 8);
|
||||
|
||||
for (uint8_t j = 0; j < 8; j++) {
|
||||
if (crc & 0x8000) {
|
||||
crc = (crc << 1) ^ 0x1021;
|
||||
} else {
|
||||
crc <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/* Calculate CRC-32 */
|
||||
static uint32_t e2e_calculate_crc32(const uint8_t* data, uint8_t length) {
|
||||
uint32_t crc = 0xFFFFFFFF;
|
||||
|
||||
for (uint8_t i = 0; i < length; i++) {
|
||||
crc ^= data[i];
|
||||
|
||||
for (uint8_t j = 0; j < 8; j++) {
|
||||
if (crc & 1) {
|
||||
crc = (crc >> 1) ^ 0xEDB88320;
|
||||
} else {
|
||||
crc >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
/* Get E2E Error Counter */
|
||||
uint32_t e2e_get_error_count(uint8_t profile_id) {
|
||||
if (profile_id >= e2e_state.profile_count) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return e2e_state.error_counters[profile_id];
|
||||
}
|
||||
|
||||
/* Reset E2E State */
|
||||
KernelStatus_t e2e_reset(uint8_t profile_id) {
|
||||
if (!e2e_state.initialized) {
|
||||
return KERNEL_ERROR;
|
||||
}
|
||||
|
||||
if (profile_id >= e2e_state.profile_count) {
|
||||
return KERNEL_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
mutex_lock(&e2e_state.mutex, 100);
|
||||
|
||||
e2e_state.counters[profile_id] = 0;
|
||||
e2e_state.last_receive_time[profile_id] = 0;
|
||||
e2e_state.error_counters[profile_id] = 0;
|
||||
|
||||
mutex_unlock(&e2e_state.mutex);
|
||||
|
||||
return KERNEL_OK;
|
||||
}
|
||||
|
||||
/* E2E Main Function */
|
||||
void e2e_protection_main_function(void) {
|
||||
if (!e2e_state.initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t current_time = kernel_get_tick_count();
|
||||
|
||||
mutex_lock(&e2e_state.mutex, 100);
|
||||
|
||||
/* Check timeouts */
|
||||
for (uint8_t i = 0; i < e2e_state.profile_count; i++) {
|
||||
E2eConfig_t* config = &e2e_state.profiles[i];
|
||||
|
||||
if (e2e_state.last_receive_time[i] > 0) {
|
||||
if ((current_time - e2e_state.last_receive_time[i]) >
|
||||
config->timeout_ms) {
|
||||
/* Timeout error */
|
||||
e2e_state.error_counters[i]++;
|
||||
e2e_state.last_receive_time[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&e2e_state.mutex);
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* @file memory_protection.c
|
||||
* @brief Memory Protection for safety-critical applications
|
||||
*/
|
||||
|
||||
#include "kernel.h"
|
||||
#include "task.h"
|
||||
#include <string.h>
|
||||
|
||||
/* Memory Protection Configuration */
|
||||
#define MPU_MAX_REGIONS 8
|
||||
#define MEMORY_PROTECTION_ALIGNMENT 32 /* 32 bytes minimum */
|
||||
|
||||
/* Memory Region Attributes */
|
||||
typedef struct {
|
||||
uint32_t base_address;
|
||||
uint32_t size;
|
||||
uint8_t permissions;
|
||||
bool executable;
|
||||
bool cacheable;
|
||||
bool bufferable;
|
||||
} MemoryRegion_t;
|
||||
|
||||
/* Memory Protection State */
|
||||
typedef struct {
|
||||
bool initialized;
|
||||
bool enabled;
|
||||
MemoryRegion_t regions[MPU_MAX_REGIONS];
|
||||
uint8_t region_count;
|
||||
TaskHandle_t current_task;
|
||||
Mutex_t mutex;
|
||||
} MemoryProtectionState_t;
|
||||
|
||||
static MemoryProtectionState_t memory_protection;
|
||||
|
||||
/* Initialize Memory Protection */
|
||||
KernelStatus_t memory_protection_init(void) {
|
||||
if (memory_protection.initialized) {
|
||||
return KERNEL_ERROR;
|
||||
}
|
||||
|
||||
memset(&memory_protection, 0, sizeof(MemoryProtectionState_t));
|
||||
memory_protection.enabled = false;
|
||||
memory_protection.region_count = 0;
|
||||
|
||||
mutex_create(&memory_protection.mutex, false);
|
||||
|
||||
memory_protection.initialized = true;
|
||||
return KERNEL_OK;
|
||||
}
|
||||
|
||||
/* Configure Memory Region */
|
||||
KernelStatus_t memory_protection_configure_region(uint32_t base_address,
|
||||
uint32_t size,
|
||||
uint8_t permissions,
|
||||
bool executable) {
|
||||
if (!memory_protection.initialized) {
|
||||
return KERNEL_ERROR;
|
||||
}
|
||||
|
||||
if (memory_protection.region_count >= MPU_MAX_REGIONS) {
|
||||
return KERNEL_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
/* Validate alignment */
|
||||
if ((base_address % MEMORY_PROTECTION_ALIGNMENT) != 0 ||
|
||||
(size % MEMORY_PROTECTION_ALIGNMENT) != 0) {
|
||||
return KERNEL_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
mutex_lock(&memory_protection.mutex, 100);
|
||||
|
||||
MemoryRegion_t* region = &memory_protection.regions[memory_protection.region_count];
|
||||
region->base_address = base_address;
|
||||
region->size = size;
|
||||
region->permissions = permissions;
|
||||
region->executable = executable;
|
||||
|
||||
memory_protection.region_count++;
|
||||
|
||||
mutex_unlock(&memory_protection.mutex);
|
||||
|
||||
return KERNEL_OK;
|
||||
}
|
||||
|
||||
/* Enable Memory Protection */
|
||||
KernelStatus_t memory_protection_enable(void) {
|
||||
if (!memory_protection.initialized) {
|
||||
return KERNEL_ERROR;
|
||||
}
|
||||
|
||||
/* Configure MPU hardware */
|
||||
hal_mpu_enable();
|
||||
|
||||
/* Configure regions */
|
||||
for (uint8_t i = 0; i < memory_protection.region_count; i++) {
|
||||
MemoryRegion_t* region = &memory_protection.regions[i];
|
||||
hal_mpu_configure_region(i, region->base_address, region->size,
|
||||
region->permissions, region->executable);
|
||||
}
|
||||
|
||||
memory_protection.enabled = true;
|
||||
|
||||
return KERNEL_OK;
|
||||
}
|
||||
|
||||
/* Disable Memory Protection */
|
||||
KernelStatus_t memory_protection_disable(void) {
|
||||
if (!memory_protection.initialized) {
|
||||
return KERNEL_ERROR;
|
||||
}
|
||||
|
||||
hal_mpu_disable();
|
||||
memory_protection.enabled = false;
|
||||
|
||||
return KERNEL_OK;
|
||||
}
|
||||
|
||||
/* Set Task Memory Region */
|
||||
KernelStatus_t memory_protection_set_task_region(TaskHandle_t task,
|
||||
uint32_t base_address,
|
||||
uint32_t size) {
|
||||
if (!memory_protection.initialized || task == NULL) {
|
||||
return KERNEL_ERROR;
|
||||
}
|
||||
|
||||
/* Configure task-specific memory region */
|
||||
hal_mpu_configure_task_region(task, base_address, size);
|
||||
|
||||
return KERNEL_OK;
|
||||
}
|
||||
|
||||
/* Check Memory Access */
|
||||
bool memory_protection_check_access(uint32_t address, uint8_t access_type) {
|
||||
if (!memory_protection.initialized || !memory_protection.enabled) {
|
||||
return true; /* Protection disabled */
|
||||
}
|
||||
|
||||
/* Check if address is within any protected region */
|
||||
for (uint8_t i = 0; i < memory_protection.region_count; i++) {
|
||||
MemoryRegion_t* region = &memory_protection.regions[i];
|
||||
|
||||
if (address >= region->base_address &&
|
||||
address < (region->base_address + region->size)) {
|
||||
/* Check permissions */
|
||||
if ((region->permissions & access_type) == 0) {
|
||||
return false; /* Access denied */
|
||||
}
|
||||
return true; /* Access allowed */
|
||||
}
|
||||
}
|
||||
|
||||
return false; /* Address not in any region */
|
||||
}
|
||||
|
||||
/* Memory Protection Fault Handler */
|
||||
void memory_protection_fault_handler(uint32_t fault_address) {
|
||||
/* Log fault */
|
||||
fault_handler_process(2, fault_address, 0);
|
||||
|
||||
/* Enter safe state */
|
||||
while (1) {
|
||||
/* Wait for watchdog reset */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* @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();
|
||||
}
|
||||
Reference in New Issue
Block a user