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:
root
2026-08-23 03:35:29 -04:00
parent f113bf0a05
commit ca13734bf0
151 changed files with 23945 additions and 0 deletions
+280
View File
@@ -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);
}
+165
View File
@@ -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 */
}
}
+212
View File
@@ -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();
}