Safe API Framework
Layered API framework for safety-related applications (ERTMS RBC reference targeting CENELEC EN 50128 SIL 4)
Loading...
Searching...
No Matches
sapi_dual_channel.c File Reference

"DualChannel" layer of ADR-020 - see sapi_dual_channel.h. More...

Include dependency graph for sapi_dual_channel.c:

Go to the source code of this file.

Data Structures

struct  dual_poll_result_t
 Result of one dual_channel_poll_link_once() attempt. More...

Macros

#define SAPI_DUAL_CHANNEL_STALL_POLL_LIMIT   32U
 Cap on consecutive sapi_dual_channel_send() ACK-wait polls that may complete without sapi_timer_now() showing any measurable progress, before that link's wait loop gives up on this round - see that loop's own comment for why more than one such iteration is legitimate but an unbounded number is not.

Functions

static sapi_dual_channel_status_t dual_channel_compute_status (const sapi_dual_channel_t *channel)
static void dual_channel_update_status (sapi_dual_channel_t *channel)
static sapi_status_t dual_channel_poll_link_once (sapi_dual_channel_t *channel, uint32_t link_index, sapi_duration_ms_t timeout_ms, dual_poll_result_t *out_result)
 One receive attempt on one link, dispatched by frame kind: DATA is auto-ACKed and staged for sapi_dual_channel_receive(); STATE is staged for sapi_dual_channel_receive_state_frame(); ACK is reported back to the caller (sapi_dual_channel_send()'s own wait loop) via *out_result, not staged anywhere.
sapi_status_t sapi_dual_channel_init (sapi_dual_channel_t *channel, const sapi_dual_channel_config_t *config)
 Initializes a sapi_dual_channel_t: initializes every configured redundant link (sapi_dual_msgchannel_init()) and starts sapi_dual_channel_get_status() at SAPI_DUAL_CHANNEL_STATUS_DOWN (no traffic has been sent/received yet).
sapi_status_t sapi_dual_channel_send (sapi_dual_channel_t *channel, const uint8_t *payload, uint8_t payload_size, uint32_t *out_ack_link_count)
 Sends payload as a DATA frame on every configured redundant link - never gated by any negotiated state (ADR-020 section 2: the real payload traffic itself is the liveness check). For each link, waits up to config->ack_timeout_ms for that link's own ACK (matched by sequence number, not just "an ACK arrived") before moving on; a DATA or STATE frame received from the peer while waiting is still auto-ACKed/staged as a side effect, not dropped.
sapi_status_t sapi_dual_channel_receive (sapi_dual_channel_t *channel, uint8_t *out_payload, uint8_t max_size, sapi_duration_ms_t timeout_ms, uint8_t *out_size)
 Returns the most recently staged inbound DATA frame, actively polling the configured links (each auto-ACked on arrival - see sapi_dual_channel_send()'s own doc) if none was already staged from a previous sapi_dual_channel_send() call's own incidental polling.
sapi_status_t sapi_dual_channel_send_heartbeat (sapi_dual_channel_t *channel, uint32_t *out_ack_link_count)
 Sends a sapi_dual_state_frame_t (sapi_dual_frames.h) on every configured redundant link - fire-and-forget, no ACK wait (unlike sapi_dual_channel_send()'s DATA frames), matching the periodic-beacon nature of state negotiation. Intended to be called by a sapi_dual_negotiator_t, not directly by application code - see ADR-020 section 3.
sapi_status_t sapi_dual_channel_send_state_frame (sapi_dual_channel_t *channel, sapi_dual_state_t state, bool channel_degraded, uint64_t timestamp_ms)
sapi_status_t sapi_dual_channel_receive_state_frame (sapi_dual_channel_t *channel, sapi_duration_ms_t timeout_ms, sapi_dual_state_frame_t *out_frame)
 Returns the most recently staged inbound STATE frame, actively polling the configured links if none was already staged. Intended to be called by a sapi_dual_negotiator_t - see ADR-020 section 3.
sapi_dual_channel_status_t sapi_dual_channel_get_status (const sapi_dual_channel_t *channel)
 Returns the aggregate connection status across every configured redundant link, as of the most recent sapi_dual_channel_send() call (ADR-020 section 2). SAPI_DUAL_CHANNEL_STATUS_DOWN before the first send.
bool sapi_dual_channel_is_link_up (const sapi_dual_channel_t *channel, uint32_t link_index)
 Returns whether one specific configured link is currently considered up, as of the most recent sapi_dual_channel_send() call - for diagnostics/logging (e.g. which specific redundant path is the one that's down), not a safety-decision input on its own (see sapi_dual_channel_get_status() for the aggregate).

Detailed Description

"DualChannel" layer of ADR-020 - see sapi_dual_channel.h.

Definition in file sapi_dual_channel.c.

Macro Definition Documentation

◆ SAPI_DUAL_CHANNEL_STALL_POLL_LIMIT

#define SAPI_DUAL_CHANNEL_STALL_POLL_LIMIT   32U

Cap on consecutive sapi_dual_channel_send() ACK-wait polls that may complete without sapi_timer_now() showing any measurable progress, before that link's wait loop gives up on this round - see that loop's own comment for why more than one such iteration is legitimate but an unbounded number is not.

Definition at line 17 of file sapi_dual_channel.c.

Function Documentation

◆ dual_channel_compute_status()

sapi_dual_channel_status_t dual_channel_compute_status ( const sapi_dual_channel_t * channel)
static

Definition at line 27 of file sapi_dual_channel.c.

◆ dual_channel_update_status()

void dual_channel_update_status ( sapi_dual_channel_t * channel)
static

Definition at line 51 of file sapi_dual_channel.c.

◆ dual_channel_poll_link_once()

sapi_status_t dual_channel_poll_link_once ( sapi_dual_channel_t * channel,
uint32_t link_index,
sapi_duration_ms_t timeout_ms,
dual_poll_result_t * out_result )
static

One receive attempt on one link, dispatched by frame kind: DATA is auto-ACKed and staged for sapi_dual_channel_receive(); STATE is staged for sapi_dual_channel_receive_state_frame(); ACK is reported back to the caller (sapi_dual_channel_send()'s own wait loop) via *out_result, not staged anywhere.

Definition at line 74 of file sapi_dual_channel.c.