Safe API Framework
Layered API framework for safety-related applications (ERTMS RBC reference targeting CENELEC EN 50128 SIL 4)
Loading...
Searching...
No Matches
Safe-State Transitions and Checked Assertions

Layer-agnostic fault-reaction facility (ADR-004). More...

Files

file  src/utils/safestate/sapi_safestate.c
 Implementation of the safe-state transition facility (ADR-004).

Macros

#define SAPI_SAFESTATE_REASON_UNSPECIFIED   ((sapi_safestate_reason_t)0U)
#define SAPI_SAFESTATE_REASON_ASSERT_FAILED   ((sapi_safestate_reason_t)1U)
#define SAPI_SAFESTATE_REASON_CHECKPOINT_TIMEOUT   ((sapi_safestate_reason_t)2U)
#define SAPI_SAFESTATE_REASON_APPLICATION_BASE   ((sapi_safestate_reason_t)4096U)
#define SAPI_ASSERT(cond)
 Checked assertion. Always active in every build configuration, including production (ADR-004 section 2.5) - unlike standard assert(), which CLAUDE.md prohibits in production paths. On failure, enters SAPI_SAFESTATE_LEVEL_SAFE with reason SAPI_SAFESTATE_REASON_ASSERT_FAILED.
#define SAPI_SAFESTATE(level, reason)
 Explicitly enters the given safe-state level with a reason code, capturing the call site automatically.
#define SAPI_REBOOT(reason)
 Enters SAPI_SAFESTATE_LEVEL_REBOOT with the given reason code. Equivalent to SAPI_SAFESTATE(SAPI_SAFESTATE_LEVEL_REBOOT, reason).

Typedefs

typedef uint16_t sapi_safestate_reason_t
 Diagnostic reason code accompanying a safe-state transition.
typedef void(*) sapi_safestate_handler_t(sapi_safestate_level_t level, sapi_safestate_reason_t reason, const char *file, int32_t line, const char *message)
 Application-supplied reaction for one safe-state level.

Enumerations

enum  sapi_safestate_level_t { SAPI_SAFESTATE_LEVEL_DEGRADED = 0 , SAPI_SAFESTATE_LEVEL_SAFE = 1 , SAPI_SAFESTATE_LEVEL_REBOOT = 2 }
 Safe-state severity levels (ADR-004 section 2.1). More...

Functions

sapi_status_t sapi_safestate_register_handler (sapi_safestate_level_t level, sapi_safestate_handler_t handler)
 Registers the reaction handler for one safe-state level. This is how an integrator supplies their own implementation of "what happens when this level is entered" (ADR-004 section 2.2).
void sapi_safestate_enter (sapi_safestate_level_t level, sapi_safestate_reason_t reason, const char *file, int32_t line, const char *message)
 Enters a safe-state level: invokes the registered handler (if any), then, for SAPI_SAFESTATE_LEVEL_SAFE and SAPI_SAFESTATE_LEVEL_REBOOT, guarantees the call never returns (REQ-COMMON-SAFESTATE-002) even if no handler was registered or the handler itself returns.

Detailed Description

Layer-agnostic fault-reaction facility (ADR-004).

Macro Definition Documentation

◆ SAPI_SAFESTATE_REASON_UNSPECIFIED

#define SAPI_SAFESTATE_REASON_UNSPECIFIED   ((sapi_safestate_reason_t)0U)

Reserved framework reason codes (0-4095).

Definition at line 66 of file sapi_safestate.h.

◆ SAPI_SAFESTATE_REASON_ASSERT_FAILED

#define SAPI_SAFESTATE_REASON_ASSERT_FAILED   ((sapi_safestate_reason_t)1U)

Set by SAPI_ASSERT() when its condition evaluates to false.

Definition at line 68 of file sapi_safestate.h.

◆ SAPI_SAFESTATE_REASON_CHECKPOINT_TIMEOUT

#define SAPI_SAFESTATE_REASON_CHECKPOINT_TIMEOUT   ((sapi_safestate_reason_t)2U)

Set by sapi_channel_checkpoint() (ADR-017) when fewer than expected_node_count peers confirm a checkpoint within max_delay_ms.

Definition at line 71 of file sapi_safestate.h.

◆ SAPI_SAFESTATE_REASON_APPLICATION_BASE

#define SAPI_SAFESTATE_REASON_APPLICATION_BASE   ((sapi_safestate_reason_t)4096U)

First reason code value applications are free to define their own meaning for.

Definition at line 73 of file sapi_safestate.h.

◆ SAPI_ASSERT

#define SAPI_ASSERT ( cond)
Value:
do \
{ \
if (!(cond)) \
{ \
sapi_safestate_enter(SAPI_SAFESTATE_LEVEL_SAFE, \
__FILE__, (int32_t)__LINE__, #cond); \
} \
} while (0)
#define SAPI_SAFESTATE_REASON_ASSERT_FAILED
@ SAPI_SAFESTATE_LEVEL_SAFE

Checked assertion. Always active in every build configuration, including production (ADR-004 section 2.5) - unlike standard assert(), which CLAUDE.md prohibits in production paths. On failure, enters SAPI_SAFESTATE_LEVEL_SAFE with reason SAPI_SAFESTATE_REASON_ASSERT_FAILED.

Definition at line 145 of file sapi_safestate.h.

◆ SAPI_SAFESTATE

#define SAPI_SAFESTATE ( level,
reason )
Value:
sapi_safestate_enter((level), (reason), __FILE__, (int32_t)__LINE__, NULL)
void sapi_safestate_enter(sapi_safestate_level_t level, sapi_safestate_reason_t reason, const char *file, int32_t line, const char *message)
Enters a safe-state level: invokes the registered handler (if any), then, for SAPI_SAFESTATE_LEVEL_SA...

Explicitly enters the given safe-state level with a reason code, capturing the call site automatically.

Definition at line 161 of file sapi_safestate.h.

◆ SAPI_REBOOT

#define SAPI_REBOOT ( reason)
Value:
sapi_safestate_enter(SAPI_SAFESTATE_LEVEL_REBOOT, (reason), __FILE__, (int32_t)__LINE__, NULL)
@ SAPI_SAFESTATE_LEVEL_REBOOT

Enters SAPI_SAFESTATE_LEVEL_REBOOT with the given reason code. Equivalent to SAPI_SAFESTATE(SAPI_SAFESTATE_LEVEL_REBOOT, reason).

Definition at line 169 of file sapi_safestate.h.

Typedef Documentation

◆ sapi_safestate_reason_t

typedef uint16_t sapi_safestate_reason_t

Diagnostic reason code accompanying a safe-state transition.

Values 0-4095 are reserved for the framework itself (see the SAPI_SAFESTATE_REASON_* constants below). Application/RBC-specific reason codes shall use 4096 and above.

Definition at line 63 of file sapi_safestate.h.

◆ sapi_safestate_handler_t

typedef void(*) sapi_safestate_handler_t(sapi_safestate_level_t level, sapi_safestate_reason_t reason, const char *file, int32_t line, const char *message)

Application-supplied reaction for one safe-state level.

Parameters
levelThe level being entered (matches the slot this handler was registered for).
reasonDiagnostic reason code.
fileSource file of the call site (from FILE), may be NULL.
lineSource line of the call site (from LINE).
messageOptional human-readable detail (e.g. the failed expression text from SAPI_ASSERT), may be NULL.
Note
For SAPI_SAFESTATE_LEVEL_SAFE and SAPI_SAFESTATE_LEVEL_REBOOT this handler shall not return. If it does anyway, sapi_safestate_enter() falls back to a defensive infinite loop (REQ-COMMON-SAFESTATE-002) rather than resuming the caller.

Definition at line 91 of file sapi_safestate.h.

Enumeration Type Documentation

◆ sapi_safestate_level_t

Safe-state severity levels (ADR-004 section 2.1).

Enumerator
SAPI_SAFESTATE_LEVEL_DEGRADED 

Continue operating with reduced functionality. The only level for which sapi_safestate_enter() is permitted to return to the caller.

SAPI_SAFESTATE_LEVEL_SAFE 

Fail-safe restrictive state (e.g. withdraw movement authorities). sapi_safestate_enter() does not return for this level.

SAPI_SAFESTATE_LEVEL_REBOOT 

SAFE is judged insufficient; a controlled restart is required. sapi_safestate_enter() does not return for this level.

Definition at line 41 of file sapi_safestate.h.

Function Documentation

◆ sapi_safestate_register_handler()

sapi_status_t sapi_safestate_register_handler ( sapi_safestate_level_t level,
sapi_safestate_handler_t handler )

Registers the reaction handler for one safe-state level. This is how an integrator supplies their own implementation of "what happens when this level is entered" (ADR-004 section 2.2).

Parameters
levelThe level to register a handler for.
handlerHandler to invoke on entry to this level. Must not be NULL.
Returns
SAPI_STATUS_INVALID_PARAM if handler is NULL or level is not a valid sapi_safestate_level_t value; SAPI_STATUS_OK otherwise. Registering again for the same level replaces the previous handler.

REQ-COMMON-SAFESTATE-010

Global functions

Definition at line 31 of file sapi_safestate.c.

◆ sapi_safestate_enter()

void sapi_safestate_enter ( sapi_safestate_level_t level,
sapi_safestate_reason_t reason,
const char * file,
int32_t line,
const char * message )

Enters a safe-state level: invokes the registered handler (if any), then, for SAPI_SAFESTATE_LEVEL_SAFE and SAPI_SAFESTATE_LEVEL_REBOOT, guarantees the call never returns (REQ-COMMON-SAFESTATE-002) even if no handler was registered or the handler itself returns.

Parameters
levelLevel to enter.
reasonDiagnostic reason code.
fileCall site file (typically FILE), may be NULL.
lineCall site line (typically LINE).
messageOptional human-readable detail, may be NULL.
Note
Prefer the SAPI_ASSERT / SAPI_SAFESTATE / SAPI_REBOOT macros over calling this directly, so FILE/__LINE__ are captured correctly.

REQ-COMMON-SAFESTATE-011

Definition at line 52 of file sapi_safestate.c.