4351dfa4e1
Validate / build-and-test (push) Successful in 30s
- Implement Safety Manager (SWA-001, ASIL-D): Hill-Hold + Auto-Apply state machine, 13 unit tests - Update SWA-002 + SWA-001 link coverage so all SWE reqs are covered - New tool: tools/traceability.py — Markdown-frontmatter-basierter Traceability-Checker + HTML/JSON-Matrix-Generator (Doorstop-Format ohne Doorstop-Dependency) - New tool: tools/render_plantuml.py — extrahiert PlantUML-Bloecke aus arch/**.md und rendert via plantuml.com zu SVG - validate.yml: neue Steps Traceability-Check, Matrix-Publish, PlantUML- Render; uploaded als Gitea-Artefakte
809 lines
28 KiB
Python
809 lines
28 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Generate Doorstop-compatible Markdown items for the EPB demo.
|
|
|
|
Source of truth: the dict EPB_DATA below.
|
|
Outputs to: reqs/sys/, reqs/swe/, arch/sys/, arch/swe/
|
|
|
|
Each output file uses Doorstop's Markdown mode (YAML frontmatter + body).
|
|
|
|
Run: python3 tools/generate_doorstop_items.py
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import textwrap
|
|
from pathlib import Path
|
|
|
|
REPO = Path(__file__).resolve().parent.parent
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# System Requirements
|
|
# ---------------------------------------------------------------------------
|
|
|
|
SYS_REQS = [
|
|
{
|
|
"id": "SYS-001", "asil": "D",
|
|
"title": "Halten der Parkbremse im Stillstand",
|
|
"text": (
|
|
"Wenn die Parkbremse aktiviert ist und das Fahrzeug stillsteht, "
|
|
"muss das EPB-System die mechanische Klemmkraft an beiden hinteren "
|
|
"Bremssaetteln aufrecht erhalten, bis ein Loesen ausdruecklich "
|
|
"angefordert wird. Sicherheitsziel: SG-01.\n\n"
|
|
"**Verifikation:** SiL-Test mit Auf-/Ab-Hangelung, Klemmkraftmessung."
|
|
),
|
|
},
|
|
{
|
|
"id": "SYS-002", "asil": "D",
|
|
"title": "Apply auf Fahrer-Anforderung",
|
|
"text": (
|
|
"Bei Betaetigung des EPB-Schalters in Apply-Richtung muss das "
|
|
"System innerhalb von 800 ms die Parkbremse anlegen, sofern die "
|
|
"Voraussetzungen erfuellt sind (Stillstand oder Geschwindigkeit "
|
|
"unter 5 km/h). Sicherheitsziel: SG-01."
|
|
),
|
|
},
|
|
{
|
|
"id": "SYS-003", "asil": "B",
|
|
"title": "Release auf Fahrer-Anforderung",
|
|
"text": (
|
|
"Bei Betaetigung des EPB-Schalters in Release-Richtung muss das "
|
|
"System die Parkbremse loesen, sofern die folgenden Voraussetzungen "
|
|
"erfuellt sind: Motor laeuft, Fahrer betaetigt Bremspedal, Gang "
|
|
"ist eingelegt. Maximalzeit fuer Loesen: 1500 ms."
|
|
),
|
|
},
|
|
{
|
|
"id": "SYS-004", "asil": "D",
|
|
"title": "Auto-Apply bei Motor-Aus",
|
|
"text": (
|
|
"Wenn der Motor ausgeschaltet wird und das Fahrzeug stillsteht "
|
|
"und keine Parkbremse aktiv ist, muss das System die Parkbremse "
|
|
"spaetestens 2 s nach Erkennung Motor-Aus automatisch anlegen. "
|
|
"Sicherheitsziel: SG-01."
|
|
),
|
|
},
|
|
{
|
|
"id": "SYS-005", "asil": "D",
|
|
"title": "Hill-Hold am Berg",
|
|
"text": (
|
|
"Bei aktivem Hill-Hold (Fahrzeug steht am Hang mit Neigung > 5%, "
|
|
"Fahrer betaetigt Bremspedal) uebernimmt das EPB-System die "
|
|
"Bremskraft beim Loesen des Bremspedals und haelt diese, bis die "
|
|
"Anfahrt erkannt wird. Sicherheitsziel: SG-01."
|
|
),
|
|
},
|
|
{
|
|
"id": "SYS-006", "asil": "B",
|
|
"title": "Auto-Release beim Anfahren (Drive-Away-Assist)",
|
|
"text": (
|
|
"Wenn die Parkbremse aktiv ist und der Fahrer Anfahrabsicht zeigt "
|
|
"(Gaspedal-Betaetigung bei eingelegtem Gang), muss das System die "
|
|
"Parkbremse innerhalb von 500 ms loesen. Voraussetzung: alle "
|
|
"Sicherheitskriterien (Fahrertuer geschlossen, Sicherheitsgurt) "
|
|
"erfuellt."
|
|
),
|
|
},
|
|
{
|
|
"id": "SYS-007", "asil": "B",
|
|
"title": "Aktor-Stromueberwachung",
|
|
"text": (
|
|
"Das System muss den Motorstrom jedes Aktors mit mindestens 1 kHz "
|
|
"ueberwachen und bei Ueberschreitung von 8 A fuer mehr als 100 ms "
|
|
"den Aktor abschalten und einen DTC setzen. Sicherheitsziel: SG-03."
|
|
),
|
|
},
|
|
{
|
|
"id": "SYS-008", "asil": "QM",
|
|
"title": "Service-Modus fuer Werkstatt",
|
|
"text": (
|
|
"Das System muss ueber UDS RoutineControl (Service 0x31) einen "
|
|
"Service-Modus bereitstellen, in dem die Aktoren manuell in "
|
|
"Wartungs-Position gefahren werden koennen (z.B. fuer Bremsbelag-"
|
|
"Wechsel)."
|
|
),
|
|
},
|
|
{
|
|
"id": "SYS-009", "asil": "QM",
|
|
"title": "UDS-Diagnose",
|
|
"text": (
|
|
"Das System muss UDS-Diagnose nach ISO 14229 bereitstellen: "
|
|
"ReadDTC (0x19), ReadDataByIdentifier (0x22), RoutineControl (0x31), "
|
|
"ECUReset (0x11). Tester-Adresse 0x712, Antwort-Adresse 0x71A."
|
|
),
|
|
},
|
|
{
|
|
"id": "SYS-010", "asil": "QM",
|
|
"title": "HMI-Statusanzeige",
|
|
"text": (
|
|
"Der EPB-Status muss dem Fahrer signalisiert werden: LED am "
|
|
"Schalter (an = Apply, aus = Release, blinkend = Fehler) sowie "
|
|
"Text im Kombi-Display via CAN-Bus (Frame-ID 0x3A0, 50 Hz)."
|
|
),
|
|
},
|
|
]
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Software Requirements (each links to one or more SYS reqs)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
SWE_REQS = [
|
|
# SYS-001 — Halten
|
|
{"id": "SWE-001", "asil": "D", "links": ["SYS-001"],
|
|
"title": "Apply-Controller haelt Klemmkraft",
|
|
"text": "Der Apply-Controller muss die Klemmkraft im Hold-Zustand alle 50 ms "
|
|
"verifizieren und bei Abweichung > 10% nachregeln."},
|
|
|
|
{"id": "SWE-002", "asil": "D", "links": ["SYS-001"],
|
|
"title": "Watchdog ueberwacht Apply-Controller",
|
|
"text": "Ein unabhaengiger Watchdog muss die Liveness des Apply-Controllers "
|
|
"mit 100 ms Timeout ueberwachen und bei Ausbleiben in den sicheren "
|
|
"Zustand (Apply) gehen."},
|
|
|
|
# SYS-002 — Apply
|
|
{"id": "SWE-003", "asil": "D", "links": ["SYS-002"],
|
|
"title": "Schalter-Apply-Signal an Apply-Controller weiterleiten",
|
|
"text": "Das Software-Modul Switch-Debouncer muss ein entprelltes "
|
|
"Apply-Signal innerhalb von 50 ms an den Apply-Controller liefern."},
|
|
|
|
{"id": "SWE-004", "asil": "D", "links": ["SYS-002"],
|
|
"title": "Klemmkraft-Erreichen bestaetigen",
|
|
"text": "Der Apply-Controller muss das Erreichen der Ziel-Klemmkraft via "
|
|
"Strommessung erkennen und ein Status-Flag setzen."},
|
|
|
|
# SYS-003 — Release
|
|
{"id": "SWE-005", "asil": "B", "links": ["SYS-003"],
|
|
"title": "Release-Voraussetzungen pruefen",
|
|
"text": "Vor jedem Release muss der Apply-Controller pruefen: Motor laeuft, "
|
|
"Bremspedal betaetigt, Gang ist eingelegt. Andernfalls Release abweisen."},
|
|
|
|
{"id": "SWE-006", "asil": "B", "links": ["SYS-003"],
|
|
"title": "Aktoren in Release-Position fahren",
|
|
"text": "Der Actuator-Driver muss beide Aktoren parallel in Release-Position "
|
|
"fahren. Maximalzeit: 1200 ms. Bei Timeout DTC setzen."},
|
|
|
|
# SYS-004 — Auto-Apply
|
|
{"id": "SWE-007", "asil": "D", "links": ["SYS-004"],
|
|
"title": "Motor-Aus-Bedingung erkennen",
|
|
"text": "Der Safety-Manager muss erkennen: Motor-Status = aus, "
|
|
"Geschwindigkeit < 0.5 km/h. Auswertezyklus 50 ms."},
|
|
|
|
{"id": "SWE-008", "asil": "D", "links": ["SYS-004"],
|
|
"title": "Auto-Apply nach 2 s Verzoegerung",
|
|
"text": "Ist die Motor-Aus-Bedingung 2 s stabil erfuellt und Parkbremse "
|
|
"noch nicht aktiv, muss der Safety-Manager Apply-Anforderung an "
|
|
"den Apply-Controller senden."},
|
|
|
|
# SYS-005 — Hill-Hold
|
|
{"id": "SWE-009", "asil": "D", "links": ["SYS-005"],
|
|
"title": "Hill-Hold-Aktivierungsbedingung",
|
|
"text": "Der Safety-Manager muss Hill-Hold aktivieren, wenn Neigung "
|
|
"(gefiltert) > 5%, Geschwindigkeit < 0.5 km/h und Bremspedal "
|
|
"betaetigt sind."},
|
|
|
|
{"id": "SWE-010", "asil": "D", "links": ["SYS-005"],
|
|
"title": "Hill-Hold-Uebergabe an Apply-Controller",
|
|
"text": "Wird das Bremspedal bei aktivem Hill-Hold losgelassen, muss der "
|
|
"Safety-Manager unmittelbar Apply-Anforderung an den Apply-"
|
|
"Controller senden, bevor das Fahrzeug zu rollen beginnen kann."},
|
|
|
|
# SYS-006 — Auto-Release
|
|
{"id": "SWE-011", "asil": "B", "links": ["SYS-006"],
|
|
"title": "Anfahrabsicht erkennen",
|
|
"text": "Anfahrabsicht ist erkannt, wenn: Gaspedal > 10%, Gang in Vorwaerts "
|
|
"oder Rueckwaerts, Motor laeuft."},
|
|
|
|
{"id": "SWE-012", "asil": "B", "links": ["SYS-006"],
|
|
"title": "Sicherheits-Check vor Auto-Release",
|
|
"text": "Vor Auto-Release muessen erfuellt sein: Fahrertuer geschlossen, "
|
|
"Sicherheitsgurt angelegt. Andernfalls warnen und nicht loesen."},
|
|
|
|
# SYS-007 — Aktor-Strom
|
|
{"id": "SWE-013", "asil": "B", "links": ["SYS-007"],
|
|
"title": "Strommessung mit 1 kHz",
|
|
"text": "Der Actuator-Driver muss den Motorstrom jedes Aktors mit "
|
|
"mindestens 1 kHz abtasten. Genauigkeit +/- 100 mA."},
|
|
|
|
{"id": "SWE-014", "asil": "B", "links": ["SYS-007"],
|
|
"title": "Overcurrent-Cutoff",
|
|
"text": "Bei Motorstrom > 8 A laenger als 100 ms muss der Actuator-Driver "
|
|
"den Motor abschalten und einen DTC P0xxx setzen."},
|
|
|
|
{"id": "SWE-015", "asil": "B", "links": ["SYS-007"],
|
|
"title": "Klemmkraft-Schaetzung aus Strom-Profil",
|
|
"text": "Der Actuator-Driver muss die erreichte Klemmkraft aus dem "
|
|
"Stromverlauf bei Apply schaetzen (Modell: F = k * I_peak)."},
|
|
|
|
# SYS-008 — Service-Modus
|
|
{"id": "SWE-016", "asil": "QM", "links": ["SYS-008"],
|
|
"title": "UDS RoutineControl 0x31 fuer Service-Release",
|
|
"text": "Service-Mode wird ueber UDS RoutineControl Service 0x31, "
|
|
"Routine-ID 0x0301 aktiviert. Bedingung: Fahrzeug muss stillstehen."},
|
|
|
|
{"id": "SWE-017", "asil": "QM", "links": ["SYS-008"],
|
|
"title": "Service-Mode-Indikator",
|
|
"text": "Im Service-Mode muss die EPB-LED am Schalter mit 2 Hz blinken."},
|
|
|
|
# SYS-009 — UDS
|
|
{"id": "SWE-018", "asil": "QM", "links": ["SYS-009"],
|
|
"title": "UDS Service 0x19 ReadDTC",
|
|
"text": "Das System muss alle gespeicherten DTCs ueber Service 0x19 "
|
|
"(Subfunktion 0x02 reportDTCByStatusMask) ausgeben."},
|
|
|
|
{"id": "SWE-019", "asil": "QM", "links": ["SYS-009"],
|
|
"title": "UDS Service 0x22 ReadDataByIdentifier",
|
|
"text": "Folgende DIDs muessen lesbar sein: 0xF187 (SW-Version), "
|
|
"0x0301 (Klemmkraft links), 0x0302 (Klemmkraft rechts)."},
|
|
|
|
# SYS-010 — HMI
|
|
{"id": "SWE-020", "asil": "QM", "links": ["SYS-010"],
|
|
"title": "LED-Steuerung",
|
|
"text": "Apply-aktiv: LED dauerleuchtend. Release: LED aus. Fehler: "
|
|
"LED blinkt 4 Hz. Service-Mode: LED blinkt 2 Hz."},
|
|
|
|
{"id": "SWE-021", "asil": "QM", "links": ["SYS-010"],
|
|
"title": "CAN-Status-Frame",
|
|
"text": "Status-Frame 0x3A0 mit 50 Hz: Byte 0 = Status (0=Released, 1=Applied, "
|
|
"2=Applying, 3=Releasing, 0xFF=Error), Byte 1-2 = Klemmkraft links, "
|
|
"Byte 3-4 = Klemmkraft rechts."},
|
|
|
|
# Sensorik & Plausibilisierung
|
|
{"id": "SWE-022", "asil": "B", "links": ["SYS-001", "SYS-002", "SYS-006"],
|
|
"title": "Stillstands-Erkennung aus Wheel Speeds",
|
|
"text": "Stillstand ist erkannt, wenn alle 4 Wheel-Speed-Signale fuer "
|
|
"mindestens 200 ms unter 0.5 km/h liegen."},
|
|
|
|
{"id": "SWE-023", "asil": "B", "links": ["SYS-007"],
|
|
"title": "Wheel Speed Plausibilisierung",
|
|
"text": "Spreizung der Wheel-Speed-Signale: bei Geradeaus-Fahrt darf die "
|
|
"Differenz nicht > 3 km/h sein. Andernfalls Sensor-Fehler-DTC."},
|
|
|
|
{"id": "SWE-024", "asil": "B", "links": ["SYS-005"],
|
|
"title": "Inclinometer Tiefpass-Filter",
|
|
"text": "Das Roh-Neigungssignal muss mit einem Tiefpass 1. Ordnung "
|
|
"(Zeitkonstante 200 ms) gefiltert werden, bevor es zur Hill-Hold-"
|
|
"Bewertung verwendet wird."},
|
|
|
|
{"id": "SWE-025", "asil": "QM", "links": ["SYS-002", "SYS-003"],
|
|
"title": "Switch-Debouncing",
|
|
"text": "Der EPB-Schalter muss mit einer Entprell-Zeit von 50 ms "
|
|
"entprellt werden. Stabiler Pegel = Eingangssignal fuer "
|
|
"Apply-Controller."},
|
|
]
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# System Architecture Elements
|
|
# ---------------------------------------------------------------------------
|
|
|
|
SA_ELEMENTS = [
|
|
{
|
|
"id": "SA-001", "links": ["SYS-001", "SYS-002", "SYS-003", "SYS-004",
|
|
"SYS-005", "SYS-006", "SYS-007", "SYS-008",
|
|
"SYS-009", "SYS-010"],
|
|
"title": "EPB ECU",
|
|
"asil": "D",
|
|
"text": textwrap.dedent("""
|
|
## Verantwortung
|
|
|
|
Zentrales Steuergeraet der elektrischen Parkbremse. Beinhaltet alle Software-
|
|
Komponenten und die elektronische Ansteuerung der Aktoren.
|
|
|
|
## System-Kontext
|
|
|
|
```plantuml
|
|
@startuml
|
|
node "EPB ECU" as ECU
|
|
node "Aktor links" as AL
|
|
node "Aktor rechts" as AR
|
|
node "Wheel Speed Sensoren (x4)" as WS
|
|
node "Inclinometer" as IN
|
|
node "EPB-Schalter + LED" as SW
|
|
node "CAN-Bus" as CAN
|
|
node "Kombi-Display" as DI
|
|
node "OBD-Tester" as OBD
|
|
|
|
ECU --> AL : PWM, I-Mess
|
|
ECU --> AR : PWM, I-Mess
|
|
WS --> ECU : Pulse
|
|
IN --> ECU : SPI
|
|
SW --> ECU : GPIO
|
|
ECU --> SW : LED
|
|
ECU <-> CAN
|
|
CAN <-> DI
|
|
CAN <-> OBD
|
|
@enduml
|
|
```
|
|
|
|
## Schnittstellen
|
|
|
|
| Schnittstelle | Typ | Richtung |
|
|
|---------------|----------------|----------|
|
|
| Aktor L/R | PWM + Shunt | I/O |
|
|
| Wheel Speed | Hall-Pulse | In |
|
|
| Inclinometer | SPI | In |
|
|
| Schalter | GPIO debounced | In |
|
|
| LED | GPIO | Out |
|
|
| CAN | ISO 11898 | I/O |
|
|
|
|
## Subkomponenten (Aufteilung auf SW)
|
|
|
|
Realisiert in Software: alle SWA-Elemente SWA-001..SWA-010.
|
|
|
|
## Nichtfunktionale Eigenschaften
|
|
|
|
- Worst-Case Reaktionszeit (Schalter → Aktor-Bewegung): 250 ms
|
|
- Flash-Bedarf: < 256 KB
|
|
- RAM-Bedarf: < 32 KB
|
|
- Stromaufnahme: < 200 mA (Standby) / < 30 A (Aktor-Spitze)
|
|
""").strip(),
|
|
},
|
|
{
|
|
"id": "SA-002", "links": ["SYS-001", "SYS-002", "SYS-003", "SYS-007"],
|
|
"title": "Aktoren (Caliper-Motoren)",
|
|
"asil": "D",
|
|
"text": textwrap.dedent("""
|
|
## Verantwortung
|
|
|
|
Zwei elektromechanische Aktoren an den hinteren Bremssaetteln klemmen
|
|
und loesen die Bremsbelaege. Geliefert (Annahme): kommerzielles Bauteil
|
|
eines Tier-1-Lieferanten.
|
|
|
|
## Schnittstellen
|
|
|
|
| Schnittstelle | Typ | Bemerkung |
|
|
|---------------|--------------|-----------------------------------|
|
|
| Power | 12 V, PWM | bidirektional fuer Apply/Release |
|
|
| Strom-Shunt | Analog | wird in der ECU abgegriffen |
|
|
|
|
## Nichtfunktionale Eigenschaften
|
|
|
|
- Max. Klemmkraft: 20 kN
|
|
- Apply-Zeit (0 → max): 600 ms
|
|
- Strom (nominal): 4 A
|
|
- Strom (Spitze): 30 A (kurzzeitig)
|
|
- Temperaturbereich: -40°C bis +85°C
|
|
""").strip(),
|
|
},
|
|
{
|
|
"id": "SA-003", "links": ["SYS-005", "SYS-006", "SYS-007"],
|
|
"title": "Sensor-Cluster",
|
|
"asil": "B",
|
|
"text": textwrap.dedent("""
|
|
## Verantwortung
|
|
|
|
Zusammenfassung aller fuer die EPB benoetigten Eingangssignale:
|
|
Wheel-Speed-Sensoren (4x), Inclinometer (1x), EPB-Schalter, Bremspedal-
|
|
Status, Gear-Position, Door-Open, Seat-Belt — die letzten vier per CAN.
|
|
|
|
## Schnittstellen
|
|
|
|
| Sensor | Typ | Quelle |
|
|
|-----------------|------------------|--------------|
|
|
| Wheel Speed x4 | Hall-Pulse | direkt |
|
|
| Inclinometer | SPI 1 kHz | direkt |
|
|
| EPB-Schalter | GPIO | direkt |
|
|
| Bremspedal | CAN 0x100 | aus BCM |
|
|
| Gear | CAN 0x110 | aus TCU |
|
|
| Door / Belt | CAN 0x120 | aus BCM |
|
|
|
|
## Nichtfunktionale Eigenschaften
|
|
|
|
- Wheel-Speed-Genauigkeit: +/- 0.1 km/h ab 1 km/h
|
|
- Inclinometer-Genauigkeit: +/- 0.5°
|
|
- Sampling-Frequenz Inclinometer: 100 Hz
|
|
""").strip(),
|
|
},
|
|
{
|
|
"id": "SA-004", "links": ["SYS-008", "SYS-010"],
|
|
"title": "HMI (Schalter, LED, Display)",
|
|
"asil": "QM",
|
|
"text": textwrap.dedent("""
|
|
## Verantwortung
|
|
|
|
Fahrer-Interaktion und -Information: Tippschalter mit integrierter LED,
|
|
Statusanzeige im Kombi-Display via CAN.
|
|
|
|
## Schnittstellen
|
|
|
|
| Element | Typ | Verhalten |
|
|
|---------------|----------|--------------------------------------------|
|
|
| Tippschalter | GPIO | Apply-Richtung / Release-Richtung |
|
|
| LED | GPIO | aus / an / blink 2 Hz / blink 4 Hz |
|
|
| Display | CAN 0x3A0 | 50 Hz Status-Frame |
|
|
""").strip(),
|
|
},
|
|
{
|
|
"id": "SA-005", "links": ["SYS-009", "SYS-010"],
|
|
"title": "CAN-Bus",
|
|
"asil": "QM",
|
|
"text": textwrap.dedent("""
|
|
## Verantwortung
|
|
|
|
Kommunikations-Backbone fuer Eingangsdaten (Bremspedal, Gang, Tuer, Gurt),
|
|
Ausgabe (Status-Frame an Display) und Diagnose (UDS auf Tester-Adresse).
|
|
|
|
## Schnittstellen
|
|
|
|
- Baudrate: 500 kbit/s, CAN 2.0B
|
|
- Empfangene Frames: 0x100 (Bremspedal), 0x110 (Gang), 0x120 (Door/Belt),
|
|
0x712 (UDS-Request)
|
|
- Gesendete Frames: 0x3A0 (Status 50 Hz), 0x71A (UDS-Response)
|
|
""").strip(),
|
|
},
|
|
]
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Software Architecture Elements
|
|
# ---------------------------------------------------------------------------
|
|
|
|
SWA_ELEMENTS = [
|
|
{
|
|
"id": "SWA-001", "asil": "D",
|
|
"links": ["SWE-007", "SWE-008", "SWE-009", "SWE-010", "SWE-011", "SWE-012"],
|
|
"title": "Safety Manager",
|
|
"text": textwrap.dedent("""
|
|
## Verantwortung
|
|
|
|
Hoechste Sicherheitsschicht. Erkennt Motor-Aus, aktiviert Hill-Hold,
|
|
triggert Auto-Apply. Lebenswichtige Logik mit redundanter Pruefung.
|
|
|
|
## Statische Sicht
|
|
|
|
```plantuml
|
|
@startuml
|
|
package "Safety Manager" {
|
|
[Engine State Monitor]
|
|
[Hill-Hold Logic]
|
|
[Auto-Apply Logic]
|
|
}
|
|
[Safety Manager] ..> [Apply Controller] : Apply-Anforderung
|
|
[Wheel Speed Plausi] --> [Safety Manager] : v_vehicle
|
|
[Inclinometer Filter] --> [Safety Manager] : grade
|
|
@enduml
|
|
```
|
|
|
|
## Schnittstellen (Provided)
|
|
|
|
```c
|
|
Status safety_mgr_init(void);
|
|
void safety_mgr_step_50ms(const SafetyInputs* in);
|
|
```
|
|
|
|
## Dynamisches Verhalten
|
|
|
|
```plantuml
|
|
@startuml
|
|
[*] --> Idle
|
|
Idle --> HillHoldArmed : grade>5% & v=0 & brake
|
|
HillHoldArmed --> HillHoldActive : brake released
|
|
HillHoldActive --> Idle : v>2 km/h
|
|
Idle --> AutoApplyArmed : engine_off & v=0
|
|
AutoApplyArmed --> AutoApplyTriggered : t>=2s
|
|
AutoApplyTriggered --> Idle : applied
|
|
@enduml
|
|
```
|
|
|
|
## Ressourcen
|
|
|
|
- Stack: <= 256 B
|
|
- Worst-Case Timing: 200 us / Aufruf
|
|
|
|
## Mapping auf Anforderungen
|
|
|
|
| Anforderung | Wie abgedeckt |
|
|
|-------------|---------------|
|
|
| SWE-007 | engine_off + v<0.5 in step_50ms |
|
|
| SWE-008 | 2s-Filter und Trigger |
|
|
| SWE-009 | Hill-Hold-Aktivierung |
|
|
| SWE-010 | Brake-Released-Detektion |
|
|
""").strip(),
|
|
},
|
|
{
|
|
"id": "SWA-002", "asil": "D",
|
|
"links": ["SWE-001", "SWE-002", "SWE-003", "SWE-004", "SWE-005"],
|
|
"title": "Apply Controller",
|
|
"text": textwrap.dedent("""
|
|
## Verantwortung
|
|
|
|
Zentraler Controller fuer Apply, Hold und Release der Parkbremse.
|
|
ASIL-D-Kern der EPB-Software. Implementiert in `src/apply_controller.c`.
|
|
|
|
## Statische Sicht
|
|
|
|
```plantuml
|
|
@startuml
|
|
[Apply Controller] --> [Actuator Driver L] : apply/release
|
|
[Apply Controller] --> [Actuator Driver R] : apply/release
|
|
[Switch Debouncer] --> [Apply Controller] : sw_apply, sw_release
|
|
[Safety Manager] --> [Apply Controller] : auto_apply, hill_hold_request
|
|
[Apply Controller] --> [Display Manager] : status
|
|
[Apply Controller] <-- [Watchdog] : alive_check
|
|
@enduml
|
|
```
|
|
|
|
## Schnittstellen (Provided)
|
|
|
|
```c
|
|
Status apply_ctrl_init(void);
|
|
void apply_ctrl_step_50ms(const ApplyInputs* in);
|
|
EpbStatus apply_ctrl_get_status(void);
|
|
```
|
|
|
|
## Dynamisches Verhalten
|
|
|
|
```plantuml
|
|
@startuml
|
|
[*] --> Released
|
|
Released --> Applying : apply_request & v_low
|
|
Applying --> Applied : current_target_reached
|
|
Applied --> Releasing : release_request & preconditions_ok
|
|
Applied --> Applied : 50ms hold check (re-clamp if needed)
|
|
Releasing --> Released : release_complete
|
|
Applying --> Error : timeout > 1500ms
|
|
Releasing --> Error : timeout > 1200ms
|
|
Error --> Released : reset & no fault
|
|
@enduml
|
|
```
|
|
|
|
## Ressourcen
|
|
|
|
- Stack: <= 384 B
|
|
- Worst-Case Timing: 350 us / Aufruf
|
|
|
|
## Designentscheidungen
|
|
|
|
| Entscheidung | Begruendung |
|
|
|--------------|-------------|
|
|
| Statische Allokation, kein Heap | Determinismus, MISRA C 21.3 |
|
|
| State Machine | Einfacher zu verifizieren, deterministisch |
|
|
| 50ms Step-Funktion | Synchron zur Inclinometer-Abtastung |
|
|
|
|
## Mapping auf Anforderungen
|
|
|
|
| Anforderung | Wie abgedeckt |
|
|
|-------------|---------------|
|
|
| SWE-001 | Hold-Zustand mit periodischer Klemmkraft-Pruefung |
|
|
| SWE-002 | Watchdog-Pet im step_50ms |
|
|
| SWE-003 | sw_apply Input wird sofort ausgewertet |
|
|
| SWE-004 | Current-Target-Detektion via Actuator-Driver-Feedback |
|
|
""").strip(),
|
|
},
|
|
{
|
|
"id": "SWA-003", "asil": "B",
|
|
"links": ["SWE-006", "SWE-013", "SWE-014", "SWE-015"],
|
|
"title": "Actuator Driver",
|
|
"text": textwrap.dedent("""
|
|
## Verantwortung
|
|
|
|
Low-Level-Ansteuerung der beiden Aktor-Motoren. PWM-Generierung,
|
|
Strom-Messung, Overcurrent-Cutoff, Klemmkraft-Schaetzung.
|
|
Implementiert in `src/actuator_driver.c`.
|
|
|
|
## Statische Sicht
|
|
|
|
```plantuml
|
|
@startuml
|
|
[Apply Controller] --> [Actuator Driver]
|
|
[Actuator Driver] --> [Hardware PWM] : pwm_set
|
|
[Actuator Driver] <-- [Hardware ADC] : current_sample
|
|
[Actuator Driver] --> [Diagnostic Manager] : DTC
|
|
@enduml
|
|
```
|
|
|
|
## Schnittstellen (Provided)
|
|
|
|
```c
|
|
Status actuator_init(void);
|
|
void actuator_apply(ActuatorId id, uint8_t pwm_percent);
|
|
void actuator_release(ActuatorId id, uint8_t pwm_percent);
|
|
void actuator_stop(ActuatorId id);
|
|
ActuatorStatus actuator_get_status(ActuatorId id);
|
|
void actuator_isr_1khz(void); // Strom-Sampling
|
|
```
|
|
|
|
## Ressourcen
|
|
|
|
- Stack: <= 256 B
|
|
- Worst-Case Timing: 50 us / ISR
|
|
- Static RAM: 64 B pro Aktor
|
|
|
|
## Mapping auf Anforderungen
|
|
|
|
| Anforderung | Wie abgedeckt |
|
|
|-------------|---------------|
|
|
| SWE-006 | actuator_release fuer beide Aktoren parallel |
|
|
| SWE-013 | actuator_isr_1khz |
|
|
| SWE-014 | Overcurrent-Detektor in ISR |
|
|
| SWE-015 | Peak-Current-Tracking + lineare Klemmkraft-Schaetzung |
|
|
""").strip(),
|
|
},
|
|
{
|
|
"id": "SWA-004", "asil": "B",
|
|
"links": ["SWE-022", "SWE-023"],
|
|
"title": "Wheel Speed Plausibilisierung",
|
|
"text": textwrap.dedent("""
|
|
## Verantwortung
|
|
|
|
Aufbereitung und Plausibilisierung der 4 Wheel-Speed-Signale. Erkennt
|
|
Stillstand und plausibilisiert untereinander.
|
|
|
|
## Schnittstellen (Provided)
|
|
|
|
```c
|
|
Status wheel_speed_init(void);
|
|
void wheel_speed_step_10ms(const WheelInputs* in);
|
|
bool wheel_speed_is_standstill(void);
|
|
float wheel_speed_get_vehicle(void);
|
|
```
|
|
""").strip(),
|
|
},
|
|
{
|
|
"id": "SWA-005", "asil": "B",
|
|
"links": ["SWE-024"],
|
|
"title": "Inclinometer Filter",
|
|
"text": textwrap.dedent("""
|
|
## Verantwortung
|
|
|
|
Tiefpass-Filterung des Inclinometer-Roh-Signals fuer die Hill-Hold-Bewertung.
|
|
|
|
## Schnittstellen (Provided)
|
|
|
|
```c
|
|
Status inclino_init(void);
|
|
void inclino_step_10ms(int16_t raw_mdeg);
|
|
float inclino_get_grade_percent(void);
|
|
```
|
|
""").strip(),
|
|
},
|
|
{
|
|
"id": "SWA-006", "asil": "QM",
|
|
"links": ["SWE-025"],
|
|
"title": "Switch Debouncer",
|
|
"text": textwrap.dedent("""
|
|
## Verantwortung
|
|
|
|
Software-Entprellung des EPB-Schalters. Liefert stabiles Apply / Release
|
|
Signal an den Apply-Controller. Implementiert in `src/switch_debouncer.c`.
|
|
|
|
## Schnittstellen (Provided)
|
|
|
|
```c
|
|
Status switch_init(void);
|
|
void switch_step_10ms(SwitchRaw raw);
|
|
SwitchState switch_get_state(void);
|
|
```
|
|
|
|
## Mapping auf Anforderungen
|
|
|
|
| Anforderung | Wie abgedeckt |
|
|
|-------------|---------------|
|
|
| SWE-025 | 50ms Debounce-Logik |
|
|
""").strip(),
|
|
},
|
|
{
|
|
"id": "SWA-007", "asil": "QM",
|
|
"links": ["SWE-020", "SWE-021"],
|
|
"title": "Display Manager",
|
|
"text": textwrap.dedent("""
|
|
## Verantwortung
|
|
|
|
Steuert LED am EPB-Schalter und CAN-Status-Frame an das Kombi-Display.
|
|
Empfaengt Status vom Apply-Controller.
|
|
|
|
## Schnittstellen (Provided)
|
|
|
|
```c
|
|
Status display_init(void);
|
|
void display_set_status(EpbStatus s);
|
|
void display_step_20ms(void); // 50 Hz CAN-Frame
|
|
```
|
|
""").strip(),
|
|
},
|
|
{
|
|
"id": "SWA-008", "asil": "QM",
|
|
"links": ["SWE-018", "SWE-019"],
|
|
"title": "Diagnostic Manager",
|
|
"text": textwrap.dedent("""
|
|
## Verantwortung
|
|
|
|
UDS-Diagnose nach ISO 14229: ReadDTC, ReadDataByIdentifier, RoutineControl.
|
|
|
|
## Schnittstellen (Provided)
|
|
|
|
```c
|
|
Status diag_init(void);
|
|
void diag_handle_request(const uint8_t* data, uint16_t len);
|
|
void diag_set_dtc(uint16_t dtc_id);
|
|
```
|
|
""").strip(),
|
|
},
|
|
{
|
|
"id": "SWA-009", "asil": "QM",
|
|
"links": ["SWE-016", "SWE-017"],
|
|
"title": "Service Mode",
|
|
"text": textwrap.dedent("""
|
|
## Verantwortung
|
|
|
|
Service-Modus fuer Werkstatt. Wird ueber UDS RoutineControl 0x31, Routine-ID
|
|
0x0301 aktiviert. Steuert Aktoren in Wartungsposition.
|
|
""").strip(),
|
|
},
|
|
{
|
|
"id": "SWA-010", "asil": "QM",
|
|
"links": ["SWE-018", "SWE-019"],
|
|
"title": "Logger",
|
|
"text": textwrap.dedent("""
|
|
## Verantwortung
|
|
|
|
Logging fuer Entwicklung und Service. Ringpuffer im RAM (1 KB) sowie
|
|
Persistenz im EEPROM bei kritischen Ereignissen.
|
|
|
|
## Schnittstellen (Provided)
|
|
|
|
```c
|
|
Status log_init(void);
|
|
void log_event(LogLevel lvl, uint16_t event_id, uint32_t param);
|
|
```
|
|
""").strip(),
|
|
},
|
|
]
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Generation
|
|
# ---------------------------------------------------------------------------
|
|
|
|
REQ_FRONTMATTER = textwrap.dedent("""
|
|
---
|
|
active: true
|
|
derived: false
|
|
header: '{title}'
|
|
level: 1.{level}
|
|
normative: true
|
|
reviewed: null
|
|
links:{links_yaml}
|
|
asil: {asil}
|
|
---
|
|
|
|
# {id}: {title}
|
|
|
|
{text}
|
|
""").strip() + "\n"
|
|
|
|
|
|
def emit_links(links):
|
|
if not links:
|
|
return " []"
|
|
parts = ["\n - {}".format(l) for l in links]
|
|
return "".join(parts)
|
|
|
|
|
|
def write_items(items, target_dir: Path, with_links=True):
|
|
target_dir.mkdir(parents=True, exist_ok=True)
|
|
for i, item in enumerate(items, start=1):
|
|
path = target_dir / f"{item['id']}.md"
|
|
links_yaml = emit_links(item.get("links", []))
|
|
content = REQ_FRONTMATTER.format(
|
|
title=item["title"],
|
|
level=i,
|
|
links_yaml=links_yaml,
|
|
asil=item["asil"],
|
|
id=item["id"],
|
|
text=item["text"],
|
|
)
|
|
path.write_text(content)
|
|
print(f"Wrote {len(items)} items to {target_dir.relative_to(REPO)}/")
|
|
|
|
|
|
def main():
|
|
write_items(SYS_REQS, REPO / "reqs" / "sys")
|
|
write_items(SWE_REQS, REPO / "reqs" / "swe")
|
|
write_items(SA_ELEMENTS, REPO / "arch" / "sys")
|
|
write_items(SWA_ELEMENTS, REPO / "arch" / "swe")
|
|
print("\nTotal: {} reqs/arch items.".format(
|
|
len(SYS_REQS) + len(SWE_REQS) + len(SA_ELEMENTS) + len(SWA_ELEMENTS)
|
|
))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|