fb2c083551
Validate / build-test (macos-latest) (push) Failing after 3s
Validate / build-test (windows-latest) (push) Failing after 15s
Validate / build-test (ubuntu-latest) (push) Successful in 17s
Validate / reports (push) Successful in 50s
Release / release (push) Successful in 50s
Phase 2 of the English translation: Word documents (filled, EPB-specific): - 8 plans (PID, PM, QA, SWE, Test, Project Manual, CM, RM) - 6 safety docs (HARA, Safety Case, FMEDA, MISRA Compliance, Verification Report, Tool Qualification Cppcheck) - 2 manuals (User, Service) - 3 audit artefacts (Review minutes, NC-001, MISRA-REC-001) - All regenerated via pandoc from English markdown sources Code, tests, headers: - All file headers, struct comments, function docstrings in English - All test names (TEST_BEGIN strings) translated - Inline comments translated - 46 tests still green after translation CI workflows: - All step names in English - Step descriptions, comments, release notes template in English README.md fully rewritten in English with proper guided tour. Phase 3 (still pending): dev-process repo templates + toolstack/setup docs.
158 lines
4.6 KiB
C
158 lines
4.6 KiB
C
/**
|
|
* @file test_actuator_driver.c
|
|
* @brief Unit tests for the Actuator Driver.
|
|
*
|
|
* @reqs SWE-006 SWE-013 SWE-014 SWE-015
|
|
* @arch SWA-003
|
|
*/
|
|
#include "../unit_test_framework.h"
|
|
#include "../../src/actuator_driver.h"
|
|
|
|
TestStats g_test_stats = {0, 0};
|
|
|
|
static void test_init(void)
|
|
{
|
|
TEST_BEGIN("init -> both actuators STOP, 0 mA");
|
|
ASSERT_EQ(actuator_init(), EPB_OK);
|
|
ActuatorStatus l = actuator_get_status(ACTUATOR_LEFT);
|
|
ActuatorStatus r = actuator_get_status(ACTUATOR_RIGHT);
|
|
ASSERT_EQ(l.direction, ACT_DIR_STOP);
|
|
ASSERT_EQ(r.direction, ACT_DIR_STOP);
|
|
ASSERT_EQ(l.current_ma, 0);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_apply_invalid_id(void)
|
|
{
|
|
TEST_BEGIN("apply: invalid ID -> EINVAL");
|
|
(void)actuator_init();
|
|
ASSERT_EQ(actuator_apply((ActuatorId)42, 50), EPB_EINVAL);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_apply_pwm_out_of_range(void)
|
|
{
|
|
TEST_BEGIN("apply: PWM > 100% -> EINVAL");
|
|
(void)actuator_init();
|
|
ASSERT_EQ(actuator_apply(ACTUATOR_LEFT, 101), EPB_EINVAL);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_apply_normal(void)
|
|
{
|
|
TEST_BEGIN("apply normal -> direction=APPLY, pwm=80");
|
|
(void)actuator_init();
|
|
ASSERT_EQ(actuator_apply(ACTUATOR_LEFT, 80), EPB_OK);
|
|
ActuatorStatus s = actuator_get_status(ACTUATOR_LEFT);
|
|
ASSERT_EQ(s.direction, ACT_DIR_APPLY);
|
|
ASSERT_EQ(s.pwm_percent, 80);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_release_normal(void)
|
|
{
|
|
TEST_BEGIN("release normal -> direction=RELEASE");
|
|
(void)actuator_init();
|
|
ASSERT_EQ(actuator_release(ACTUATOR_LEFT, 70), EPB_OK);
|
|
ActuatorStatus s = actuator_get_status(ACTUATOR_LEFT);
|
|
ASSERT_EQ(s.direction, ACT_DIR_RELEASE);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_isr_samples_current(void)
|
|
{
|
|
TEST_BEGIN("ISR sample sets current_ma and peak");
|
|
(void)actuator_init();
|
|
(void)actuator_apply(ACTUATOR_LEFT, 80);
|
|
actuator_isr_1khz(ACTUATOR_LEFT, 3000);
|
|
ActuatorStatus s = actuator_get_status(ACTUATOR_LEFT);
|
|
ASSERT_EQ(s.current_ma, 3000);
|
|
ASSERT_EQ(s.peak_current_ma, 3000);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_overcurrent_cutoff_after_100ms(void)
|
|
{
|
|
TEST_BEGIN("Overcurrent > 8 A for 100 ms -> STOP + overcurrent flag");
|
|
(void)actuator_init();
|
|
(void)actuator_apply(ACTUATOR_LEFT, 80);
|
|
/* 100 samples (= 100 ms at 1 kHz) above 8 A */
|
|
for (int i = 0; i < 100; ++i) {
|
|
actuator_isr_1khz(ACTUATOR_LEFT, 8500);
|
|
}
|
|
ActuatorStatus s = actuator_get_status(ACTUATOR_LEFT);
|
|
ASSERT_EQ(s.direction, ACT_DIR_STOP);
|
|
ASSERT_TRUE(s.overcurrent);
|
|
ASSERT_EQ(s.last_error, EPB_EOVERCURRENT);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_overcurrent_below_window_no_cutoff(void)
|
|
{
|
|
TEST_BEGIN("Overcurrent < 100 ms does not trip yet");
|
|
(void)actuator_init();
|
|
(void)actuator_apply(ACTUATOR_LEFT, 80);
|
|
for (int i = 0; i < 50; ++i) {
|
|
actuator_isr_1khz(ACTUATOR_LEFT, 8500);
|
|
}
|
|
ActuatorStatus s = actuator_get_status(ACTUATOR_LEFT);
|
|
ASSERT_EQ(s.direction, ACT_DIR_APPLY);
|
|
ASSERT_TRUE(!s.overcurrent);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_overcurrent_blocks_subsequent_apply(void)
|
|
{
|
|
TEST_BEGIN("after overcurrent: subsequent apply -> EOVERCURRENT");
|
|
(void)actuator_init();
|
|
(void)actuator_apply(ACTUATOR_LEFT, 80);
|
|
for (int i = 0; i < 120; ++i) {
|
|
actuator_isr_1khz(ACTUATOR_LEFT, 9000);
|
|
}
|
|
EpbStatus rc = actuator_apply(ACTUATOR_LEFT, 80);
|
|
ASSERT_EQ(rc, EPB_EOVERCURRENT);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_clamping_force_estimate(void)
|
|
{
|
|
TEST_BEGIN("Clamping force estimation from peak current (SWE-015)");
|
|
(void)actuator_init();
|
|
(void)actuator_apply(ACTUATOR_LEFT, 80);
|
|
actuator_isr_1khz(ACTUATOR_LEFT, 4000); /* 4 A peak */
|
|
actuator_isr_1khz(ACTUATOR_LEFT, 3500); /* then lower */
|
|
ActuatorStatus s = actuator_get_status(ACTUATOR_LEFT);
|
|
/* F = (4000 * 2500) / 1000 = 10000 N */
|
|
ASSERT_EQ(s.clamping_force_n, 10000);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_stop_clears_pwm(void)
|
|
{
|
|
TEST_BEGIN("stop -> direction=STOP, pwm=0");
|
|
(void)actuator_init();
|
|
(void)actuator_apply(ACTUATOR_LEFT, 80);
|
|
(void)actuator_stop(ACTUATOR_LEFT);
|
|
ActuatorStatus s = actuator_get_status(ACTUATOR_LEFT);
|
|
ASSERT_EQ(s.direction, ACT_DIR_STOP);
|
|
ASSERT_EQ(s.pwm_percent, 0);
|
|
TEST_END();
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
printf("== test_actuator_driver ==\n");
|
|
test_init();
|
|
test_apply_invalid_id();
|
|
test_apply_pwm_out_of_range();
|
|
test_apply_normal();
|
|
test_release_normal();
|
|
test_isr_samples_current();
|
|
test_overcurrent_cutoff_after_100ms();
|
|
test_overcurrent_below_window_no_cutoff();
|
|
test_overcurrent_blocks_subsequent_apply();
|
|
test_clamping_force_estimate();
|
|
test_stop_clears_pwm();
|
|
TEST_SUMMARY();
|
|
}
|