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
+156
View File
@@ -0,0 +1,156 @@
/**
* @file test_mutex.c
* @brief Unit tests for mutex
*/
#include "unity.h"
#include "kernel.h"
#include "mutex.h"
#include "task.h"
#include <string.h>
/* Test mutexes */
static Mutex_t test_mutex;
static Mutex_t recursive_mutex;
/* Test task for mutex contention */
static TaskHandle_t contention_task;
static volatile bool task_got_mutex = false;
static void mutex_contention_task(void* params) {
(void)params;
/* Try to lock mutex */
if (mutex_lock(&test_mutex, 1000) == KERNEL_OK) {
task_got_mutex = true;
mutex_unlock(&test_mutex);
}
while (1) {
kernel_delay(1000);
}
}
/* Setup */
void setUp(void) {
kernel_init();
/* Create test mutexes */
mutex_create(&test_mutex, false);
mutex_create(&recursive_mutex, true);
task_got_mutex = false;
}
/* Teardown */
void tearDown(void) {
kernel_stop();
}
/* ============================================================================
* Test Cases
* ============================================================================ */
/**
* @brief Test mutex creation
*/
void test_mutex_create(void) {
TEST_ASSERT_NULL(mutex_get_owner(&test_mutex));
}
/**
* @brief Test mutex lock and unlock
*/
void test_mutex_lock_unlock(void) {
TEST_ASSERT_EQUAL(KERNEL_OK, mutex_lock(&test_mutex, 100));
TEST_ASSERT_NOT_NULL(mutex_get_owner(&test_mutex));
TEST_ASSERT_EQUAL(KERNEL_OK, mutex_unlock(&test_mutex));
TEST_ASSERT_NULL(mutex_get_owner(&test_mutex));
}
/**
* @brief Test recursive mutex
*/
void test_recursive_mutex(void) {
/* Lock recursive mutex multiple times */
TEST_ASSERT_EQUAL(KERNEL_OK, mutex_lock(&recursive_mutex, 100));
TEST_ASSERT_EQUAL(KERNEL_OK, mutex_lock(&recursive_mutex, 100));
TEST_ASSERT_EQUAL(KERNEL_OK, mutex_lock(&recursive_mutex, 100));
/* Unlock same number of times */
TEST_ASSERT_EQUAL(KERNEL_OK, mutex_unlock(&recursive_mutex));
TEST_ASSERT_EQUAL(KERNEL_OK, mutex_unlock(&recursive_mutex));
TEST_ASSERT_EQUAL(KERNEL_OK, mutex_unlock(&recursive_mutex));
}
/**
* @brief Test non-recursive mutex
*/
void test_non_recursive_mutex(void) {
/* Lock mutex */
TEST_ASSERT_EQUAL(KERNEL_OK, mutex_lock(&test_mutex, 100));
/* Try to lock again */
TEST_ASSERT_EQUAL(KERNEL_RESOURCE_BUSY, mutex_lock(&test_mutex, 0));
/* Unlock */
TEST_ASSERT_EQUAL(KERNEL_OK, mutex_unlock(&test_mutex));
}
/**
* @brief Test mutex timeout
*/
void test_mutex_timeout(void) {
/* Lock mutex */
TEST_ASSERT_EQUAL(KERNEL_OK, mutex_lock(&test_mutex, 0));
/* Create contention task */
TaskConfig_t config = {
.name = "contention",
.function = mutex_contention_task,
.parameters = NULL,
.stack_size = 1024,
.priority = 1,
.period_ticks = 0
};
contention_task = task_create(&config);
kernel_start();
kernel_delay(100);
/* Task should not have gotten mutex yet */
TEST_ASSERT_FALSE(task_got_mutex);
/* Unlock mutex */
mutex_unlock(&test_mutex);
kernel_delay(100);
/* Task should have gotten mutex */
TEST_ASSERT_TRUE(task_got_mutex);
}
/**
* @brief Test mutex deletion
*/
void test_mutex_delete(void) {
TEST_ASSERT_EQUAL(KERNEL_OK, mutex_delete(&test_mutex));
}
/* ============================================================================
* Test Runner
* ============================================================================ */
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_mutex_create);
RUN_TEST(test_mutex_lock_unlock);
RUN_TEST(test_recursive_mutex);
RUN_TEST(test_non_recursive_mutex);
RUN_TEST(test_mutex_timeout);
RUN_TEST(test_mutex_delete);
return UNITY_END();
}
+129
View File
@@ -0,0 +1,129 @@
/**
* @file test_queue.c
* @brief Unit tests for message queue
*/
#include "unity.h"
#include "kernel.h"
#include "queue.h"
#include <string.h>
/* Test queue */
static Queue_t test_queue;
static uint8_t queue_buffer[256];
/* Test data */
typedef struct {
uint32_t id;
uint8_t data[8];
} TestMessage_t;
/* Setup */
void setUp(void) {
kernel_init();
queue_create(&test_queue, queue_buffer, sizeof(TestMessage_t), 10);
}
/* Teardown */
void tearDown(void) {
kernel_stop();
queue_delete(&test_queue);
}
/* ============================================================================
* Test Cases
* ============================================================================ */
/**
* @brief Test queue creation
*/
void test_queue_create(void) {
TEST_ASSERT_EQUAL(0, queue_get_count(&test_queue));
}
/**
* @brief Test queue send and receive
*/
void test_queue_send_receive(void) {
TestMessage_t send_msg = {
.id = 1,
.data = {1, 2, 3, 4, 5, 6, 7, 8}
};
TestMessage_t recv_msg;
/* Send message */
TEST_ASSERT_EQUAL(KERNEL_OK, queue_send(&test_queue, &send_msg, 100));
TEST_ASSERT_EQUAL(1, queue_get_count(&test_queue));
/* Receive message */
TEST_ASSERT_EQUAL(KERNEL_OK, queue_receive(&test_queue, &recv_msg, 100));
TEST_ASSERT_EQUAL(0, queue_get_count(&test_queue));
/* Verify data */
TEST_ASSERT_EQUAL(send_msg.id, recv_msg.id);
TEST_ASSERT_EQUAL_MEMORY(send_msg.data, recv_msg.data, 8);
}
/**
* @brief Test queue full condition
*/
void test_queue_full(void) {
TestMessage_t msg = {0};
/* Fill queue */
for (int i = 0; i < 10; i++) {
msg.id = i;
TEST_ASSERT_EQUAL(KERNEL_OK, queue_send(&test_queue, &msg, 0));
}
TEST_ASSERT_EQUAL(10, queue_get_count(&test_queue));
/* Try to send when full */
TEST_ASSERT_EQUAL(KERNEL_TIMEOUT, queue_send(&test_queue, &msg, 0));
}
/**
* @brief Test queue empty condition
*/
void test_queue_empty(void) {
TestMessage_t msg;
/* Try to receive from empty queue */
TEST_ASSERT_EQUAL(KERNEL_TIMEOUT, queue_receive(&test_queue, &msg, 0));
}
/**
* @brief Test FIFO ordering
*/
void test_queue_fifo(void) {
TestMessage_t send_msg;
TestMessage_t recv_msg;
/* Send multiple messages */
for (int i = 0; i < 5; i++) {
send_msg.id = i;
TEST_ASSERT_EQUAL(KERNEL_OK, queue_send(&test_queue, &send_msg, 100));
}
/* Receive in order */
for (int i = 0; i < 5; i++) {
TEST_ASSERT_EQUAL(KERNEL_OK, queue_receive(&test_queue, &recv_msg, 100));
TEST_ASSERT_EQUAL(i, recv_msg.id);
}
}
/* ============================================================================
* Test Runner
* ============================================================================ */
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_queue_create);
RUN_TEST(test_queue_send_receive);
RUN_TEST(test_queue_full);
RUN_TEST(test_queue_empty);
RUN_TEST(test_queue_fifo);
return UNITY_END();
}
+214
View File
@@ -0,0 +1,214 @@
/**
* @file test_scheduler.c
* @brief Unit tests for scheduler
*/
#include "unity.h"
#include "kernel.h"
#include "scheduler.h"
#include "task.h"
#include <string.h>
/* Test task handles */
static TaskHandle_t test_tasks[10];
static volatile uint32_t task_execution_count[10];
static volatile uint32_t task_execution_order[100];
static volatile uint32_t execution_index = 0;
/* Test task functions */
static void test_task_0(void* params) {
(void)params;
while (1) {
task_execution_count[0]++;
task_execution_order[execution_index++] = 0;
kernel_delay(10);
}
}
static void test_task_1(void* params) {
(void)params;
while (1) {
task_execution_count[1]++;
task_execution_order[execution_index++] = 1;
kernel_delay(20);
}
}
static void test_task_2(void* params) {
(void)params;
while (1) {
task_execution_count[2]++;
task_execution_order[execution_index++] = 2;
kernel_delay(50);
}
}
/* Test Setup */
void setUp(void) {
/* Reset test state */
memset((void*)task_execution_count, 0, sizeof(task_execution_count));
execution_index = 0;
/* Initialize kernel */
kernel_init();
}
/* Test Teardown */
void tearDown(void) {
/* Stop kernel */
kernel_stop();
}
/* ============================================================================
* Test Cases
* ============================================================================ */
/**
* @brief Test scheduler initialization
*/
void test_scheduler_init(void) {
SchedulerConfig_t config = {
.type = SCHEDULER_PRIORITY_PREEMPTIVE,
.time_slice_ticks = 10,
.enable_deadline_monitoring = true
};
scheduler_init(&config);
/* Verify scheduler is initialized */
TEST_ASSERT_NOT_NULL(scheduler_get_current_task());
}
/**
* @brief Test task creation and scheduling
*/
void test_task_creation(void) {
TaskConfig_t config = {
.name = "test_task",
.function = test_task_0,
.parameters = NULL,
.stack_size = 1024,
.priority = 1,
.period_ticks = 0
};
test_tasks[0] = task_create(&config);
TEST_ASSERT_NOT_NULL(test_tasks[0]);
TEST_ASSERT_EQUAL(1, task_get_priority(test_tasks[0]));
TEST_ASSERT_EQUAL(TASK_READY, task_get_state(test_tasks[0]));
}
/**
* @brief Test priority-based scheduling
*/
void test_priority_scheduling(void) {
/* Create tasks with different priorities */
TaskConfig_t config1 = {
.name = "high_priority",
.function = test_task_0,
.parameters = NULL,
.stack_size = 1024,
.priority = 0,
.period_ticks = 10
};
TaskConfig_t config2 = {
.name = "low_priority",
.function = test_task_1,
.parameters = NULL,
.stack_size = 1024,
.priority = 5,
.period_ticks = 10
};
test_tasks[0] = task_create(&config1);
test_tasks[1] = task_create(&config2);
/* Start kernel */
kernel_start();
/* Let tasks run for 100ms */
kernel_delay(100);
/* High priority task should execute more */
TEST_ASSERT_GREATER_THAN(task_execution_count[1], task_execution_count[0]);
}
/**
* @brief Test round-robin scheduling
*/
void test_round_robin_scheduling(void) {
/* Create two tasks with same priority */
TaskConfig_t config1 = {
.name = "task_a",
.function = test_task_0,
.parameters = NULL,
.stack_size = 1024,
.priority = 3,
.period_ticks = 0
};
TaskConfig_t config2 = {
.name = "task_b",
.function = test_task_1,
.parameters = NULL,
.stack_size = 1024,
.priority = 3,
.period_ticks = 0
};
test_tasks[0] = task_create(&config1);
test_tasks[1] = task_create(&config2);
kernel_start();
kernel_delay(100);
/* Both tasks should execute */
TEST_ASSERT_GREATER_THAN(0, task_execution_count[0]);
TEST_ASSERT_GREATER_THAN(0, task_execution_count[1]);
}
/**
* @brief Test scheduler statistics
*/
void test_scheduler_statistics(void) {
SchedulerStatistics_t stats;
scheduler_get_statistics(&stats);
TEST_ASSERT_GREATER_THAN(0, stats.context_switches);
TEST_ASSERT_GREATER_OR_EQUAL(0, stats.preemptions);
}
/**
* @brief Test scheduler lock/unlock
*/
void test_scheduler_lock_unlock(void) {
/* Lock scheduler */
scheduler_lock();
/* Try to yield */
scheduler_yield();
/* Unlock scheduler */
scheduler_unlock();
TEST_ASSERT_TRUE(true);
}
/* ============================================================================
* Test Runner
* ============================================================================ */
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_scheduler_init);
RUN_TEST(test_task_creation);
RUN_TEST(test_priority_scheduling);
RUN_TEST(test_round_robin_scheduling);
RUN_TEST(test_scheduler_statistics);
RUN_TEST(test_scheduler_lock_unlock);
return UNITY_END();
}
+114
View File
@@ -0,0 +1,114 @@
/**
* @file test_semaphore.c
* @brief Unit tests for semaphore
*/
#include "unity.h"
#include "kernel.h"
#include "semaphore.h"
#include <string.h>
/* Test semaphores */
static Semaphore_t binary_sem;
static Semaphore_t counting_sem;
static Semaphore_t mutex_sem;
/* Setup */
void setUp(void) {
kernel_init();
/* Create test semaphores */
semaphore_create(&binary_sem, SEMAPHORE_BINARY, 1, 1);
semaphore_create(&counting_sem, SEMAPHORE_COUNTING, 0, 10);
semaphore_create(&mutex_sem, SEMAPHORE_MUTEX, 1, 1);
}
/* Teardown */
void tearDown(void) {
kernel_stop();
}
/* ============================================================================
* Test Cases
* ============================================================================ */
/**
* @brief Test binary semaphore creation
*/
void test_binary_semaphore_create(void) {
TEST_ASSERT_EQUAL(1, semaphore_get_count(&binary_sem));
}
/**
* @brief Test counting semaphore creation
*/
void test_counting_semaphore_create(void) {
TEST_ASSERT_EQUAL(0, semaphore_get_count(&counting_sem));
}
/**
* @brief Test semaphore take and give
*/
void test_semaphore_take_give(void) {
/* Take binary semaphore */
TEST_ASSERT_EQUAL(KERNEL_OK, semaphore_take(&binary_sem, 100));
TEST_ASSERT_EQUAL(0, semaphore_get_count(&binary_sem));
/* Give binary semaphore */
TEST_ASSERT_EQUAL(KERNEL_OK, semaphore_give(&binary_sem));
TEST_ASSERT_EQUAL(1, semaphore_get_count(&binary_sem));
}
/**
* @brief Test semaphore timeout
*/
void test_semaphore_timeout(void) {
/* Take the only available semaphore */
TEST_ASSERT_EQUAL(KERNEL_OK, semaphore_take(&binary_sem, 0));
/* Try to take again with timeout */
TEST_ASSERT_EQUAL(KERNEL_TIMEOUT, semaphore_take(&binary_sem, 10));
}
/**
* @brief Test counting semaphore operations
*/
void test_counting_semaphore_operations(void) {
/* Give multiple times */
for (int i = 0; i < 5; i++) {
TEST_ASSERT_EQUAL(KERNEL_OK, semaphore_give(&counting_sem));
}
TEST_ASSERT_EQUAL(5, semaphore_get_count(&counting_sem));
/* Take multiple times */
for (int i = 0; i < 3; i++) {
TEST_ASSERT_EQUAL(KERNEL_OK, semaphore_take(&counting_sem, 0));
}
TEST_ASSERT_EQUAL(2, semaphore_get_count(&counting_sem));
}
/**
* @brief Test semaphore deletion
*/
void test_semaphore_delete(void) {
TEST_ASSERT_EQUAL(KERNEL_OK, semaphore_delete(&binary_sem));
TEST_ASSERT_EQUAL(0, semaphore_get_count(&binary_sem));
}
/* ============================================================================
* Test Runner
* ============================================================================ */
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_binary_semaphore_create);
RUN_TEST(test_counting_semaphore_create);
RUN_TEST(test_semaphore_take_give);
RUN_TEST(test_semaphore_timeout);
RUN_TEST(test_counting_semaphore_operations);
RUN_TEST(test_semaphore_delete);
return UNITY_END();
}
+184
View File
@@ -0,0 +1,184 @@
/**
* @file test_task.c
* @brief Unit tests for task management
*/
#include "unity.h"
#include "kernel.h"
#include "task.h"
#include <string.h>
/* Test variables */
static TaskHandle_t test_task_handle;
static volatile bool task_executed = false;
static volatile uint32_t task_execution_count = 0;
/* Test task function */
static void simple_task(void* params) {
(void)params;
task_executed = true;
task_execution_count++;
/* Task should terminate after execution */
while (1) {
kernel_delay(1000);
}
}
/* Setup */
void setUp(void) {
task_executed = false;
task_execution_count = 0;
kernel_init();
}
/* Teardown */
void tearDown(void) {
kernel_stop();
}
/* ============================================================================
* Test Cases
* ============================================================================ */
/**
* @brief Test task creation
*/
void test_task_create(void) {
TaskConfig_t config = {
.name = "test_task",
.function = simple_task,
.parameters = NULL,
.stack_size = 1024,
.priority = 1,
.period_ticks = 0
};
test_task_handle = task_create(&config);
TEST_ASSERT_NOT_NULL(test_task_handle);
TEST_ASSERT_EQUAL_STRING("test_task", test_task_handle->name);
TEST_ASSERT_EQUAL(1, task_get_priority(test_task_handle));
}
/**
* @brief Test task creation with invalid parameters
*/
void test_task_create_invalid(void) {
TaskConfig_t config = {
.name = NULL,
.function = NULL,
.parameters = NULL,
.stack_size = 0,
.priority = 100,
.period_ticks = 0
};
test_task_handle = task_create(&config);
TEST_ASSERT_NULL(test_task_handle);
}
/**
* @brief Test task suspend and resume
*/
void test_task_suspend_resume(void) {
TaskConfig_t config = {
.name = "suspend_test",
.function = simple_task,
.parameters = NULL,
.stack_size = 1024,
.priority = 2,
.period_ticks = 0
};
test_task_handle = task_create(&config);
/* Suspend task */
TEST_ASSERT_EQUAL(KERNEL_OK, task_suspend(test_task_handle));
TEST_ASSERT_EQUAL(TASK_SUSPENDED, task_get_state(test_task_handle));
/* Resume task */
TEST_ASSERT_EQUAL(KERNEL_OK, task_resume(test_task_handle));
TEST_ASSERT_EQUAL(TASK_READY, task_get_state(test_task_handle));
}
/**
* @brief Test task priority change
*/
void test_task_set_priority(void) {
TaskConfig_t config = {
.name = "priority_test",
.function = simple_task,
.parameters = NULL,
.stack_size = 1024,
.priority = 3,
.period_ticks = 0
};
test_task_handle = task_create(&config);
/* Change priority */
TEST_ASSERT_EQUAL(KERNEL_OK, task_set_priority(test_task_handle, 1));
TEST_ASSERT_EQUAL(1, task_get_priority(test_task_handle));
/* Invalid priority */
TEST_ASSERT_EQUAL(KERNEL_INVALID_PARAMETER,
task_set_priority(test_task_handle, 100));
}
/**
* @brief Test task statistics
*/
void test_task_statistics(void) {
TaskConfig_t config = {
.name = "stats_test",
.function = simple_task,
.parameters = NULL,
.stack_size = 1024,
.priority = 4,
.period_ticks = 10
};
test_task_handle = task_create(&config);
kernel_start();
kernel_delay(100);
TaskStatistics_t stats;
TEST_ASSERT_EQUAL(KERNEL_OK, task_get_statistics(test_task_handle, &stats));
TEST_ASSERT_GREATER_THAN(0, stats.execution_count);
}
/**
* @brief Test task deletion
*/
void test_task_delete(void) {
TaskConfig_t config = {
.name = "delete_test",
.function = simple_task,
.parameters = NULL,
.stack_size = 1024,
.priority = 5,
.period_ticks = 0
};
test_task_handle = task_create(&config);
TEST_ASSERT_EQUAL(KERNEL_OK, task_delete(test_task_handle));
}
/* ============================================================================
* Test Runner
* ============================================================================ */
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_task_create);
RUN_TEST(test_task_create_invalid);
RUN_TEST(test_task_suspend_resume);
RUN_TEST(test_task_set_priority);
RUN_TEST(test_task_statistics);
RUN_TEST(test_task_delete);
return UNITY_END();
}