|
Safe API Framework 0.1.0 build 384e6ae
Layered API framework for safety-related applications (ERTMS RBC reference targeting CENELEC EN 50128 SIL 4)
|
Safe-State is a handler registration system for critical events. Applications register handlers for each severity level (DEGRADED, SAFE, REBOOT), then call RTE_SAFESTATE() or RTE_REBOOT() macros to trigger transitions. The framework invokes the registered handler with context (file, line, message) and guarantees control never returns for SAFE/REBOOT levels.
No dynamic allocation; handler storage is fixed (3 slots, one per level).
DEGRADED (0) - Can return to caller └─ Use for: single component failure, reduced redundancy └─ Example: backup channel failed, primary still working └─ Behavior: handler runs, can return, system continues SAFE (1) - Cannot return └─ Use for: critical fail-safe state, critical functions disabled └─ Example: both channels down, or voting disagreement └─ Behavior: handler runs, MUST NOT return, infinite loop if it does REBOOT (2) - Cannot return └─ Use for: emergency restart required └─ Example: unrecoverable software error, corruption detected └─ Behavior: handler runs, MUST NOT return, infinite loop if it does
Registers handler for one level. Replaces any previous handler for that level. Called at startup before any safe-state transitions are expected.
Invokes registered handler for level, passing context. For SAFE/REBOOT, never returns (even if handler returns, framework enters infinite loop).
Normally called via macros, not directly.
Macros automatically capture FILE and LINE.
Handler receives full context about what triggered the transition. For DEGRADED: can return normally. For SAFE/REBOOT: must not return; if it does, framework prevents it.
RTE_SAFESTATE_REASON_UNSPECIFIED (0) - No specific reason RTE_SAFESTATE_REASON_ASSERT_FAILED (1) - RTE_ASSERT() condition false RTE_SAFESTATE_REASON_APPLICATION_BASE - 4096, start of app-specific codes
Applications define their own reason codes starting at 4096:
Reason codes appear in handler and handler can log/persist them for diagnostics.
Application calls RTE_SAFESTATE(level, reason)
│
├─ Captures __FILE__, __LINE__
└─ Calls rte_safestate_enter(level, reason, file, line, NULL)
│
├─ Retrieves registered handler for level
├─ If handler != NULL: invokes it with context
└─ Handler returns (DEGRADED only) or doesn't (SAFE/REBOOT)
If DEGRADED:
└─ Handler returns normally
└─ rte_safestate_enter() returns to caller
└─ Application continues execution
If SAFE or REBOOT:
├─ If handler returns:
│ └─ Framework enters infinite loop (infinite while(1))
└─ Handler never returns:
└─ Caller never regains control
Fixed storage for 3 handlers (one per level). No dynamic allocation. Handlers must be registered before use (typically at startup).
Level 0 (DEGRADED) ──> Handler A Level 1 (SAFE) ──> Handler B Level 2 (REBOOT) ──> Handler C
RTE_ASSERT() is a macro that:
Unlike standard assert(), RTE_ASSERT() is always active, never disabled. This is intentional for safety-critical systems where assertions must catch bugs in production.
Rule 2.1 │ ✓ │ No unreachable code Rule 5.1 │ ✓ │ External identifiers unique Rule 7.2 │ ✓ │ Correct signedness Rule 8.4 │ ✓ │ Consistent declarations Rule 14.4 │ ✓ │ Boolean operators correct Rule 17.1 │ ✓ │ Pointer validity checked Rule 20.6 │ ✓ │ No malloc/free
No dynamic allocation; no undefined behavior on entry/exit.
Watchdog timeouts can trigger safe-state via handler:
RTE_REBOOT() enters REBOOT level; handler can call rte_reboot_request() to actually restart the system.