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.
154 lines
4.2 KiB
C
154 lines
4.2 KiB
C
/**
|
|
* @file apply_controller.c
|
|
* @brief Apply/Hold/Release State Machine.
|
|
*
|
|
* @arch SWA-002
|
|
* @reqs SWE-001 SWE-002 SWE-003 SWE-004
|
|
*
|
|
* ASIL: D. This is the safety-critical core logic.
|
|
* Changes require a technical review with 2 approvals.
|
|
*/
|
|
#include <stddef.h>
|
|
|
|
#include "apply_controller.h"
|
|
#include "actuator_driver.h"
|
|
|
|
typedef struct {
|
|
EpbState state;
|
|
uint8_t step_in_state; /* 50ms ticks in the current state */
|
|
EpbStatus last_error;
|
|
uint32_t step_count; /* Watchdog alive counter */
|
|
} ApplyCtx;
|
|
|
|
static ApplyCtx s_ctx;
|
|
|
|
static void enter_state(EpbState new_state)
|
|
{
|
|
s_ctx.state = new_state;
|
|
s_ctx.step_in_state = 0U;
|
|
}
|
|
|
|
static bool release_preconditions_ok(const ApplyInputs* in)
|
|
{
|
|
/* @reqs SWE-005 (Release preconditions) — consumed here */
|
|
return in->engine_running
|
|
&& in->brake_pedal_pressed
|
|
&& in->gear_engaged;
|
|
}
|
|
|
|
static bool apply_request_present(const ApplyInputs* in)
|
|
{
|
|
return (in->sw_state == SWITCH_APPLY) || in->safety_apply_request;
|
|
}
|
|
|
|
static bool release_request_present(const ApplyInputs* in)
|
|
{
|
|
return in->sw_state == SWITCH_RELEASE;
|
|
}
|
|
|
|
static uint16_t min_force(const ApplyInputs* in)
|
|
{
|
|
return (in->left_force_n < in->right_force_n)
|
|
? in->left_force_n : in->right_force_n;
|
|
}
|
|
|
|
EpbStatus apply_ctrl_init(void)
|
|
{
|
|
s_ctx.state = EPB_STATE_RELEASED;
|
|
s_ctx.step_in_state = 0U;
|
|
s_ctx.last_error = EPB_OK;
|
|
s_ctx.step_count = 0U;
|
|
return EPB_OK;
|
|
}
|
|
|
|
void apply_ctrl_step_50ms(const ApplyInputs* in)
|
|
{
|
|
if (in == NULL) {
|
|
s_ctx.last_error = EPB_EINVAL;
|
|
return;
|
|
}
|
|
|
|
/* SWE-002: Watchdog alive counter erhoehen */
|
|
++s_ctx.step_count;
|
|
|
|
if (s_ctx.step_in_state < UINT8_MAX) {
|
|
++s_ctx.step_in_state;
|
|
}
|
|
|
|
switch (s_ctx.state) {
|
|
case EPB_STATE_RELEASED:
|
|
if (apply_request_present(in) && in->standstill) {
|
|
(void)actuator_apply(ACTUATOR_LEFT, 80U);
|
|
(void)actuator_apply(ACTUATOR_RIGHT, 80U);
|
|
enter_state(EPB_STATE_APPLYING);
|
|
}
|
|
break;
|
|
|
|
case EPB_STATE_APPLYING:
|
|
/* SWE-004: Check target clamping force reached */
|
|
if (min_force(in) >= APPLY_TARGET_FORCE_N) {
|
|
(void)actuator_stop(ACTUATOR_LEFT);
|
|
(void)actuator_stop(ACTUATOR_RIGHT);
|
|
enter_state(EPB_STATE_APPLIED);
|
|
} else if (s_ctx.step_in_state >= APPLY_TIMEOUT_50MS) {
|
|
s_ctx.last_error = EPB_ETIMEOUT;
|
|
(void)actuator_stop(ACTUATOR_LEFT);
|
|
(void)actuator_stop(ACTUATOR_RIGHT);
|
|
enter_state(EPB_STATE_ERROR);
|
|
}
|
|
break;
|
|
|
|
case EPB_STATE_APPLIED:
|
|
/* SWE-001: Hold clamping force — re-apply on drop */
|
|
if (min_force(in) < (APPLY_TARGET_FORCE_N - HOLD_TOLERANCE_N)) {
|
|
(void)actuator_apply(ACTUATOR_LEFT, 60U);
|
|
(void)actuator_apply(ACTUATOR_RIGHT, 60U);
|
|
enter_state(EPB_STATE_APPLYING);
|
|
break;
|
|
}
|
|
if (release_request_present(in) && release_preconditions_ok(in)) {
|
|
(void)actuator_release(ACTUATOR_LEFT, 80U);
|
|
(void)actuator_release(ACTUATOR_RIGHT, 80U);
|
|
enter_state(EPB_STATE_RELEASING);
|
|
}
|
|
break;
|
|
|
|
case EPB_STATE_RELEASING:
|
|
if (min_force(in) < HOLD_TOLERANCE_N) {
|
|
(void)actuator_stop(ACTUATOR_LEFT);
|
|
(void)actuator_stop(ACTUATOR_RIGHT);
|
|
enter_state(EPB_STATE_RELEASED);
|
|
} else if (s_ctx.step_in_state >= (APPLY_TIMEOUT_50MS - 6U)) {
|
|
s_ctx.last_error = EPB_ETIMEOUT;
|
|
(void)actuator_stop(ACTUATOR_LEFT);
|
|
(void)actuator_stop(ACTUATOR_RIGHT);
|
|
enter_state(EPB_STATE_ERROR);
|
|
}
|
|
break;
|
|
|
|
case EPB_STATE_ERROR:
|
|
default:
|
|
/* Wait for reset; safe state is Apply, hence no release */
|
|
if (!apply_request_present(in) && !release_request_present(in)) {
|
|
s_ctx.last_error = EPB_OK;
|
|
enter_state(EPB_STATE_RELEASED);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
EpbState apply_ctrl_get_state(void)
|
|
{
|
|
return s_ctx.state;
|
|
}
|
|
|
|
EpbStatus apply_ctrl_last_error(void)
|
|
{
|
|
return s_ctx.last_error;
|
|
}
|
|
|
|
uint32_t apply_ctrl_get_step_count(void)
|
|
{
|
|
return s_ctx.step_count;
|
|
}
|