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,77 @@
|
||||
/**
|
||||
* @file test_adc.c
|
||||
* @brief Hardware tests for ADC
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "kernel.h"
|
||||
#include "adc_driver.h"
|
||||
#include "board.h"
|
||||
|
||||
/* Setup */
|
||||
void setUp(void) {
|
||||
kernel_init();
|
||||
board_init();
|
||||
}
|
||||
|
||||
/* Teardown */
|
||||
void tearDown(void) {
|
||||
kernel_stop();
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Test Cases
|
||||
* ============================================================================ */
|
||||
|
||||
/**
|
||||
* @brief Test ADC initialization
|
||||
*/
|
||||
void test_adc_init(void) {
|
||||
AdcConfig_t config = {
|
||||
.resolution = ADC_RESOLUTION_12BIT,
|
||||
.mode = ADC_MODE_SINGLE,
|
||||
.trigger_source = ADC_TRIGGER_SOFTWARE,
|
||||
.reference = ADC_REFERENCE_VDD,
|
||||
.enable_dma = false,
|
||||
.conversion_frequency = 1000,
|
||||
.channel_count = 1,
|
||||
.channels = {
|
||||
{.channel = 0, .sampling_time = ADC_SAMPLING_28_5_CYCLES}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, adc_init(0, &config));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test ADC conversion
|
||||
*/
|
||||
void test_adc_conversion(void) {
|
||||
uint16_t value = 0;
|
||||
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, adc_read_channel(0, 0, &value, 1000));
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(0, value);
|
||||
TEST_ASSERT_LESS_OR_EQUAL(4095, value); /* 12-bit resolution */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test ADC voltage conversion
|
||||
*/
|
||||
void test_adc_voltage_conversion(void) {
|
||||
/* Test voltage conversion */
|
||||
float voltage = adc_convert_to_voltage(2048, ADC_RESOLUTION_12BIT, 3.3f);
|
||||
TEST_ASSERT_FLOAT_WITHIN(0.1f, 1.65f, voltage);
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Test Runner
|
||||
* ============================================================================ */
|
||||
int main(void) {
|
||||
UNITY_BEGIN();
|
||||
|
||||
RUN_TEST(test_adc_init);
|
||||
RUN_TEST(test_adc_conversion);
|
||||
RUN_TEST(test_adc_voltage_conversion);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* @file test_gpio.c
|
||||
* @brief Hardware tests for GPIO
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "kernel.h"
|
||||
#include "gpio_driver.h"
|
||||
#include "board.h"
|
||||
|
||||
/* Test pins */
|
||||
#define TEST_OUTPUT_PIN 0
|
||||
#define TEST_INPUT_PIN 1
|
||||
|
||||
/* Setup */
|
||||
void setUp(void) {
|
||||
kernel_init();
|
||||
board_init();
|
||||
}
|
||||
|
||||
/* Teardown */
|
||||
void tearDown(void) {
|
||||
kernel_stop();
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Test Cases
|
||||
* ============================================================================ */
|
||||
|
||||
/**
|
||||
* @brief Test GPIO initialization
|
||||
*/
|
||||
void test_gpio_init(void) {
|
||||
GpioPinConfig_t config = {
|
||||
.port = 0,
|
||||
.pin = TEST_OUTPUT_PIN,
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.output_type = GPIO_OUTPUT_PUSH_PULL,
|
||||
.pull = GPIO_PULL_NONE,
|
||||
.speed = GPIO_SPEED_HIGH
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, gpio_init(&config));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test GPIO write and read
|
||||
*/
|
||||
void test_gpio_write_read(void) {
|
||||
/* Configure output pin */
|
||||
GpioPinConfig_t output_config = {
|
||||
.port = 0,
|
||||
.pin = TEST_OUTPUT_PIN,
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.output_type = GPIO_OUTPUT_PUSH_PULL,
|
||||
.pull = GPIO_PULL_NONE,
|
||||
.speed = GPIO_SPEED_HIGH
|
||||
};
|
||||
gpio_init(&output_config);
|
||||
|
||||
/* Write high */
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, gpio_write(0, TEST_OUTPUT_PIN, true));
|
||||
TEST_ASSERT_TRUE(gpio_read(0, TEST_OUTPUT_PIN));
|
||||
|
||||
/* Write low */
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, gpio_write(0, TEST_OUTPUT_PIN, false));
|
||||
TEST_ASSERT_FALSE(gpio_read(0, TEST_OUTPUT_PIN));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test GPIO toggle
|
||||
*/
|
||||
void test_gpio_toggle(void) {
|
||||
GpioPinConfig_t config = {
|
||||
.port = 0,
|
||||
.pin = TEST_OUTPUT_PIN,
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.output_type = GPIO_OUTPUT_PUSH_PULL,
|
||||
.pull = GPIO_PULL_NONE,
|
||||
.speed = GPIO_SPEED_HIGH
|
||||
};
|
||||
gpio_init(&config);
|
||||
|
||||
bool initial_state = gpio_read(0, TEST_OUTPUT_PIN);
|
||||
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, gpio_toggle(0, TEST_OUTPUT_PIN));
|
||||
TEST_ASSERT_NOT_EQUAL(initial_state, gpio_read(0, TEST_OUTPUT_PIN));
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Test Runner
|
||||
* ============================================================================ */
|
||||
int main(void) {
|
||||
UNITY_BEGIN();
|
||||
|
||||
RUN_TEST(test_gpio_init);
|
||||
RUN_TEST(test_gpio_write_read);
|
||||
RUN_TEST(test_gpio_toggle);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @file test_pwm.c
|
||||
* @brief Hardware tests for PWM
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "kernel.h"
|
||||
#include "pwm_driver.h"
|
||||
#include "board.h"
|
||||
|
||||
/* Setup */
|
||||
void setUp(void) {
|
||||
kernel_init();
|
||||
board_init();
|
||||
}
|
||||
|
||||
/* Teardown */
|
||||
void tearDown(void) {
|
||||
kernel_stop();
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Test Cases
|
||||
* ============================================================================ */
|
||||
|
||||
/**
|
||||
* @brief Test PWM initialization
|
||||
*/
|
||||
void test_pwm_init(void) {
|
||||
PwmConfig_t config = {
|
||||
.frequency_hz = 1000,
|
||||
.alignment = PWM_ALIGNMENT_EDGE,
|
||||
.period_ticks = 1000,
|
||||
.prescaler = 100,
|
||||
.channel_count = 1,
|
||||
.channels = {
|
||||
{.channel = 0, .duty_cycle = 0}
|
||||
},
|
||||
.enable_fault_protection = false,
|
||||
.fault_action = PWM_FAULT_DISABLE
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, pwm_init(0, &config));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test PWM duty cycle
|
||||
*/
|
||||
void test_pwm_duty_cycle(void) {
|
||||
/* Set 50% duty cycle */
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, pwm_set_duty_cycle(0, 0, 5000));
|
||||
TEST_ASSERT_EQUAL(5000, pwm_get_duty_cycle(0, 0));
|
||||
|
||||
/* Set 0% duty cycle */
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, pwm_set_duty_cycle(0, 0, 0));
|
||||
TEST_ASSERT_EQUAL(0, pwm_get_duty_cycle(0, 0));
|
||||
|
||||
/* Set 100% duty cycle */
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, pwm_set_duty_cycle(0, 0, 10000));
|
||||
TEST_ASSERT_EQUAL(10000, pwm_get_duty_cycle(0, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test PWM frequency
|
||||
*/
|
||||
void test_pwm_frequency(void) {
|
||||
/* Set frequency */
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, pwm_set_frequency(0, 2000));
|
||||
TEST_ASSERT_EQUAL(2000, pwm_get_frequency(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test PWM start/stop
|
||||
*/
|
||||
void test_pwm_start_stop(void) {
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, pwm_start(0));
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, pwm_stop(0));
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Test Runner
|
||||
* ============================================================================ */
|
||||
int main(void) {
|
||||
UNITY_BEGIN();
|
||||
|
||||
RUN_TEST(test_pwm_init);
|
||||
RUN_TEST(test_pwm_duty_cycle);
|
||||
RUN_TEST(test_pwm_frequency);
|
||||
RUN_TEST(test_pwm_start_stop);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* @file test_can_communication.c
|
||||
* @brief Integration tests for CAN communication
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "kernel.h"
|
||||
#include "can_driver.h"
|
||||
#include "can_tp.h"
|
||||
#include "can_nm.h"
|
||||
#include <string.h>
|
||||
|
||||
/* CAN test variables */
|
||||
static CanMessage_t test_message;
|
||||
static volatile bool message_received = false;
|
||||
static volatile bool message_sent = false;
|
||||
static volatile uint32_t rx_count = 0;
|
||||
|
||||
/* Callback functions */
|
||||
static void test_rx_callback(const CanMessage_t* message) {
|
||||
message_received = true;
|
||||
rx_count++;
|
||||
memcpy(&test_message, message, sizeof(CanMessage_t));
|
||||
}
|
||||
|
||||
static void test_tx_callback(uint32_t mailbox, bool success) {
|
||||
message_sent = success;
|
||||
}
|
||||
|
||||
/* Setup */
|
||||
void setUp(void) {
|
||||
kernel_init();
|
||||
message_received = false;
|
||||
message_sent = false;
|
||||
rx_count = 0;
|
||||
|
||||
/* Initialize CAN */
|
||||
CanConfig_t config = {
|
||||
.nominal_baudrate = CAN_BAUD_500K,
|
||||
.data_baudrate = CAN_BAUD_500K,
|
||||
.frame_type = CAN_FRAME_CLASSIC,
|
||||
.enable_fd = false,
|
||||
.enable_automatic_retransmission = true,
|
||||
.rx_callback = test_rx_callback,
|
||||
.tx_callback = test_tx_callback,
|
||||
.filter_count = 0
|
||||
};
|
||||
|
||||
can_init(&config);
|
||||
}
|
||||
|
||||
/* Teardown */
|
||||
void tearDown(void) {
|
||||
can_deinit();
|
||||
kernel_stop();
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Test Cases
|
||||
* ============================================================================ */
|
||||
|
||||
/**
|
||||
* @brief Test CAN initialization
|
||||
*/
|
||||
void test_can_init(void) {
|
||||
CanStatistics_t stats;
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, can_get_statistics(&stats));
|
||||
TEST_ASSERT_EQUAL(0, stats.tx_messages);
|
||||
TEST_ASSERT_EQUAL(0, stats.rx_messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test CAN message send
|
||||
*/
|
||||
void test_can_send(void) {
|
||||
CanMessage_t msg = {
|
||||
.id = {.id = 0x100, .is_extended = false},
|
||||
.length = 8,
|
||||
.data = {1, 2, 3, 4, 5, 6, 7, 8}
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, can_send_message(&msg, 1000));
|
||||
|
||||
/* Wait for transmission */
|
||||
kernel_delay(10);
|
||||
|
||||
TEST_ASSERT_TRUE(message_sent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test CAN message receive
|
||||
*/
|
||||
void test_can_receive(void) {
|
||||
CanMessage_t msg = {
|
||||
.id = {.id = 0x200, .is_extended = false},
|
||||
.length = 4,
|
||||
.data = {0xAA, 0xBB, 0xCC, 0xDD}
|
||||
};
|
||||
|
||||
/* Simulate received message */
|
||||
can_process_interrupt();
|
||||
|
||||
TEST_ASSERT_TRUE(message_received);
|
||||
TEST_ASSERT_EQUAL(0x200, test_message.id.id);
|
||||
TEST_ASSERT_EQUAL(4, test_message.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test CAN TP multi-frame message
|
||||
*/
|
||||
void test_can_tp_multiframe(void) {
|
||||
CanTpConfig_t tp_config = {
|
||||
.addressing_format = CAN_TP_ADDRESSING_NORMAL,
|
||||
.source_address = 0x100,
|
||||
.target_address = 0x200,
|
||||
.timeout_ms = 1000,
|
||||
.stmin = 10,
|
||||
.block_size = 8,
|
||||
.padding_enabled = true,
|
||||
.padding_byte = 0xAA
|
||||
};
|
||||
|
||||
can_tp_init(&tp_config);
|
||||
|
||||
/* Create test message */
|
||||
uint8_t data[100];
|
||||
for (int i = 0; i < 100; i++) {
|
||||
data[i] = i;
|
||||
}
|
||||
|
||||
CanTpMessage_t tp_msg = {
|
||||
.message_id = 0x300,
|
||||
.data = data,
|
||||
.length = 100,
|
||||
.addressing_format = CAN_TP_ADDRESSING_NORMAL
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, can_tp_send_message(&tp_msg, 5000));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test CAN network management
|
||||
*/
|
||||
void test_can_nm(void) {
|
||||
CanNmConfig_t nm_config = {
|
||||
.node_id = 1,
|
||||
.network_id = 0,
|
||||
.message_id = 0x400,
|
||||
.timeout_ms = 2000,
|
||||
.repeat_message_time_ms = 500,
|
||||
.is_coordinator = false,
|
||||
.sleep_ack_timeout_ms = 100
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, can_nm_init(&nm_config));
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, can_nm_start());
|
||||
|
||||
kernel_delay(100);
|
||||
|
||||
TEST_ASSERT_EQUAL(CAN_NM_NORMAL_OPERATION, can_nm_get_state());
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Test Runner
|
||||
* ============================================================================ */
|
||||
int main(void) {
|
||||
UNITY_BEGIN();
|
||||
|
||||
RUN_TEST(test_can_init);
|
||||
RUN_TEST(test_can_send);
|
||||
RUN_TEST(test_can_receive);
|
||||
RUN_TEST(test_can_tp_multiframe);
|
||||
RUN_TEST(test_can_nm);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* @file test_fault_handling.c
|
||||
* @brief Integration tests for fault handling
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "kernel.h"
|
||||
#include "task.h"
|
||||
#include "fault_handler.h"
|
||||
#include <string.h>
|
||||
|
||||
/* Fault test variables */
|
||||
static volatile uint32_t fault_count = 0;
|
||||
static volatile uint32_t last_fault_type = 0;
|
||||
|
||||
/* Fault callback */
|
||||
static void test_fault_callback(const FaultInfo_t* fault_info) {
|
||||
fault_count++;
|
||||
last_fault_type = fault_info->type;
|
||||
}
|
||||
|
||||
/* Stack overflow test task */
|
||||
static void stack_overflow_task(void* params) {
|
||||
(void)params;
|
||||
|
||||
/* Allocate large array on stack to cause overflow */
|
||||
uint8_t large_array[10000];
|
||||
memset(large_array, 0, sizeof(large_array));
|
||||
|
||||
while (1) {
|
||||
kernel_delay(100);
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup */
|
||||
void setUp(void) {
|
||||
kernel_init();
|
||||
fault_count = 0;
|
||||
last_fault_type = 0;
|
||||
|
||||
fault_handler_register_callback(test_fault_callback);
|
||||
}
|
||||
|
||||
/* Teardown */
|
||||
void tearDown(void) {
|
||||
kernel_stop();
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Test Cases
|
||||
* ============================================================================ */
|
||||
|
||||
/**
|
||||
* @brief Test fault handler initialization
|
||||
*/
|
||||
void test_fault_handler_init(void) {
|
||||
fault_handler_init();
|
||||
TEST_ASSERT_TRUE(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test stack overflow detection
|
||||
*/
|
||||
void test_stack_overflow_detection(void) {
|
||||
TaskConfig_t config = {
|
||||
.name = "overflow",
|
||||
.function = stack_overflow_task,
|
||||
.parameters = NULL,
|
||||
.stack_size = 512, /* Small stack to force overflow */
|
||||
.priority = 1,
|
||||
.period_ticks = 0
|
||||
};
|
||||
|
||||
TaskHandle_t task = task_create(&config);
|
||||
|
||||
kernel_start();
|
||||
kernel_delay(100);
|
||||
|
||||
/* Stack overflow should be detected */
|
||||
TEST_ASSERT_GREATER_THAN(0, fault_count);
|
||||
TEST_ASSERT_EQUAL(FAULT_STACK_OVERFLOW, last_fault_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test fault processing
|
||||
*/
|
||||
void test_fault_process(void) {
|
||||
fault_handler_process(FAULT_HARD_FAULT, 0x20000000, 0x01);
|
||||
|
||||
TEST_ASSERT_EQUAL(1, fault_count);
|
||||
TEST_ASSERT_EQUAL(FAULT_HARD_FAULT, last_fault_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test multiple faults
|
||||
*/
|
||||
void test_multiple_faults(void) {
|
||||
fault_handler_process(FAULT_BUS_FAULT, 0x40000000, 0x02);
|
||||
fault_handler_process(FAULT_USAGE_FAULT, 0x00000000, 0x03);
|
||||
|
||||
TEST_ASSERT_EQUAL(2, fault_count);
|
||||
TEST_ASSERT_EQUAL(FAULT_USAGE_FAULT, last_fault_type);
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Test Runner
|
||||
* ============================================================================ */
|
||||
int main(void) {
|
||||
UNITY_BEGIN();
|
||||
|
||||
RUN_TEST(test_fault_handler_init);
|
||||
RUN_TEST(test_stack_overflow_detection);
|
||||
RUN_TEST(test_fault_process);
|
||||
RUN_TEST(test_multiple_faults);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* @file test_timing.c
|
||||
* @brief Integration tests for timing accuracy
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "kernel.h"
|
||||
#include "task.h"
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Timing test variables */
|
||||
static volatile uint32_t periodic_count = 0;
|
||||
static volatile uint32_t first_period_time = 0;
|
||||
static volatile uint32_t last_period_time = 0;
|
||||
static volatile uint32_t max_period_jitter = 0;
|
||||
|
||||
/* Periodic test task */
|
||||
static void periodic_task(void* params) {
|
||||
(void)params;
|
||||
|
||||
uint32_t current_time = kernel_get_tick_count();
|
||||
|
||||
if (periodic_count == 0) {
|
||||
first_period_time = current_time;
|
||||
} else {
|
||||
uint32_t period = current_time - last_period_time;
|
||||
if (period > max_period_jitter) {
|
||||
max_period_jitter = period;
|
||||
}
|
||||
}
|
||||
|
||||
last_period_time = current_time;
|
||||
periodic_count++;
|
||||
|
||||
while (1) {
|
||||
kernel_delay(10);
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup */
|
||||
void setUp(void) {
|
||||
kernel_init();
|
||||
periodic_count = 0;
|
||||
max_period_jitter = 0;
|
||||
}
|
||||
|
||||
/* Teardown */
|
||||
void tearDown(void) {
|
||||
kernel_stop();
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Test Cases
|
||||
* ============================================================================ */
|
||||
|
||||
/**
|
||||
* @brief Test periodic task timing
|
||||
*/
|
||||
void test_periodic_timing(void) {
|
||||
TaskConfig_t config = {
|
||||
.name = "periodic",
|
||||
.function = periodic_task,
|
||||
.parameters = NULL,
|
||||
.stack_size = 1024,
|
||||
.priority = 1,
|
||||
.period_ticks = 10
|
||||
};
|
||||
|
||||
TaskHandle_t task = task_create(&config);
|
||||
|
||||
kernel_start();
|
||||
kernel_delay(1000); /* Run for 1 second */
|
||||
|
||||
/* Verify task executed */
|
||||
TEST_ASSERT_GREATER_THAN(90, periodic_count);
|
||||
TEST_ASSERT_LESS_THAN(110, periodic_count);
|
||||
|
||||
/* Verify timing accuracy */
|
||||
TEST_ASSERT_LESS_OR_EQUAL(2, max_period_jitter); /* Max 2ms jitter */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test delay accuracy
|
||||
*/
|
||||
void test_delay_accuracy(void) {
|
||||
kernel_start();
|
||||
|
||||
uint32_t start = kernel_get_tick_count();
|
||||
kernel_delay(100);
|
||||
uint32_t end = kernel_get_tick_count();
|
||||
|
||||
uint32_t elapsed = end - start;
|
||||
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(99, elapsed);
|
||||
TEST_ASSERT_LESS_OR_EQUAL(102, elapsed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test tick count
|
||||
*/
|
||||
void test_tick_count(void) {
|
||||
kernel_start();
|
||||
|
||||
uint32_t start = kernel_get_tick_count();
|
||||
kernel_delay(50);
|
||||
uint32_t end = kernel_get_tick_count();
|
||||
|
||||
TEST_ASSERT_EQUAL(50, end - start);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test high-frequency task
|
||||
*/
|
||||
void test_high_frequency_task(void) {
|
||||
TaskConfig_t config = {
|
||||
.name = "fast_task",
|
||||
.function = periodic_task,
|
||||
.parameters = NULL,
|
||||
.stack_size = 1024,
|
||||
.priority = 0,
|
||||
.period_ticks = 1
|
||||
};
|
||||
|
||||
TaskHandle_t task = task_create(&config);
|
||||
|
||||
kernel_start();
|
||||
kernel_delay(100);
|
||||
|
||||
/* 1ms task should execute approximately 100 times */
|
||||
TEST_ASSERT_GREATER_THAN(90, periodic_count);
|
||||
TEST_ASSERT_LESS_THAN(110, periodic_count);
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Test Runner
|
||||
* ============================================================================ */
|
||||
int main(void) {
|
||||
UNITY_BEGIN();
|
||||
|
||||
RUN_TEST(test_periodic_timing);
|
||||
RUN_TEST(test_delay_accuracy);
|
||||
RUN_TEST(test_tick_count);
|
||||
RUN_TEST(test_high_frequency_task);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
/**
|
||||
* @file test_full_system.c
|
||||
* @brief Full system integration tests
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "kernel.h"
|
||||
#include "task.h"
|
||||
#include "semaphore.h"
|
||||
#include "mutex.h"
|
||||
#include "queue.h"
|
||||
#include "can_driver.h"
|
||||
#include "gpio_driver.h"
|
||||
#include "adc_driver.h"
|
||||
#include "pwm_driver.h"
|
||||
#include "dtc_manager.h"
|
||||
#include "watchdog_manager.h"
|
||||
#include <string.h>
|
||||
|
||||
/* System test variables */
|
||||
static volatile bool system_running = false;
|
||||
static volatile uint32_t system_ticks = 0;
|
||||
static Queue_t command_queue;
|
||||
static Semaphore_t system_semaphore;
|
||||
|
||||
/* System tasks */
|
||||
static void sensor_task(void* params) {
|
||||
(void)params;
|
||||
while (1) {
|
||||
/* Read sensors */
|
||||
uint16_t adc_value;
|
||||
adc_read_channel(0, 0, &adc_value, 10);
|
||||
|
||||
kernel_delay(10);
|
||||
}
|
||||
}
|
||||
|
||||
static void control_task(void* params) {
|
||||
(void)params;
|
||||
while (1) {
|
||||
/* Control loop */
|
||||
pwm_set_duty_cycle(0, 0, 5000); /* 50% duty */
|
||||
|
||||
kernel_delay(5);
|
||||
}
|
||||
}
|
||||
|
||||
static void communication_task(void* params) {
|
||||
(void)params;
|
||||
while (1) {
|
||||
CanMessage_t msg = {
|
||||
.id = {.id = 0x100, .is_extended = false},
|
||||
.length = 8,
|
||||
.data = {1, 2, 3, 4, 5, 6, 7, 8}
|
||||
};
|
||||
|
||||
can_send_message(&msg, 100);
|
||||
kernel_delay(50);
|
||||
}
|
||||
}
|
||||
|
||||
static void monitor_task(void* params) {
|
||||
(void)params;
|
||||
while (1) {
|
||||
system_ticks++;
|
||||
watchdog_task_alive(scheduler_get_current_task());
|
||||
kernel_delay(100);
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup */
|
||||
void setUp(void) {
|
||||
kernel_init();
|
||||
system_running = false;
|
||||
system_ticks = 0;
|
||||
|
||||
/* Initialize subsystems */
|
||||
dtc_manager_init();
|
||||
watchdog_manager_init(1000);
|
||||
}
|
||||
|
||||
/* Teardown */
|
||||
void tearDown(void) {
|
||||
kernel_stop();
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Test Cases
|
||||
* ============================================================================ */
|
||||
|
||||
/**
|
||||
* @brief Test full system startup
|
||||
*/
|
||||
void test_system_startup(void) {
|
||||
/* Create all system tasks */
|
||||
TaskConfig_t sensor_config = {
|
||||
.name = "sensor",
|
||||
.function = sensor_task,
|
||||
.parameters = NULL,
|
||||
.stack_size = 1024,
|
||||
.priority = 2,
|
||||
.period_ticks = 0
|
||||
};
|
||||
task_create(&sensor_config);
|
||||
|
||||
TaskConfig_t control_config = {
|
||||
.name = "control",
|
||||
.function = control_task,
|
||||
.parameters = NULL,
|
||||
.stack_size = 1024,
|
||||
.priority = 1,
|
||||
.period_ticks = 0
|
||||
};
|
||||
task_create(&control_config);
|
||||
|
||||
TaskConfig_t comm_config = {
|
||||
.name = "comm",
|
||||
.function = communication_task,
|
||||
.parameters = NULL,
|
||||
.stack_size = 2048,
|
||||
.priority = 3,
|
||||
.period_ticks = 0
|
||||
};
|
||||
task_create(&comm_config);
|
||||
|
||||
TaskConfig_t monitor_config = {
|
||||
.name = "monitor",
|
||||
.function = monitor_task,
|
||||
.parameters = NULL,
|
||||
.stack_size = 1024,
|
||||
.priority = 4,
|
||||
.period_ticks = 0
|
||||
};
|
||||
task_create(&monitor_config);
|
||||
|
||||
/* Start system */
|
||||
kernel_start();
|
||||
system_running = true;
|
||||
|
||||
/* Let system run */
|
||||
kernel_delay(500);
|
||||
|
||||
TEST_ASSERT_TRUE(system_running);
|
||||
TEST_ASSERT_GREATER_THAN(0, system_ticks);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test system communication
|
||||
*/
|
||||
void test_system_communication(void) {
|
||||
/* Create communication test */
|
||||
CanMessage_t test_msg = {
|
||||
.id = {.id = 0x200, .is_extended = false},
|
||||
.length = 4,
|
||||
.data = {0xAA, 0xBB, 0xCC, 0xDD}
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, can_send_message(&test_msg, 1000));
|
||||
|
||||
kernel_delay(10);
|
||||
|
||||
CanStatistics_t stats;
|
||||
can_get_statistics(&stats);
|
||||
TEST_ASSERT_GREATER_THAN(0, stats.tx_messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test system diagnostics
|
||||
*/
|
||||
void test_system_diagnostics(void) {
|
||||
/* Add test DTC */
|
||||
DtcCode_t dtc = {
|
||||
.high_byte = 0x01,
|
||||
.middle_byte = 0x02,
|
||||
.low_byte = 0x03
|
||||
};
|
||||
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, dtc_manager_add_dtc(&dtc, 3));
|
||||
TEST_ASSERT_EQUAL(1, dtc_manager_get_count());
|
||||
|
||||
/* Clear DTCs */
|
||||
TEST_ASSERT_EQUAL(KERNEL_OK, dtc_manager_clear_all());
|
||||
TEST_ASSERT_EQUAL(0, dtc_manager_get_count());
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Test Runner
|
||||
* ============================================================================ */
|
||||
int main(void) {
|
||||
UNITY_BEGIN();
|
||||
|
||||
RUN_TEST(test_system_startup);
|
||||
RUN_TEST(test_system_communication);
|
||||
RUN_TEST(test_system_diagnostics);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* @file test_stress.c
|
||||
* @brief Stress tests for system
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "kernel.h"
|
||||
#include "task.h"
|
||||
#include "semaphore.h"
|
||||
#include "queue.h"
|
||||
#include <string.h>
|
||||
|
||||
/* Stress test constants */
|
||||
#define STRESS_TEST_DURATION 5000 /* 5 seconds */
|
||||
#define MAX_STRESS_TASKS 20
|
||||
#define STRESS_QUEUE_SIZE 100
|
||||
|
||||
/* Stress test variables */
|
||||
static TaskHandle_t stress_tasks[MAX_STRESS_TASKS];
|
||||
static Semaphore_t stress_semaphores[MAX_STRESS_TASKS];
|
||||
static Queue_t stress_queue;
|
||||
static volatile uint32_t task_counts[MAX_STRESS_TASKS];
|
||||
static volatile uint32_t total_executions = 0;
|
||||
static volatile bool stress_test_passed = true;
|
||||
|
||||
/* Stress task function */
|
||||
static void stress_task(void* params) {
|
||||
uint32_t task_id = (uint32_t)params;
|
||||
|
||||
while (1) {
|
||||
/* Increment counters */
|
||||
task_counts[task_id]++;
|
||||
total_executions++;
|
||||
|
||||
/* Semaphore operations */
|
||||
semaphore_take(&stress_semaphores[task_id], 10);
|
||||
semaphore_give(&stress_semaphores[task_id]);
|
||||
|
||||
/* Queue operations */
|
||||
uint32_t data = task_id;
|
||||
queue_send(&stress_queue, &data, 0);
|
||||
queue_receive(&stress_queue, &data, 0);
|
||||
|
||||
/* Random delay */
|
||||
kernel_delay((task_id % 5) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup */
|
||||
void setUp(void) {
|
||||
kernel_init();
|
||||
total_executions = 0;
|
||||
stress_test_passed = true;
|
||||
|
||||
/* Initialize stress test resources */
|
||||
queue_create(&stress_queue, malloc(STRESS_QUEUE_SIZE * sizeof(uint32_t)),
|
||||
sizeof(uint32_t), STRESS_QUEUE_SIZE);
|
||||
|
||||
for (int i = 0; i < MAX_STRESS_TASKS; i++) {
|
||||
semaphore_create(&stress_semaphores[i], SEMAPHORE_BINARY, 1, 1);
|
||||
task_counts[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Teardown */
|
||||
void tearDown(void) {
|
||||
kernel_stop();
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Test Cases
|
||||
* ============================================================================ */
|
||||
|
||||
/**
|
||||
* @brief Test with maximum tasks
|
||||
*/
|
||||
void test_max_tasks_stress(void) {
|
||||
/* Create maximum number of tasks */
|
||||
for (int i = 0; i < MAX_STRESS_TASKS; i++) {
|
||||
TaskConfig_t config = {
|
||||
.name = "stress_task",
|
||||
.function = stress_task,
|
||||
.parameters = (void*)(uint32_t)i,
|
||||
.stack_size = 1024,
|
||||
.priority = i % MAX_PRIORITY_LEVELS,
|
||||
.period_ticks = 0
|
||||
};
|
||||
|
||||
stress_tasks[i] = task_create(&config);
|
||||
TEST_ASSERT_NOT_NULL(stress_tasks[i]);
|
||||
}
|
||||
|
||||
/* Run stress test */
|
||||
kernel_start();
|
||||
kernel_delay(STRESS_TEST_DURATION);
|
||||
|
||||
/* Verify all tasks executed */
|
||||
for (int i = 0; i < MAX_STRESS_TASKS; i++) {
|
||||
TEST_ASSERT_GREATER_THAN(0, task_counts[i]);
|
||||
}
|
||||
|
||||
TEST_ASSERT_GREATER_THAN(1000, total_executions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test context switching stress
|
||||
*/
|
||||
void test_context_switch_stress(void) {
|
||||
/* Create tasks that cause frequent context switches */
|
||||
for (int i = 0; i < 5; i++) {
|
||||
TaskConfig_t config = {
|
||||
.name = "ctx_switch",
|
||||
.function = stress_task,
|
||||
.parameters = (void*)(uint32_t)i,
|
||||
.stack_size = 512,
|
||||
.priority = i,
|
||||
.period_ticks = 0
|
||||
};
|
||||
|
||||
stress_tasks[i] = task_create(&config);
|
||||
}
|
||||
|
||||
kernel_start();
|
||||
kernel_delay(1000);
|
||||
|
||||
SchedulerStatistics_t stats;
|
||||
scheduler_get_statistics(&stats);
|
||||
|
||||
TEST_ASSERT_GREATER_THAN(100, stats.context_switches);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test memory stress
|
||||
*/
|
||||
void test_memory_stress(void) {
|
||||
/* Allocate and free memory repeatedly */
|
||||
void* pointers[100];
|
||||
|
||||
for (int iteration = 0; iteration < 100; iteration++) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
pointers[i] = malloc(128);
|
||||
TEST_ASSERT_NOT_NULL(pointers[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
free(pointers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_ASSERT_TRUE(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test interrupt stress
|
||||
*/
|
||||
void test_interrupt_stress(void) {
|
||||
/* Enable maximum interrupts */
|
||||
kernel_start();
|
||||
|
||||
/* Generate interrupt load */
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
/* Trigger software interrupts */
|
||||
__asm volatile("SVC #0");
|
||||
}
|
||||
|
||||
kernel_delay(100);
|
||||
|
||||
TEST_ASSERT_TRUE(stress_test_passed);
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* Test Runner
|
||||
* ============================================================================ */
|
||||
int main(void) {
|
||||
UNITY_BEGIN();
|
||||
|
||||
RUN_TEST(test_max_tasks_stress);
|
||||
RUN_TEST(test_context_switch_stress);
|
||||
RUN_TEST(test_memory_stress);
|
||||
RUN_TEST(test_interrupt_stress);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user