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.
241 lines
7.0 KiB
C
241 lines
7.0 KiB
C
/**
|
|
* @file test_apply_controller.c
|
|
* @brief Unit tests for the Apply Controller (ASIL-D core).
|
|
*
|
|
* @reqs SWE-001 SWE-002 SWE-003 SWE-004 SWE-005
|
|
* @arch SWA-002
|
|
*/
|
|
#include "../unit_test_framework.h"
|
|
#include "../../src/apply_controller.h"
|
|
#include "../../src/actuator_driver.h"
|
|
|
|
TestStats g_test_stats = {0, 0};
|
|
|
|
static ApplyInputs make_idle_inputs(void)
|
|
{
|
|
ApplyInputs in = {0};
|
|
in.sw_state = SWITCH_NEUTRAL;
|
|
in.standstill = true;
|
|
in.engine_running = true;
|
|
in.brake_pedal_pressed = true;
|
|
in.gear_engaged = true;
|
|
in.safety_apply_request = false;
|
|
in.left_force_n = 0;
|
|
in.right_force_n = 0;
|
|
return in;
|
|
}
|
|
|
|
static void apply_full_cycle_until_state(ApplyInputs* in, EpbState target, int max_steps)
|
|
{
|
|
for (int i = 0; i < max_steps; ++i) {
|
|
apply_ctrl_step_50ms(in);
|
|
if (apply_ctrl_get_state() == target) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void test_init(void)
|
|
{
|
|
TEST_BEGIN("init -> RELEASED");
|
|
(void)actuator_init();
|
|
ASSERT_EQ(apply_ctrl_init(), EPB_OK);
|
|
ASSERT_EQ(apply_ctrl_get_state(), EPB_STATE_RELEASED);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_null_input(void)
|
|
{
|
|
TEST_BEGIN("step_50ms(NULL) -> last_error=EINVAL");
|
|
(void)actuator_init();
|
|
(void)apply_ctrl_init();
|
|
apply_ctrl_step_50ms(NULL);
|
|
ASSERT_EQ(apply_ctrl_last_error(), EPB_EINVAL);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_apply_request_starts_applying(void)
|
|
{
|
|
TEST_BEGIN("Apply request at standstill -> APPLYING");
|
|
(void)actuator_init();
|
|
(void)apply_ctrl_init();
|
|
ApplyInputs in = make_idle_inputs();
|
|
in.sw_state = SWITCH_APPLY;
|
|
apply_ctrl_step_50ms(&in);
|
|
ASSERT_EQ(apply_ctrl_get_state(), EPB_STATE_APPLYING);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_no_apply_without_standstill(void)
|
|
{
|
|
TEST_BEGIN("Apply request without standstill is ignored");
|
|
(void)actuator_init();
|
|
(void)apply_ctrl_init();
|
|
ApplyInputs in = make_idle_inputs();
|
|
in.standstill = false;
|
|
in.sw_state = SWITCH_APPLY;
|
|
apply_ctrl_step_50ms(&in);
|
|
ASSERT_EQ(apply_ctrl_get_state(), EPB_STATE_RELEASED);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_applying_reaches_applied_on_target_force(void)
|
|
{
|
|
TEST_BEGIN("APPLYING -> APPLIED when both clamping forces >= target");
|
|
(void)actuator_init();
|
|
(void)apply_ctrl_init();
|
|
ApplyInputs in = make_idle_inputs();
|
|
in.sw_state = SWITCH_APPLY;
|
|
apply_ctrl_step_50ms(&in); /* -> APPLYING */
|
|
in.sw_state = SWITCH_NEUTRAL;
|
|
in.left_force_n = 12000;
|
|
in.right_force_n = 12000;
|
|
apply_ctrl_step_50ms(&in);
|
|
ASSERT_EQ(apply_ctrl_get_state(), EPB_STATE_APPLIED);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_applying_timeout_to_error(void)
|
|
{
|
|
TEST_BEGIN("APPLYING timeout (>30 steps) -> ERROR");
|
|
(void)actuator_init();
|
|
(void)apply_ctrl_init();
|
|
ApplyInputs in = make_idle_inputs();
|
|
in.sw_state = SWITCH_APPLY;
|
|
apply_ctrl_step_50ms(&in); /* -> APPLYING */
|
|
in.sw_state = SWITCH_NEUTRAL;
|
|
/* Clamping forces stay at 0 -> timeout after 30 steps */
|
|
apply_full_cycle_until_state(&in, EPB_STATE_ERROR, 35);
|
|
ASSERT_EQ(apply_ctrl_get_state(), EPB_STATE_ERROR);
|
|
ASSERT_EQ(apply_ctrl_last_error(), EPB_ETIMEOUT);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_applied_holds_force(void)
|
|
{
|
|
TEST_BEGIN("APPLIED maintains clamping force (SWE-001)");
|
|
(void)actuator_init();
|
|
(void)apply_ctrl_init();
|
|
ApplyInputs in = make_idle_inputs();
|
|
in.sw_state = SWITCH_APPLY;
|
|
apply_ctrl_step_50ms(&in);
|
|
in.sw_state = SWITCH_NEUTRAL;
|
|
in.left_force_n = 12000;
|
|
in.right_force_n = 12000;
|
|
apply_ctrl_step_50ms(&in); /* -> APPLIED */
|
|
|
|
/* Clamping force drops to 10000 (below tolerance threshold 10800) */
|
|
in.left_force_n = 10000;
|
|
in.right_force_n = 10000;
|
|
apply_ctrl_step_50ms(&in);
|
|
/* Apply controller must re-apply -> APPLYING */
|
|
ASSERT_EQ(apply_ctrl_get_state(), EPB_STATE_APPLYING);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_release_requires_preconditions(void)
|
|
{
|
|
TEST_BEGIN("Release without engine is rejected");
|
|
(void)actuator_init();
|
|
(void)apply_ctrl_init();
|
|
ApplyInputs in = make_idle_inputs();
|
|
in.sw_state = SWITCH_APPLY;
|
|
apply_ctrl_step_50ms(&in);
|
|
in.sw_state = SWITCH_NEUTRAL;
|
|
in.left_force_n = 12000;
|
|
in.right_force_n = 12000;
|
|
apply_ctrl_step_50ms(&in); /* -> APPLIED */
|
|
|
|
in.sw_state = SWITCH_RELEASE;
|
|
in.engine_running = false;
|
|
apply_ctrl_step_50ms(&in);
|
|
ASSERT_EQ(apply_ctrl_get_state(), EPB_STATE_APPLIED);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_release_with_preconditions(void)
|
|
{
|
|
TEST_BEGIN("Release with all preconditions -> RELEASING -> RELEASED");
|
|
(void)actuator_init();
|
|
(void)apply_ctrl_init();
|
|
ApplyInputs in = make_idle_inputs();
|
|
in.sw_state = SWITCH_APPLY;
|
|
apply_ctrl_step_50ms(&in);
|
|
in.sw_state = SWITCH_NEUTRAL;
|
|
in.left_force_n = 12000;
|
|
in.right_force_n = 12000;
|
|
apply_ctrl_step_50ms(&in); /* APPLIED */
|
|
|
|
in.sw_state = SWITCH_RELEASE;
|
|
apply_ctrl_step_50ms(&in);
|
|
ASSERT_EQ(apply_ctrl_get_state(), EPB_STATE_RELEASING);
|
|
|
|
in.sw_state = SWITCH_NEUTRAL;
|
|
in.left_force_n = 0;
|
|
in.right_force_n = 0;
|
|
apply_ctrl_step_50ms(&in);
|
|
ASSERT_EQ(apply_ctrl_get_state(), EPB_STATE_RELEASED);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_safety_apply_request(void)
|
|
{
|
|
TEST_BEGIN("Safety Manager apply request (Hill-Hold/Auto-Apply)");
|
|
(void)actuator_init();
|
|
(void)apply_ctrl_init();
|
|
ApplyInputs in = make_idle_inputs();
|
|
in.sw_state = SWITCH_NEUTRAL;
|
|
in.safety_apply_request = true;
|
|
apply_ctrl_step_50ms(&in);
|
|
ASSERT_EQ(apply_ctrl_get_state(), EPB_STATE_APPLYING);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_watchdog_alive_counter(void)
|
|
{
|
|
TEST_BEGIN("Step counter increases monotonically (SWE-002 watchdog alive)");
|
|
(void)actuator_init();
|
|
(void)apply_ctrl_init();
|
|
ApplyInputs in = make_idle_inputs();
|
|
uint32_t before = apply_ctrl_get_step_count();
|
|
apply_ctrl_step_50ms(&in);
|
|
apply_ctrl_step_50ms(&in);
|
|
apply_ctrl_step_50ms(&in);
|
|
ASSERT_EQ(apply_ctrl_get_step_count(), before + 3);
|
|
TEST_END();
|
|
}
|
|
|
|
static void test_error_state_recoverable(void)
|
|
{
|
|
TEST_BEGIN("ERROR -> RELEASED on neutral switch");
|
|
(void)actuator_init();
|
|
(void)apply_ctrl_init();
|
|
ApplyInputs in = make_idle_inputs();
|
|
in.sw_state = SWITCH_APPLY;
|
|
apply_ctrl_step_50ms(&in);
|
|
in.sw_state = SWITCH_NEUTRAL;
|
|
apply_full_cycle_until_state(&in, EPB_STATE_ERROR, 35);
|
|
ASSERT_EQ(apply_ctrl_get_state(), EPB_STATE_ERROR);
|
|
apply_ctrl_step_50ms(&in);
|
|
ASSERT_EQ(apply_ctrl_get_state(), EPB_STATE_RELEASED);
|
|
TEST_END();
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
printf("== test_apply_controller ==\n");
|
|
test_init();
|
|
test_null_input();
|
|
test_apply_request_starts_applying();
|
|
test_no_apply_without_standstill();
|
|
test_applying_reaches_applied_on_target_force();
|
|
test_applying_timeout_to_error();
|
|
test_applied_holds_force();
|
|
test_release_requires_preconditions();
|
|
test_release_with_preconditions();
|
|
test_safety_apply_request();
|
|
test_watchdog_alive_counter();
|
|
test_error_state_recoverable();
|
|
TEST_SUMMARY();
|
|
}
|