Initial commit: demo-epb v1.0 — Elektrische Parkbremse Demo
Vollstaendige Demo des slohmaier Dev Process anhand einer EPB-Steuergeraet- Software. Zeigt ASPICE 4.0 / ISO 26262-konforme Entwicklung im Monorepo. Inhalte: - 5 Plaene (PID, PM-, QA-, SWE-, Test-Plan) in Word, ausgefuellt mit EPB-spezifischen Inhalten - 10 System-Anforderungen + 25 Software-Anforderungen (Doorstop-MD) - 5 System-Architektur-Elemente + 10 Software-Architektur-Elemente mit PlantUML-Diagrammen und vollstaendigem Mapping - 3 implementierte Komponenten (Apply Controller D, Actuator Driver B, Switch Debouncer QM) plus 7 Header-Stubs - 28 Unit-Tests, alle gruen, mit Coverage- und MISRA-Build-Targets - Audit-Artefakte: 1 Review-Protokoll, 1 Non-Conformity, 1 MISRA-Record - Gitea-Actions-CI-Pipeline (validate.yml) - Doorstop-Konfiguration fuer bidirektionale Traceability - Generator-Skript fuer alle 50 Reqs/Arch-Elemente aus Strukturdaten - README mit gefuehrter Tour fuer Prospects
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* @file actuator_driver.c
|
||||
* @brief Implementierung der EPB-Aktor-Ansteuerung.
|
||||
*
|
||||
* @arch SWA-003
|
||||
* @reqs SWE-006 SWE-013 SWE-014 SWE-015
|
||||
*
|
||||
* ASIL: B.
|
||||
*/
|
||||
#include "actuator_driver.h"
|
||||
|
||||
typedef struct {
|
||||
ActuatorStatus status;
|
||||
uint16_t over_ms; /* Millisekunden ueber Strom-Limit (zaehlt in 1 kHz ISR) */
|
||||
} ActuatorCtx;
|
||||
|
||||
static ActuatorCtx s_ctx[ACTUATOR_COUNT];
|
||||
|
||||
static bool is_valid_id(ActuatorId id)
|
||||
{
|
||||
return (id == ACTUATOR_LEFT) || (id == ACTUATOR_RIGHT);
|
||||
}
|
||||
|
||||
EpbStatus actuator_init(void)
|
||||
{
|
||||
for (uint8_t i = 0U; i < ACTUATOR_COUNT; ++i) {
|
||||
s_ctx[i].status.direction = ACT_DIR_STOP;
|
||||
s_ctx[i].status.pwm_percent = 0U;
|
||||
s_ctx[i].status.current_ma = 0U;
|
||||
s_ctx[i].status.peak_current_ma = 0U;
|
||||
s_ctx[i].status.clamping_force_n = 0U;
|
||||
s_ctx[i].status.overcurrent = false;
|
||||
s_ctx[i].status.last_error = EPB_OK;
|
||||
s_ctx[i].over_ms = 0U;
|
||||
}
|
||||
return EPB_OK;
|
||||
}
|
||||
|
||||
EpbStatus actuator_apply(ActuatorId id, uint8_t pwm_percent)
|
||||
{
|
||||
if (!is_valid_id(id)) {
|
||||
return EPB_EINVAL;
|
||||
}
|
||||
if (pwm_percent > 100U) {
|
||||
return EPB_EINVAL;
|
||||
}
|
||||
if (s_ctx[id].status.overcurrent) {
|
||||
return EPB_EOVERCURRENT;
|
||||
}
|
||||
s_ctx[id].status.direction = ACT_DIR_APPLY;
|
||||
s_ctx[id].status.pwm_percent = pwm_percent;
|
||||
s_ctx[id].status.peak_current_ma = 0U;
|
||||
return EPB_OK;
|
||||
}
|
||||
|
||||
EpbStatus actuator_release(ActuatorId id, uint8_t pwm_percent)
|
||||
{
|
||||
if (!is_valid_id(id)) {
|
||||
return EPB_EINVAL;
|
||||
}
|
||||
if (pwm_percent > 100U) {
|
||||
return EPB_EINVAL;
|
||||
}
|
||||
if (s_ctx[id].status.overcurrent) {
|
||||
return EPB_EOVERCURRENT;
|
||||
}
|
||||
s_ctx[id].status.direction = ACT_DIR_RELEASE;
|
||||
s_ctx[id].status.pwm_percent = pwm_percent;
|
||||
return EPB_OK;
|
||||
}
|
||||
|
||||
EpbStatus actuator_stop(ActuatorId id)
|
||||
{
|
||||
if (!is_valid_id(id)) {
|
||||
return EPB_EINVAL;
|
||||
}
|
||||
s_ctx[id].status.direction = ACT_DIR_STOP;
|
||||
s_ctx[id].status.pwm_percent = 0U;
|
||||
return EPB_OK;
|
||||
}
|
||||
|
||||
ActuatorStatus actuator_get_status(ActuatorId id)
|
||||
{
|
||||
if (!is_valid_id(id)) {
|
||||
ActuatorStatus empty = {0};
|
||||
empty.last_error = EPB_EINVAL;
|
||||
return empty;
|
||||
}
|
||||
return s_ctx[id].status;
|
||||
}
|
||||
|
||||
void actuator_isr_1khz(ActuatorId id, uint16_t current_sample_ma)
|
||||
{
|
||||
if (!is_valid_id(id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
s_ctx[id].status.current_ma = current_sample_ma;
|
||||
if (current_sample_ma > s_ctx[id].status.peak_current_ma) {
|
||||
s_ctx[id].status.peak_current_ma = current_sample_ma;
|
||||
}
|
||||
|
||||
/* SWE-014: Overcurrent-Cutoff bei > 8 A fuer > 100 ms */
|
||||
if (current_sample_ma > ACT_OVERCURRENT_LIMIT_MA) {
|
||||
if (s_ctx[id].over_ms < UINT16_MAX) {
|
||||
++s_ctx[id].over_ms;
|
||||
}
|
||||
if (s_ctx[id].over_ms >= ACT_OVERCURRENT_WINDOW_MS) {
|
||||
s_ctx[id].status.direction = ACT_DIR_STOP;
|
||||
s_ctx[id].status.pwm_percent = 0U;
|
||||
s_ctx[id].status.overcurrent = true;
|
||||
s_ctx[id].status.last_error = EPB_EOVERCURRENT;
|
||||
}
|
||||
} else {
|
||||
s_ctx[id].over_ms = 0U;
|
||||
}
|
||||
|
||||
/* SWE-015: Klemmkraft aus Peak-Strom schaetzen (nur bei Apply). */
|
||||
if (s_ctx[id].status.direction == ACT_DIR_APPLY) {
|
||||
const uint32_t force = ((uint32_t)s_ctx[id].status.peak_current_ma
|
||||
* ACT_FORCE_PER_AMP_N) / 1000U;
|
||||
s_ctx[id].status.clamping_force_n =
|
||||
(force > UINT16_MAX) ? UINT16_MAX : (uint16_t)force;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @file actuator_driver.h
|
||||
* @brief Low-Level-Ansteuerung der EPB-Aktoren.
|
||||
*
|
||||
* @arch SWA-003
|
||||
* @reqs SWE-006 SWE-013 SWE-014 SWE-015
|
||||
*
|
||||
* ASIL: B
|
||||
*/
|
||||
#ifndef ACTUATOR_DRIVER_H
|
||||
#define ACTUATOR_DRIVER_H
|
||||
|
||||
#include "epb_types.h"
|
||||
|
||||
typedef enum {
|
||||
ACT_DIR_STOP = 0,
|
||||
ACT_DIR_APPLY = 1,
|
||||
ACT_DIR_RELEASE = 2
|
||||
} ActuatorDirection;
|
||||
|
||||
typedef struct {
|
||||
ActuatorDirection direction;
|
||||
uint8_t pwm_percent; /* 0..100 */
|
||||
uint16_t current_ma; /* aktueller Motorstrom */
|
||||
uint16_t peak_current_ma;
|
||||
uint16_t clamping_force_n; /* geschaetzt aus Strom */
|
||||
bool overcurrent;
|
||||
EpbStatus last_error;
|
||||
} ActuatorStatus;
|
||||
|
||||
/** Strom-Limit (Spec) und Zeitfenster fuer Cutoff (Spec). */
|
||||
#define ACT_OVERCURRENT_LIMIT_MA 8000U
|
||||
#define ACT_OVERCURRENT_WINDOW_MS 100U
|
||||
#define ACT_FORCE_PER_AMP_N 2500U /* lineare Naeherung */
|
||||
|
||||
EpbStatus actuator_init(void);
|
||||
EpbStatus actuator_apply(ActuatorId id, uint8_t pwm_percent);
|
||||
EpbStatus actuator_release(ActuatorId id, uint8_t pwm_percent);
|
||||
EpbStatus actuator_stop(ActuatorId id);
|
||||
ActuatorStatus actuator_get_status(ActuatorId id);
|
||||
|
||||
/**
|
||||
* @brief ISR-Hook fuer Strom-Sampling. Wird mit 1 kHz aufgerufen.
|
||||
*
|
||||
* Fuer Tests durch Test-Doubles ersetzt.
|
||||
*/
|
||||
void actuator_isr_1khz(ActuatorId id, uint16_t current_sample_ma);
|
||||
|
||||
#endif /* ACTUATOR_DRIVER_H */
|
||||
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* @file apply_controller.c
|
||||
* @brief Apply/Hold/Release State Machine.
|
||||
*
|
||||
* @arch SWA-002
|
||||
* @reqs SWE-001 SWE-002 SWE-003 SWE-004
|
||||
*
|
||||
* ASIL: D. Diese Komponente ist die sicherheitskritische Kernlogik.
|
||||
* Aenderungen erfordern Technical Review mit 2 Approvals.
|
||||
*/
|
||||
#include <stddef.h>
|
||||
|
||||
#include "apply_controller.h"
|
||||
#include "actuator_driver.h"
|
||||
|
||||
typedef struct {
|
||||
EpbState state;
|
||||
uint8_t step_in_state; /* 50ms-Ticks im aktuellen 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-Voraussetzungen) — hier konsumiert */
|
||||
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: Klemmkraft-Erreichen pruefen */
|
||||
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: Klemmkraft halten — bei Unterschreitung nachregeln */
|
||||
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:
|
||||
/* Auf Reset warten; sicherer Zustand ist Apply, also kein 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;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @file apply_controller.h
|
||||
* @brief Apply/Hold/Release-Steuerung der EPB.
|
||||
*
|
||||
* @arch SWA-002
|
||||
* @reqs SWE-001 SWE-002 SWE-003 SWE-004
|
||||
*
|
||||
* ASIL: D
|
||||
*/
|
||||
#ifndef APPLY_CONTROLLER_H
|
||||
#define APPLY_CONTROLLER_H
|
||||
|
||||
#include "epb_types.h"
|
||||
|
||||
typedef struct {
|
||||
SwitchState sw_state; /* aus SwitchDebouncer */
|
||||
bool standstill; /* aus Wheel-Speed-Plausi */
|
||||
bool engine_running;
|
||||
bool brake_pedal_pressed;
|
||||
bool gear_engaged;
|
||||
bool safety_apply_request; /* aus SafetyManager */
|
||||
uint16_t left_force_n;
|
||||
uint16_t right_force_n;
|
||||
} ApplyInputs;
|
||||
|
||||
#define APPLY_TARGET_FORCE_N 12000U /* Ziel-Klemmkraft je Aktor */
|
||||
#define APPLY_TIMEOUT_50MS 30U /* 30 * 50ms = 1500 ms */
|
||||
#define HOLD_TOLERANCE_N 1200U /* 10% von Ziel */
|
||||
|
||||
EpbStatus apply_ctrl_init(void);
|
||||
|
||||
/**
|
||||
* @brief Step-Funktion 50 ms.
|
||||
*
|
||||
* @reqs SWE-001 SWE-002 SWE-003 SWE-004
|
||||
*/
|
||||
void apply_ctrl_step_50ms(const ApplyInputs* in);
|
||||
|
||||
EpbState apply_ctrl_get_state(void);
|
||||
EpbStatus apply_ctrl_last_error(void);
|
||||
uint32_t apply_ctrl_get_step_count(void); /* Watchdog-Alive-Counter */
|
||||
|
||||
#endif /* APPLY_CONTROLLER_H */
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @file epb_types.h
|
||||
* @brief Gemeinsame Typen fuer die EPB-Software.
|
||||
*
|
||||
* @arch SA-001
|
||||
*/
|
||||
#ifndef EPB_TYPES_H
|
||||
#define EPB_TYPES_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
EPB_OK = 0,
|
||||
EPB_EINVAL = 1,
|
||||
EPB_ETIMEOUT = 2,
|
||||
EPB_ENOSPACE = 3,
|
||||
EPB_EHARDWARE = 4,
|
||||
EPB_EOVERCURRENT = 5
|
||||
} EpbStatus;
|
||||
|
||||
typedef enum {
|
||||
EPB_STATE_RELEASED = 0,
|
||||
EPB_STATE_APPLYING = 1,
|
||||
EPB_STATE_APPLIED = 2,
|
||||
EPB_STATE_RELEASING = 3,
|
||||
EPB_STATE_ERROR = 0xFF
|
||||
} EpbState;
|
||||
|
||||
typedef enum {
|
||||
ACTUATOR_LEFT = 0,
|
||||
ACTUATOR_RIGHT = 1,
|
||||
ACTUATOR_COUNT = 2
|
||||
} ActuatorId;
|
||||
|
||||
typedef enum {
|
||||
SWITCH_NEUTRAL = 0,
|
||||
SWITCH_APPLY = 1,
|
||||
SWITCH_RELEASE = 2
|
||||
} SwitchState;
|
||||
|
||||
typedef struct {
|
||||
uint8_t apply_raw : 1;
|
||||
uint8_t release_raw : 1;
|
||||
} SwitchRaw;
|
||||
|
||||
#endif /* EPB_TYPES_H */
|
||||
@@ -0,0 +1,18 @@
|
||||
# Stubs — nicht implementierte Komponenten
|
||||
|
||||
Diese Komponenten sind in der Software-Architektur (`arch/swe/`) vollstaendig
|
||||
spezifiziert, aber in dieser Demo nicht ausimplementiert. Sie zeigen nur die
|
||||
Header-Schnittstellen.
|
||||
|
||||
Im Real-Projekt wuerden hier vollstaendige `.c`-Implementierungen plus
|
||||
Unit-Tests stehen.
|
||||
|
||||
| Komponente | ASIL | SWA |
|
||||
|-------------------------|------|-----------|
|
||||
| Safety Manager | D | SWA-001 |
|
||||
| Wheel Speed Plausi | B | SWA-004 |
|
||||
| Inclinometer Filter | B | SWA-005 |
|
||||
| Display Manager | QM | SWA-007 |
|
||||
| Diagnostic Manager | QM | SWA-008 |
|
||||
| Service Mode | QM | SWA-009 |
|
||||
| Logger | QM | SWA-010 |
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @file diag_manager.h
|
||||
* @brief UDS-Diagnose nach ISO 14229.
|
||||
*
|
||||
* @arch SWA-008
|
||||
* @reqs SWE-018 SWE-019
|
||||
*
|
||||
* ASIL: QM. STUB.
|
||||
*/
|
||||
#ifndef DIAG_MANAGER_H
|
||||
#define DIAG_MANAGER_H
|
||||
|
||||
#include "../epb_types.h"
|
||||
|
||||
EpbStatus diag_init(void);
|
||||
void diag_handle_request(const uint8_t* data, uint16_t len);
|
||||
void diag_set_dtc(uint16_t dtc_id);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @file display_manager.h
|
||||
* @brief LED + CAN-Status-Frame Steuerung.
|
||||
*
|
||||
* @arch SWA-007
|
||||
* @reqs SWE-020 SWE-021
|
||||
*
|
||||
* ASIL: QM. STUB.
|
||||
*/
|
||||
#ifndef DISPLAY_MANAGER_H
|
||||
#define DISPLAY_MANAGER_H
|
||||
|
||||
#include "../epb_types.h"
|
||||
|
||||
EpbStatus display_init(void);
|
||||
void display_set_status(EpbState s);
|
||||
void display_step_20ms(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @file inclinometer.h
|
||||
* @brief Inclinometer-Tiefpass-Filter.
|
||||
*
|
||||
* @arch SWA-005
|
||||
* @reqs SWE-024
|
||||
*
|
||||
* ASIL: B. STUB.
|
||||
*/
|
||||
#ifndef INCLINOMETER_H
|
||||
#define INCLINOMETER_H
|
||||
|
||||
#include "../epb_types.h"
|
||||
|
||||
EpbStatus inclino_init(void);
|
||||
void inclino_step_10ms(int16_t raw_mdeg);
|
||||
float inclino_get_grade_percent(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @file logger.h
|
||||
* @brief Logger — Ringpuffer + EEPROM-Persistenz.
|
||||
*
|
||||
* @arch SWA-010
|
||||
*
|
||||
* ASIL: QM. STUB.
|
||||
*/
|
||||
#ifndef LOGGER_H
|
||||
#define LOGGER_H
|
||||
|
||||
#include "../epb_types.h"
|
||||
|
||||
typedef enum {
|
||||
LOG_DEBUG = 0,
|
||||
LOG_INFO,
|
||||
LOG_WARN,
|
||||
LOG_ERROR
|
||||
} LogLevel;
|
||||
|
||||
EpbStatus log_init(void);
|
||||
void log_event(LogLevel lvl, uint16_t event_id, uint32_t param);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* @file safety_manager.h
|
||||
* @brief Safety Manager — Hill-Hold + Auto-Apply Logik.
|
||||
*
|
||||
* @arch SWA-001
|
||||
* @reqs SWE-007 SWE-008 SWE-009 SWE-010
|
||||
*
|
||||
* ASIL: D. STUB — nicht implementiert in dieser Demo.
|
||||
*/
|
||||
#ifndef SAFETY_MANAGER_H
|
||||
#define SAFETY_MANAGER_H
|
||||
|
||||
#include "../epb_types.h"
|
||||
|
||||
typedef struct {
|
||||
bool engine_running;
|
||||
bool brake_pedal_pressed;
|
||||
float vehicle_speed_kmh;
|
||||
float grade_percent;
|
||||
EpbState current_state;
|
||||
} SafetyInputs;
|
||||
|
||||
EpbStatus safety_mgr_init(void);
|
||||
void safety_mgr_step_50ms(const SafetyInputs* in);
|
||||
bool safety_mgr_apply_requested(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @file service_mode.h
|
||||
* @brief Service-Modus fuer Werkstatt (Bremsbelag-Wechsel).
|
||||
*
|
||||
* @arch SWA-009
|
||||
* @reqs SWE-016 SWE-017
|
||||
*
|
||||
* ASIL: QM. STUB.
|
||||
*/
|
||||
#ifndef SERVICE_MODE_H
|
||||
#define SERVICE_MODE_H
|
||||
|
||||
#include "../epb_types.h"
|
||||
|
||||
EpbStatus service_mode_init(void);
|
||||
EpbStatus service_mode_activate(void);
|
||||
EpbStatus service_mode_deactivate(void);
|
||||
bool service_mode_is_active(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* @file wheel_speed_plausi.h
|
||||
* @brief Wheel-Speed-Plausibilisierung + Stillstands-Erkennung.
|
||||
*
|
||||
* @arch SWA-004
|
||||
* @reqs SWE-022 SWE-023
|
||||
*
|
||||
* ASIL: B. STUB.
|
||||
*/
|
||||
#ifndef WHEEL_SPEED_PLAUSI_H
|
||||
#define WHEEL_SPEED_PLAUSI_H
|
||||
|
||||
#include "../epb_types.h"
|
||||
|
||||
typedef struct {
|
||||
float fl_kmh;
|
||||
float fr_kmh;
|
||||
float rl_kmh;
|
||||
float rr_kmh;
|
||||
} WheelInputs;
|
||||
|
||||
EpbStatus wheel_speed_init(void);
|
||||
void wheel_speed_step_10ms(const WheelInputs* in);
|
||||
bool wheel_speed_is_standstill(void);
|
||||
float wheel_speed_get_vehicle(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @file switch_debouncer.c
|
||||
* @brief Implementierung des EPB-Schalter-Debouncers.
|
||||
*
|
||||
* @arch SWA-006
|
||||
* @reqs SWE-025
|
||||
*
|
||||
* ASIL: QM.
|
||||
*/
|
||||
#include "switch_debouncer.h"
|
||||
|
||||
typedef struct {
|
||||
SwitchState current;
|
||||
SwitchState candidate;
|
||||
uint8_t candidate_count;
|
||||
} DebouncerCtx;
|
||||
|
||||
static DebouncerCtx s_ctx;
|
||||
|
||||
static SwitchState raw_to_candidate(SwitchRaw raw)
|
||||
{
|
||||
if (raw.apply_raw && !raw.release_raw) {
|
||||
return SWITCH_APPLY;
|
||||
}
|
||||
if (raw.release_raw && !raw.apply_raw) {
|
||||
return SWITCH_RELEASE;
|
||||
}
|
||||
return SWITCH_NEUTRAL;
|
||||
}
|
||||
|
||||
EpbStatus switch_init(void)
|
||||
{
|
||||
s_ctx.current = SWITCH_NEUTRAL;
|
||||
s_ctx.candidate = SWITCH_NEUTRAL;
|
||||
s_ctx.candidate_count = 0U;
|
||||
return EPB_OK;
|
||||
}
|
||||
|
||||
void switch_step_10ms(SwitchRaw raw)
|
||||
{
|
||||
const SwitchState observed = raw_to_candidate(raw);
|
||||
|
||||
if (observed == s_ctx.candidate) {
|
||||
if (s_ctx.candidate_count < SWITCH_DEBOUNCE_SAMPLES) {
|
||||
++s_ctx.candidate_count;
|
||||
}
|
||||
} else {
|
||||
s_ctx.candidate = observed;
|
||||
s_ctx.candidate_count = 1U;
|
||||
}
|
||||
|
||||
if (s_ctx.candidate_count >= SWITCH_DEBOUNCE_SAMPLES) {
|
||||
s_ctx.current = s_ctx.candidate;
|
||||
}
|
||||
}
|
||||
|
||||
SwitchState switch_get_state(void)
|
||||
{
|
||||
return s_ctx.current;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @file switch_debouncer.h
|
||||
* @brief EPB-Schalter mit Software-Entprellung.
|
||||
*
|
||||
* @arch SWA-006
|
||||
* @reqs SWE-025
|
||||
*
|
||||
* ASIL: QM
|
||||
*/
|
||||
#ifndef SWITCH_DEBOUNCER_H
|
||||
#define SWITCH_DEBOUNCER_H
|
||||
|
||||
#include "epb_types.h"
|
||||
|
||||
/** Step-Zyklus 10 ms. Debounce-Schwelle 50 ms (5 stabile Samples). */
|
||||
#define SWITCH_DEBOUNCE_SAMPLES 5
|
||||
|
||||
EpbStatus switch_init(void);
|
||||
void switch_step_10ms(SwitchRaw raw);
|
||||
SwitchState switch_get_state(void);
|
||||
|
||||
#endif /* SWITCH_DEBOUNCER_H */
|
||||
Reference in New Issue
Block a user