|
Safe Communication Framework 0.1.0 build feea4f9
ERTMS/ETCS safe communication (Subset-037 EuroRadio, Subset-098 RBC/RBC), CENELEC EN 50128 SIL 4 oriented
|
Safe Application Intermediate (SAI) sub-layer (Subset-098 v4.0.0 §5.4). More...
#include <stdbool.h>#include <stddef.h>#include <stdint.h>#include "safecomm/status.h"#include "safecomm/saf/saf.h"Go to the source code of this file.
Data Structures | |
| struct | safecomm_sai_config_t |
| Static configuration for one SAI connection. More... | |
| struct | safecomm_sai_conn_t |
| SAI connection object, layered over an already-initialised safecomm_saf_conn_t. Caller-allocated, zero-initialised; fields are not part of the API contract. More... | |
Functions | |
| safecomm_status_t | safecomm_sai_init (safecomm_sai_conn_t *conn, safecomm_saf_conn_t *saf, const safecomm_sai_config_t *cfg) |
| Initialise a SAI connection object over an already-initialised SaF connection. | |
| safecomm_status_t | safecomm_sai_start (safecomm_sai_conn_t *conn) |
Run the EC initialisation exchange (§5.4.9.3): send our ExecutionCycleStart, wait for the peer's, and compute the EC ratio. saf must already be in DATA (its own AU1-3/AR handshake done). | |
| safecomm_status_t | safecomm_sai_send (safecomm_sai_conn_t *conn, const uint8_t *pdu, size_t pdu_len) |
| Wrap one user PDU in a SAI header (message type, sequence number, our EC counter) and send it through the underlying SaF connection. | |
| safecomm_status_t | safecomm_sai_recv (safecomm_sai_conn_t *conn, uint8_t *out, size_t out_cap, size_t *out_len) |
| Receive, unwrap and check one SAI-protected PDU. | |
| void | safecomm_sai_tick (safecomm_sai_conn_t *conn) |
Advance our own EC by one: call this once per cfg.ec_period_ms elapsed on the caller's clock. Updates the expected-EC estimate and the freshness state (§5.4.9.4.4-7) even if no message arrived in this cycle (using the last one received). | |
Safe Application Intermediate (SAI) sub-layer (Subset-098 v4.0.0 §5.4).
Sits functionally above the Safety Layer (safecomm_saf_conn_t): it wraps every user PDU in a SAI header before handing it to safecomm_saf_send, and unwraps/checks it on safecomm_saf_recv. It supplies the delay/re-ordering/repetition defence that the Safety Layer's own Sa-DATA PDU does not carry (Subset-037-2 Table 12 has no sequence field at all):
Subset-098 offers two mutually-exclusive delay defences: Triple Time Stamping (§5.4.8, a 5-message clock-offset estimation exchange) or the EC counter (§5.4.9, simpler: each side declares a fixed cycle period and a counter, and the peer's freshness is judged by how many of its own cycles its last received counter lags the receiver's running estimate). Only EC is implemented here — the spec explicitly allows the choice per project (§4.3.1.1.7-8), and TTS is a materially larger undertaking (its own multi-message clock-offset protocol with maximum/minimum offset bookkeeping). See docs/safety/SUBSET_MAPPING.md for what that leaves open.
Also not implemented from §5.4.9: the "further procedures" correction for long-term clock/period drift (§5.4.9.5) and the separate "procedure for detection of transmission delay" heartbeat (§5.4.9.6). The core freshness check (§5.4.9.4, the Delta/state computation) is implemented and is what actually detects a stale or delayed peer.
This module does not open a transport itself; it drives an already-initialised safecomm_saf_conn_t (typically already in DATA, i.e. past its own AU1-3/AR handshake).
Definition in file sai.h.
| safecomm_status_t safecomm_sai_init | ( | safecomm_sai_conn_t * | conn, |
| safecomm_saf_conn_t * | saf, | ||
| const safecomm_sai_config_t * | cfg ) |
Initialise a SAI connection object over an already-initialised SaF connection.
| conn | caller-allocated, will be fully overwritten. Non-NULL. |
| saf | the underlying SaF connection (kept by reference; not copied, not owned). Non-NULL. |
| cfg | static configuration, copied. Non-NULL. |
| safecomm_status_t safecomm_sai_start | ( | safecomm_sai_conn_t * | conn | ) |
Run the EC initialisation exchange (§5.4.9.3): send our ExecutionCycleStart, wait for the peer's, and compute the EC ratio. saf must already be in DATA (its own AU1-3/AR handshake done).
| conn | an initialised SAI connection. Non-NULL. |
| safecomm_status_t safecomm_sai_send | ( | safecomm_sai_conn_t * | conn, |
| const uint8_t * | pdu, | ||
| size_t | pdu_len ) |
Wrap one user PDU in a SAI header (message type, sequence number, our EC counter) and send it through the underlying SaF connection.
| conn | a started SAI connection. Non-NULL. |
| pdu | user bytes. Non-NULL when pdu_len > 0. |
| pdu_len | length of pdu. |
| safecomm_status_t safecomm_sai_recv | ( | safecomm_sai_conn_t * | conn, |
| uint8_t * | out, | ||
| size_t | out_cap, | ||
| size_t * | out_len ) |
Receive, unwrap and check one SAI-protected PDU.
| conn | a started SAI connection. Non-NULL. |
| out | destination for the user bytes. Non-NULL. |
| out_cap | capacity of out. |
| out_len | receives the user-byte count. Non-NULL. |
| void safecomm_sai_tick | ( | safecomm_sai_conn_t * | conn | ) |
Advance our own EC by one: call this once per cfg.ec_period_ms elapsed on the caller's clock. Updates the expected-EC estimate and the freshness state (§5.4.9.4.4-7) even if no message arrived in this cycle (using the last one received).
| conn | a started SAI connection. Non-NULL. |