LCOV - code coverage report
Current view: top level - src - apply_controller.c (source / functions) Hit Total Coverage
Test: coverage.clean.info Lines: 74 79 93.7 %
Date: 2026-05-12 09:00:35 Functions: 10 10 100.0 %

          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             : }

Generated by: LCOV version 1.14