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,808 @@
|
||||
#!/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"],
|
||||
"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"],
|
||||
"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()
|
||||
Reference in New Issue
Block a user