#!/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()