Files
demo-epb/tools/generate_doorstop_items.py
T
Stefan Lohmaier a47e0aed3e
Validate / build-test (macos-latest) (push) Failing after 2s
Validate / build-test (windows-latest) (push) Failing after 16s
Validate / build-test (ubuntu-latest) (push) Successful in 18s
Validate / reports (push) Successful in 52s
feat(i18n): tools + landing page + doorstop generator in English
Phase 1 of full English translation:
- generate_doorstop_items.py: all 55 items (SG/SYS/SWE/SA/SWA) rewritten in English
- generate_landing_page.py: full UI labels, KPI cards, section headings in English
- traceability.py: docstring, error messages, HTML headers in English
- generate_test_report.py: report content + table headers in English
- All 55 markdown items in safety/sg/, reqs/, arch/ regenerated in English

Still to come:
- demo-epb filled Word docs (PID, plans, safety, manuals, audit artefacts)
- Code comments + test names + CI workflow step names
- README + dev-process repo templates
2026-05-12 03:28:54 -07:00

892 lines
31 KiB
Python

#!/usr/bin/env python3
"""
Generate Doorstop-compatible Markdown items for the EPB demo.
Source of truth: the dicts below.
Outputs to: safety/sg/, 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
# ---------------------------------------------------------------------------
# Safety Goals (ISO 26262, derived from HARA)
# ---------------------------------------------------------------------------
SG_GOALS = [
{
"id": "SG-001", "asil": "D",
"title": "No unintended release of the parking brake during standstill",
"text": (
"The EPB shall not unintentionally release while the vehicle is at "
"a standstill. Derived from HARA hazards H-01 (unintended release "
"during parking) and H-04 (clamping force loss in hold state).\n\n"
"**FTTI:** 5 s (H-01) / 30 s (H-04).\n"
"**Safe state:** APPLIED (maintain clamping force)."
),
},
{
"id": "SG-002", "asil": "D",
"title": "No unintended clamping while driving",
"text": (
"The EPB shall not unintentionally clamp while the vehicle is "
"moving. Derived from HARA hazard H-02.\n\n"
"**FTTI:** 100 ms.\n"
"**Safe state:** Actuator stop (do not initiate apply)."
),
},
{
"id": "SG-003", "asil": "A",
"title": "Protection against actuator overload",
"text": (
"The system shall prevent actuator motor damage due to overcurrent. "
"Derived from HARA hazard H-05.\n\n"
"**FTTI:** 100 ms.\n"
"**Safe state:** Disable actuator, set DTC."
),
},
{
"id": "SG-004", "asil": "C",
"title": "Reliable hill-hold handover",
"text": (
"When the driver releases the brake pedal on an incline, the EPB "
"shall take over the braking force before the vehicle starts "
"rolling. Derived from HARA hazard H-06.\n\n"
"**FTTI:** 500 ms.\n"
"**Safe state:** Initiate apply."
),
},
{
"id": "SG-005", "asil": "B",
"title": "Response to driver requests",
"text": (
"The system shall respond to driver apply and release requests "
"within specified times. Derived from HARA hazards H-03 and H-07.\n\n"
"**Response time:** apply <= 800 ms, release <= 1500 ms."
),
},
]
# ---------------------------------------------------------------------------
# System Requirements (link upward to SG)
# ---------------------------------------------------------------------------
SYS_REQS = [
{
"id": "SYS-001", "asil": "D",
"links": ["SG-001"],
"title": "Holding the parking brake at standstill",
"text": (
"When the parking brake is engaged and the vehicle is at a "
"standstill, the EPB system must maintain the mechanical clamping "
"force on both rear callipers until a release is explicitly "
"requested. Safety goal: SG-001.\n\n"
"**Verification:** SiL test with up/down grade scenarios, "
"clamping force measurement."
),
},
{
"id": "SYS-002", "asil": "D",
"links": ["SG-002", "SG-005"],
"title": "Apply on driver request",
"text": (
"On apply-direction actuation of the EPB switch, the system must "
"engage the parking brake within 800 ms, provided the "
"preconditions are met (standstill or vehicle speed below 5 km/h). "
"Safety goal: SG-002."
),
},
{
"id": "SYS-003", "asil": "B",
"links": ["SG-005"],
"title": "Release on driver request",
"text": (
"On release-direction actuation of the EPB switch, the system "
"must release the parking brake provided the following "
"preconditions are met: engine running, driver pressing the brake "
"pedal, a gear is engaged. Maximum release time: 1500 ms."
),
},
{
"id": "SYS-004", "asil": "D",
"links": ["SG-001"],
"title": "Auto-apply on engine off",
"text": (
"When the engine is switched off and the vehicle is at a "
"standstill, and the parking brake is not yet engaged, the system "
"must automatically engage the parking brake at the latest 2 s "
"after detecting engine-off. Safety goal: SG-001."
),
},
{
"id": "SYS-005", "asil": "D",
"links": ["SG-002", "SG-004"],
"title": "Hill-hold on an incline",
"text": (
"When hill-hold is active (vehicle on a slope with grade > 5%, "
"driver pressing the brake pedal), the EPB system shall take over "
"the brake force when the brake pedal is released and shall "
"maintain it until drive-away is detected. Safety goal: SG-002."
),
},
{
"id": "SYS-006", "asil": "B",
"links": ["SG-004"],
"title": "Auto-release on drive-away (Drive-Away Assist)",
"text": (
"When the parking brake is engaged and the driver shows intent "
"to drive away (throttle actuation with gear engaged), the "
"system must release the parking brake within 500 ms. "
"Precondition: all safety criteria (driver door closed, seatbelt "
"fastened) are met."
),
},
{
"id": "SYS-007", "asil": "B",
"links": ["SG-003"],
"title": "Actuator current monitoring",
"text": (
"The system must monitor the motor current of each actuator at "
"at least 1 kHz and, on exceeding 8 A for more than 100 ms, "
"shut down the actuator and set a DTC. Safety goal: SG-003."
),
},
{
"id": "SYS-008", "asil": "QM",
"title": "Service mode for the workshop",
"text": (
"The system must provide a service mode via UDS RoutineControl "
"(service 0x31) in which the actuators can be moved manually "
"into maintenance position (e.g. for brake pad replacement)."
),
},
{
"id": "SYS-009", "asil": "QM",
"title": "UDS diagnostics",
"text": (
"The system must provide UDS diagnostics per ISO 14229: "
"ReadDTC (0x19), ReadDataByIdentifier (0x22), RoutineControl "
"(0x31), ECUReset (0x11). Tester address 0x712, response "
"address 0x71A."
),
},
{
"id": "SYS-010", "asil": "QM",
"title": "HMI status display",
"text": (
"The EPB status must be signalled to the driver: LED on the "
"switch (on = applied, off = released, blinking = error) and a "
"text in the instrument cluster via CAN bus (frame ID 0x3A0, "
"50 Hz)."
),
},
]
# ---------------------------------------------------------------------------
# Software Requirements (each links to one or more SYS reqs)
# ---------------------------------------------------------------------------
SWE_REQS = [
# SYS-001 — hold
{"id": "SWE-001", "asil": "D", "links": ["SYS-001"],
"title": "Apply controller maintains clamping force",
"text": "The apply controller must verify the clamping force in the hold "
"state every 50 ms and re-apply when the deviation exceeds 10%."},
{"id": "SWE-002", "asil": "D", "links": ["SYS-001"],
"title": "Watchdog monitors the apply controller",
"text": "An independent watchdog must monitor the liveness of the apply "
"controller with a 100 ms timeout and, on failure to respond, "
"transition to the safe state (apply)."},
# SYS-002 — apply
{"id": "SWE-003", "asil": "D", "links": ["SYS-002"],
"title": "Forward switch apply signal to the apply controller",
"text": "The Switch Debouncer software module must deliver a debounced "
"apply signal to the apply controller within 50 ms."},
{"id": "SWE-004", "asil": "D", "links": ["SYS-002"],
"title": "Confirm target clamping force reached",
"text": "The apply controller must detect that the target clamping force "
"has been reached via current measurement and set a status flag."},
# SYS-003 — release
{"id": "SWE-005", "asil": "B", "links": ["SYS-003"],
"title": "Check release preconditions",
"text": "Before any release, the apply controller must verify: engine "
"running, brake pedal pressed, gear engaged. Otherwise reject "
"the release."},
{"id": "SWE-006", "asil": "B", "links": ["SYS-003"],
"title": "Drive actuators into release position",
"text": "The Actuator Driver must drive both actuators in parallel into "
"the release position. Maximum time: 1200 ms. On timeout, set a "
"DTC."},
# SYS-004 — auto-apply
{"id": "SWE-007", "asil": "D", "links": ["SYS-004"],
"title": "Detect engine-off condition",
"text": "The Safety Manager must detect: engine status = off, vehicle "
"speed < 0.5 km/h. Sampling period 50 ms."},
{"id": "SWE-008", "asil": "D", "links": ["SYS-004"],
"title": "Auto-apply after 2 s delay",
"text": "If the engine-off condition is stable for 2 s and the parking "
"brake is not yet active, the Safety Manager must send an apply "
"request to the apply controller."},
# SYS-005 — hill-hold
{"id": "SWE-009", "asil": "D", "links": ["SYS-005"],
"title": "Hill-hold activation condition",
"text": "The Safety Manager must activate hill-hold when grade "
"(filtered) > 5%, vehicle speed < 0.5 km/h and the brake pedal "
"is pressed."},
{"id": "SWE-010", "asil": "D", "links": ["SYS-005"],
"title": "Hill-hold handover to the apply controller",
"text": "If the brake pedal is released while hill-hold is active, the "
"Safety Manager must immediately send an apply request to the "
"apply controller before the vehicle can start to roll."},
# SYS-006 — auto-release
{"id": "SWE-011", "asil": "B", "links": ["SYS-006"],
"title": "Detect drive-away intent",
"text": "Drive-away intent is detected when: throttle > 10%, gear in "
"forward or reverse, engine running."},
{"id": "SWE-012", "asil": "B", "links": ["SYS-006"],
"title": "Safety check before auto-release",
"text": "Before auto-release, the following must be satisfied: driver "
"door closed, seatbelt fastened. Otherwise warn and do not "
"release."},
# SYS-007 — actuator current
{"id": "SWE-013", "asil": "B", "links": ["SYS-007"],
"title": "Current sampling at 1 kHz",
"text": "The Actuator Driver must sample the motor current of each "
"actuator at at least 1 kHz. Accuracy +/- 100 mA."},
{"id": "SWE-014", "asil": "B", "links": ["SYS-007"],
"title": "Overcurrent cutoff",
"text": "On motor current > 8 A for longer than 100 ms, the Actuator "
"Driver must shut down the motor and set DTC P0xxx."},
{"id": "SWE-015", "asil": "B", "links": ["SYS-007"],
"title": "Clamping force estimation from current profile",
"text": "The Actuator Driver must estimate the achieved clamping force "
"from the current waveform during apply (model: F = k * I_peak)."},
# SYS-008 — service mode
{"id": "SWE-016", "asil": "QM", "links": ["SYS-008"],
"title": "UDS RoutineControl 0x31 for service release",
"text": "Service mode is activated via UDS RoutineControl service 0x31, "
"routine ID 0x0301. Precondition: vehicle must be at standstill."},
{"id": "SWE-017", "asil": "QM", "links": ["SYS-008"],
"title": "Service mode indicator",
"text": "While in service mode, the EPB LED on the switch must blink "
"at 2 Hz."},
# SYS-009 — UDS
{"id": "SWE-018", "asil": "QM", "links": ["SYS-009"],
"title": "UDS service 0x19 ReadDTC",
"text": "The system must output all stored DTCs via service 0x19 "
"(sub-function 0x02 reportDTCByStatusMask)."},
{"id": "SWE-019", "asil": "QM", "links": ["SYS-009"],
"title": "UDS service 0x22 ReadDataByIdentifier",
"text": "The following DIDs must be readable: 0xF187 (SW version), "
"0x0301 (clamping force left), 0x0302 (clamping force right)."},
# SYS-010 — HMI
{"id": "SWE-020", "asil": "QM", "links": ["SYS-010"],
"title": "LED control",
"text": "Apply active: LED solid. Release: LED off. Fault: LED blinks "
"at 4 Hz. Service mode: LED blinks at 2 Hz."},
{"id": "SWE-021", "asil": "QM", "links": ["SYS-010"],
"title": "CAN status frame",
"text": "Status frame 0x3A0 at 50 Hz: byte 0 = status (0=released, "
"1=applied, 2=applying, 3=releasing, 0xFF=error), byte 1-2 = "
"left clamping force, byte 3-4 = right clamping force."},
# Sensors & plausibilisation
{"id": "SWE-022", "asil": "B", "links": ["SYS-001", "SYS-002", "SYS-006"],
"title": "Standstill detection from wheel speeds",
"text": "Standstill is detected when all 4 wheel-speed signals stay "
"below 0.5 km/h for at least 200 ms."},
{"id": "SWE-023", "asil": "B", "links": ["SYS-007"],
"title": "Wheel-speed plausibilisation",
"text": "Spread of the wheel-speed signals: when driving straight, the "
"difference must not exceed 3 km/h. Otherwise set a sensor "
"fault DTC."},
{"id": "SWE-024", "asil": "B", "links": ["SYS-005"],
"title": "Inclinometer low-pass filter",
"text": "The raw inclinometer signal must be filtered with a first-"
"order low-pass (time constant 200 ms) before being used for "
"hill-hold evaluation."},
{"id": "SWE-025", "asil": "QM", "links": ["SYS-002", "SYS-003"],
"title": "Switch debouncing",
"text": "The EPB switch must be debounced with a debounce time of "
"50 ms. Stable level = input signal for the 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("""
## Responsibility
Central control unit of the electric parking brake. Contains all
software components and the electronic actuation of the actuators.
## System context
```plantuml
@startuml
node "EPB ECU" as ECU
node "Actuator left" as AL
node "Actuator right" as AR
node "Wheel-speed sensors (x4)" as WS
node "Inclinometer" as IN
node "EPB switch + LED" as SW
node "CAN bus" as CAN
node "Instrument cluster" as DI
node "OBD tester" as OBD
ECU --> AL : PWM, I-meas
ECU --> AR : PWM, I-meas
WS --> ECU : pulses
IN --> ECU : SPI
SW --> ECU : GPIO
ECU --> SW : LED
ECU <-> CAN
CAN <-> DI
CAN <-> OBD
@enduml
```
## Interfaces
| Interface | Type | Direction |
|---------------|------------------|-----------|
| Actuator L/R | PWM + shunt | I/O |
| Wheel speed | Hall pulses | in |
| Inclinometer | SPI | in |
| Switch | GPIO debounced | in |
| LED | GPIO | out |
| CAN | ISO 11898 | I/O |
## Subcomponents (allocated to software)
Realised in software: all SWA elements SWA-001..SWA-010.
## Non-functional properties
- Worst-case reaction time (switch to actuator motion): 250 ms
- Flash demand: < 256 KB
- RAM demand: < 32 KB
- Current: < 200 mA (standby) / < 30 A (actuator peak)
""").strip(),
},
{
"id": "SA-002", "links": ["SYS-001", "SYS-002", "SYS-003", "SYS-007"],
"title": "Actuators (calliper motors)",
"asil": "D",
"text": textwrap.dedent("""
## Responsibility
Two electromechanical actuators on the rear callipers clamp and
release the brake pads. Supplied (assumption): commercial component
from a Tier-1 supplier.
## Interfaces
| Interface | Type | Notes |
|---------------|--------------|---------------------------------|
| Power | 12 V, PWM | bidirectional for apply/release |
| Current shunt | analog | sampled inside the ECU |
## Non-functional properties
- Max clamping force: 20 kN
- Apply time (0 → max): 600 ms
- Nominal current: 4 A
- Peak current: 30 A (brief)
- Temperature range: -40 °C to +85 °C
""").strip(),
},
{
"id": "SA-003", "links": ["SYS-005", "SYS-006", "SYS-007"],
"title": "Sensor cluster",
"asil": "B",
"text": textwrap.dedent("""
## Responsibility
Summary of all input signals required by the EPB: wheel-speed
sensors (4x), inclinometer (1x), EPB switch, brake-pedal status,
gear position, door open, seatbelt — the last four via CAN.
## Interfaces
| Sensor | Type | Source |
|-----------------|--------------|------------|
| Wheel speed x4 | Hall pulses | direct |
| Inclinometer | SPI 1 kHz | direct |
| EPB switch | GPIO | direct |
| Brake pedal | CAN 0x100 | from BCM |
| Gear | CAN 0x110 | from TCU |
| Door / belt | CAN 0x120 | from BCM |
## Non-functional properties
- Wheel-speed accuracy: +/- 0.1 km/h above 1 km/h
- Inclinometer accuracy: +/- 0.5°
- Inclinometer sampling rate: 100 Hz
""").strip(),
},
{
"id": "SA-004", "links": ["SYS-008", "SYS-010"],
"title": "HMI (switch, LED, display)",
"asil": "QM",
"text": textwrap.dedent("""
## Responsibility
Driver interaction and information: tap switch with integrated LED,
status display in the instrument cluster via CAN.
## Interfaces
| Element | Type | Behaviour |
|---------------|----------|-------------------------------------------|
| Tap switch | GPIO | apply direction / release direction |
| LED | GPIO | off / on / 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("""
## Responsibility
Communication backbone for input data (brake pedal, gear, door,
belt), output (status frame to the display) and diagnostics (UDS
on the tester address).
## Interfaces
- Baud rate: 500 kbit/s, CAN 2.0B
- Received frames: 0x100 (brake pedal), 0x110 (gear),
0x120 (door/belt), 0x712 (UDS request)
- Sent 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("""
## Responsibility
Highest safety layer. Detects engine-off, activates hill-hold,
triggers auto-apply. Life-critical logic with redundant checks.
## Static view
```plantuml
@startuml
package "Safety Manager" {
[Engine State Monitor]
[Hill-Hold Logic]
[Auto-Apply Logic]
}
[Safety Manager] ..> [Apply Controller] : apply request
[Wheel Speed Plausi] --> [Safety Manager] : v_vehicle
[Inclinometer Filter] --> [Safety Manager] : grade
@enduml
```
## Provided interfaces
```c
Status safety_mgr_init(void);
void safety_mgr_step_50ms(const SafetyInputs* in);
```
## Dynamic behaviour
```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
```
## Resources
- Stack: <= 256 B
- Worst-case timing: 200 us per call
## Mapping to requirements
| Requirement | How covered |
|-------------|-------------|
| SWE-007 | engine_off + v<0.5 in step_50ms |
| SWE-008 | 2 s filter and trigger |
| SWE-009 | hill-hold activation |
| SWE-010 | brake-released detection |
""").strip(),
},
{
"id": "SWA-002", "asil": "D",
"links": ["SWE-001", "SWE-002", "SWE-003", "SWE-004", "SWE-005"],
"title": "Apply Controller",
"text": textwrap.dedent("""
## Responsibility
Central controller for apply, hold and release of the parking brake.
ASIL-D core of the EPB software. Implemented in
`src/apply_controller.c`.
## Static view
```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
```
## Provided interfaces
```c
Status apply_ctrl_init(void);
void apply_ctrl_step_50ms(const ApplyInputs* in);
EpbStatus apply_ctrl_get_status(void);
```
## Dynamic behaviour
```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
```
## Resources
- Stack: <= 384 B
- Worst-case timing: 350 us per call
## Design decisions
| Decision | Rationale |
|----------|-----------|
| Static allocation, no heap | Determinism, MISRA C 21.3 |
| State machine | Easier to verify, deterministic |
| 50 ms step function | Synchronous with inclinometer sample rate |
## Mapping to requirements
| Requirement | How covered |
|-------------|-------------|
| SWE-001 | Hold state with periodic clamping-force check |
| SWE-002 | Watchdog pet in step_50ms |
| SWE-003 | sw_apply input is evaluated immediately |
| SWE-004 | current-target detection 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("""
## Responsibility
Low-level control of the two actuator motors. PWM generation,
current measurement, overcurrent cutoff, clamping-force estimation.
Implemented in `src/actuator_driver.c`.
## Static view
```plantuml
@startuml
[Apply Controller] --> [Actuator Driver]
[Actuator Driver] --> [Hardware PWM] : pwm_set
[Actuator Driver] <-- [Hardware ADC] : current_sample
[Actuator Driver] --> [Diagnostic Manager] : DTC
@enduml
```
## Provided interfaces
```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); // Current sampling
```
## Resources
- Stack: <= 256 B
- Worst-case timing: 50 us per ISR
- Static RAM: 64 B per actuator
## Mapping to requirements
| Requirement | How covered |
|-------------|-------------|
| SWE-006 | actuator_release for both actuators in parallel |
| SWE-013 | actuator_isr_1khz |
| SWE-014 | overcurrent detector in ISR |
| SWE-015 | peak-current tracking + linear clamping-force estimate |
""").strip(),
},
{
"id": "SWA-004", "asil": "B",
"links": ["SWE-022", "SWE-023"],
"title": "Wheel Speed Plausibilisation",
"text": textwrap.dedent("""
## Responsibility
Conditioning and plausibilisation of the four wheel-speed signals.
Detects standstill and cross-checks the wheels.
## Provided interfaces
```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("""
## Responsibility
Low-pass filtering of the raw inclinometer signal for hill-hold
evaluation.
## Provided interfaces
```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("""
## Responsibility
Software debouncing of the EPB switch. Provides a stable apply /
release signal to the apply controller. Implemented in
`src/switch_debouncer.c`.
## Provided interfaces
```c
Status switch_init(void);
void switch_step_10ms(SwitchRaw raw);
SwitchState switch_get_state(void);
```
## Mapping to requirements
| Requirement | How covered |
|-------------|-------------|
| SWE-025 | 50 ms debounce logic |
""").strip(),
},
{
"id": "SWA-007", "asil": "QM",
"links": ["SWE-020", "SWE-021"],
"title": "Display Manager",
"text": textwrap.dedent("""
## Responsibility
Drives the LED on the EPB switch and the CAN status frame to the
instrument cluster. Receives status from the apply controller.
## Provided interfaces
```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("""
## Responsibility
UDS diagnostics per ISO 14229: ReadDTC, ReadDataByIdentifier,
RoutineControl.
## Provided interfaces
```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("""
## Responsibility
Service mode for the workshop. Activated via UDS RoutineControl
0x31, routine ID 0x0301. Drives the actuators into maintenance
position.
""").strip(),
},
{
"id": "SWA-010", "asil": "QM",
"links": ["SWE-018", "SWE-019"],
"title": "Logger",
"text": textwrap.dedent("""
## Responsibility
Logging for development and service. Ring buffer in RAM (1 KB)
plus persistence in EEPROM on critical events.
## Provided interfaces
```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(link) for link 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(SG_GOALS, REPO / "safety" / "sg")
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(SG_GOALS) + len(SYS_REQS) + len(SWE_REQS) + len(SA_ELEMENTS) + len(SWA_ELEMENTS)
))
if __name__ == "__main__":
main()