Line data Source code
1 : /** 2 : * @file apply_controller.c 3 : * @brief Apply/Hold/Release State Machine. 4 : * 5 : * @arch SWA-002 6 : * @reqs SWE-001 SWE-002 SWE-003 SWE-004 7 : * 8 : * ASIL: D. Diese Komponente ist die sicherheitskritische Kernlogik. 9 : * Aenderungen erfordern Technical Review mit 2 Approvals. 10 : */ 11 : #include <stddef.h> 12 : 13 : #include "apply_controller.h" 14 : #include "actuator_driver.h" 15 : 16 : typedef struct { 17 : EpbState state; 18 : uint8_t step_in_state; /* 50ms-Ticks im aktuellen State */ 19 : EpbStatus last_error; 20 : uint32_t step_count; /* Watchdog-Alive-Counter */ 21 : } ApplyCtx; 22 : 23 : static ApplyCtx s_ctx; 24 : 25 36 : static void enter_state(EpbState new_state) 26 : { 27 36 : s_ctx.state = new_state; 28 36 : s_ctx.step_in_state = 0U; 29 36 : } 30 : 31 4 : static bool release_preconditions_ok(const ApplyInputs* in) 32 : { 33 : /* @reqs SWE-005 (Release-Voraussetzungen) — hier konsumiert */ 34 4 : return in->engine_running 35 2 : && in->brake_pedal_pressed 36 6 : && in->gear_engaged; 37 : } 38 : 39 26 : static bool apply_request_present(const ApplyInputs* in) 40 : { 41 26 : return (in->sw_state == SWITCH_APPLY) || in->safety_apply_request; 42 : } 43 : 44 6 : static bool release_request_present(const ApplyInputs* in) 45 : { 46 6 : return in->sw_state == SWITCH_RELEASE; 47 : } 48 : 49 136 : static uint16_t min_force(const ApplyInputs* in) 50 : { 51 136 : return (in->left_force_n < in->right_force_n) 52 136 : ? in->left_force_n : in->right_force_n; 53 : } 54 : 55 24 : EpbStatus apply_ctrl_init(void) 56 : { 57 24 : s_ctx.state = EPB_STATE_RELEASED; 58 24 : s_ctx.step_in_state = 0U; 59 24 : s_ctx.last_error = EPB_OK; 60 24 : s_ctx.step_count = 0U; 61 24 : return EPB_OK; 62 : } 63 : 64 164 : void apply_ctrl_step_50ms(const ApplyInputs* in) 65 : { 66 164 : if (in == NULL) { 67 2 : s_ctx.last_error = EPB_EINVAL; 68 2 : return; 69 : } 70 : 71 : /* SWE-002: Watchdog-Alive-Counter erhoehen */ 72 162 : ++s_ctx.step_count; 73 : 74 162 : if (s_ctx.step_in_state < UINT8_MAX) { 75 162 : ++s_ctx.step_in_state; 76 : } 77 : 78 162 : switch (s_ctx.state) { 79 24 : case EPB_STATE_RELEASED: 80 24 : if (apply_request_present(in) && in->standstill) { 81 16 : (void)actuator_apply(ACTUATOR_LEFT, 80U); 82 16 : (void)actuator_apply(ACTUATOR_RIGHT, 80U); 83 16 : enter_state(EPB_STATE_APPLYING); 84 : } 85 24 : break; 86 : 87 128 : case EPB_STATE_APPLYING: 88 : /* SWE-004: Klemmkraft-Erreichen pruefen */ 89 128 : if (min_force(in) >= APPLY_TARGET_FORCE_N) { 90 8 : (void)actuator_stop(ACTUATOR_LEFT); 91 8 : (void)actuator_stop(ACTUATOR_RIGHT); 92 8 : enter_state(EPB_STATE_APPLIED); 93 120 : } else if (s_ctx.step_in_state >= APPLY_TIMEOUT_50MS) { 94 4 : s_ctx.last_error = EPB_ETIMEOUT; 95 4 : (void)actuator_stop(ACTUATOR_LEFT); 96 4 : (void)actuator_stop(ACTUATOR_RIGHT); 97 4 : enter_state(EPB_STATE_ERROR); 98 : } 99 128 : break; 100 : 101 6 : case EPB_STATE_APPLIED: 102 : /* SWE-001: Klemmkraft halten — bei Unterschreitung nachregeln */ 103 6 : if (min_force(in) < (APPLY_TARGET_FORCE_N - HOLD_TOLERANCE_N)) { 104 2 : (void)actuator_apply(ACTUATOR_LEFT, 60U); 105 2 : (void)actuator_apply(ACTUATOR_RIGHT, 60U); 106 2 : enter_state(EPB_STATE_APPLYING); 107 2 : break; 108 : } 109 4 : if (release_request_present(in) && release_preconditions_ok(in)) { 110 2 : (void)actuator_release(ACTUATOR_LEFT, 80U); 111 2 : (void)actuator_release(ACTUATOR_RIGHT, 80U); 112 2 : enter_state(EPB_STATE_RELEASING); 113 : } 114 4 : break; 115 : 116 2 : case EPB_STATE_RELEASING: 117 2 : if (min_force(in) < HOLD_TOLERANCE_N) { 118 2 : (void)actuator_stop(ACTUATOR_LEFT); 119 2 : (void)actuator_stop(ACTUATOR_RIGHT); 120 2 : enter_state(EPB_STATE_RELEASED); 121 0 : } else if (s_ctx.step_in_state >= (APPLY_TIMEOUT_50MS - 6U)) { 122 0 : s_ctx.last_error = EPB_ETIMEOUT; 123 0 : (void)actuator_stop(ACTUATOR_LEFT); 124 0 : (void)actuator_stop(ACTUATOR_RIGHT); 125 0 : enter_state(EPB_STATE_ERROR); 126 : } 127 2 : break; 128 : 129 2 : case EPB_STATE_ERROR: 130 : default: 131 : /* Auf Reset warten; sicherer Zustand ist Apply, also kein Release */ 132 2 : if (!apply_request_present(in) && !release_request_present(in)) { 133 2 : s_ctx.last_error = EPB_OK; 134 2 : enter_state(EPB_STATE_RELEASED); 135 : } 136 2 : break; 137 : } 138 : } 139 : 140 144 : EpbState apply_ctrl_get_state(void) 141 : { 142 144 : return s_ctx.state; 143 : } 144 : 145 4 : EpbStatus apply_ctrl_last_error(void) 146 : { 147 4 : return s_ctx.last_error; 148 : } 149 : 150 4 : uint32_t apply_ctrl_get_step_count(void) 151 : { 152 4 : return s_ctx.step_count; 153 : }