|
Safe API Framework 0.1.0 build 384e6ae
Layered API framework for safety-related applications (ERTMS RBC reference targeting CENELEC EN 50128 SIL 4)
|
Which of two redundant instances is active, and how well-backed is the standby one (ADR-020). More...
Files | |
| file | src/redundancy/dual/rte_dual_channel.c |
| "DualChannel" layer of ADR-020 - see rte_dual_channel.h. | |
| file | src/redundancy/dual/rte_dual_msgchannel.c |
| "Channel" layer of ADR-020 - see rte_dual_msgchannel.h. | |
| file | src/redundancy/dual/rte_dual_negotiator.c |
| Dual state negotiator of ADR-020 - see rte_dual_negotiator.h. | |
| file | src/redundancy/dual/rte_dual_types.c |
| Diagnostics-only string rendering for the rte_dual module's shared enums (ADR-020). | |
Data Structures | |
| struct | rte_dual_channel_t |
| One rte_dual_channel_t instance's state. Caller-owned storage; every field is private - reach it only through the functions below. More... | |
| struct | rte_dual_channel_config_t |
| Configuration for rte_dual_channel_init(). More... | |
| struct | rte_dual_frame_header_t |
| Common 4-byte header prefixing every Layer-2 frame; kept a fixed 4 bytes (not just 1) so the fields that follow in rte_dual_ack_frame_t/rte_dual_state_frame_t stay naturally aligned. More... | |
| struct | rte_dual_ack_frame_t |
| RTE_DUAL_FRAME_KIND_ACK payload. More... | |
| struct | rte_dual_state_frame_t |
| RTE_DUAL_FRAME_KIND_STATE payload - rte_dual_negotiator_t's own periodic beacon. More... | |
| struct | rte_dual_heartbeat_frame_t |
| RTE_DUAL_FRAME_KIND_HEARTBEAT payload - connection maintenance heartbeat. More... | |
| struct | rte_dual_msgchannel_t |
| One rte_dual_msgchannel_t instance's state. Caller-owned storage (REQ-DUAL-MSGCHANNEL-001); opaque in practice, exposed here (not via RTE_DECLARE_STORAGE) only because its size is already small and fixed - callers must still treat every field as private and only reach it through the functions below. More... | |
| struct | rte_dual_msgchannel_config_t |
| Configuration for rte_dual_msgchannel_init(). More... | |
| struct | rte_dual_negotiator_t |
| One rte_dual_negotiator_t instance's state. Caller-owned storage; every field is private - reach it only through the functions below. More... | |
| struct | rte_dual_negotiator_config_t |
| Configuration for rte_dual_negotiator_init(). More... | |
Macros | |
| #define | RTE_DUAL_CHANNEL_MAX_LINKS 4U |
| Maximum number of redundant links one rte_dual_channel_t may be configured with. Fixed, not dynamic (REQ-OAL-COMMON-010). | |
| #define | RTE_DUAL_CHANNEL_MAX_PAYLOAD (RTE_DUAL_MSGCHANNEL_MAX_PAYLOAD - 4U) |
| Max application payload bytes usable via rte_dual_channel_send()/_receive() - Layer-1's own RTE_DUAL_MSGCHANNEL_MAX_PAYLOAD minus this layer's 4-byte rte_dual_frame_header_t. | |
| #define | RTE_DUAL_MSGCHANNEL_MAX_PAYLOAD 248U |
| Max payload bytes usable via rte_dual_msgchannel_send()/ _receive() - bounded by rte_vital_message_t's own fixed 248-byte payload field (rte_checksum.h). | |
Typedefs | |
| typedef void(*) | rte_dual_channel_status_callback_t(rte_dual_channel_status_t new_status, rte_dual_channel_status_t old_status, void *user_ctx) |
| Optional callback invoked whenever rte_dual_channel_get_status()'s value changes (ADR-020 section 2's "indicate to the user via
callback if registered" requirement). Called synchronously from inside rte_dual_channel_send() (the only place aggregate status is recomputed) - keep this fast; it is on the same call path as the send it was triggered by. | |
| typedef void(*) | rte_dual_negotiator_state_change_callback_t(rte_dual_state_t new_own_state, rte_dual_state_t old_own_state, rte_dual_state_t new_peer_state, rte_dual_state_t old_peer_state, void *user_ctx) |
| Optional callback invoked whenever either the own or the peer rte_dual_state_t changes, from inside rte_dual_negotiator_execute(). | |
Enumerations | |
| enum | rte_dual_frame_kind_t { RTE_DUAL_FRAME_KIND_DATA = 0 , RTE_DUAL_FRAME_KIND_ACK = 1 , RTE_DUAL_FRAME_KIND_STATE = 2 , RTE_DUAL_FRAME_KIND_HEARTBEAT = 3 } |
| Which kind of Layer-2 frame a given Layer-1 payload holds. Stored as the first byte of every rte_dual_channel_t frame so DATA, ACK, and STATE traffic sharing the same redundant links can never be misinterpreted as each other. More... | |
| enum | rte_dual_state_t { RTE_DUAL_STATE_IDLE = 0 , RTE_DUAL_STATE_UNKNOWN = 1 , RTE_DUAL_STATE_ONLINE = 2 , RTE_DUAL_STATE_HOTSTANDBY = 3 , RTE_DUAL_STATE_COLDSTANDBY = 4 } |
| State of one instance in a dual (two-redundant-instance) relationship, as decided by rte_dual_negotiator_t (ADR-020 section 3). Both this instance's own state and its last-known view of the peer's state use this same enum - see rte_dual_negotiator_get_own_state()/_get_peer_state(). More... | |
| enum | rte_dual_channel_status_t { RTE_DUAL_CHANNEL_STATUS_DOWN = 0 , RTE_DUAL_CHANNEL_STATUS_DEGRADED = 1 , RTE_DUAL_CHANNEL_STATUS_FULL = 2 } |
| Aggregate connection status of a rte_dual_channel_t across all of its configured redundant links (ADR-020 section 2). Independent of rte_dual_state_t: losing some (not all) of the redundant links degrades this status without by itself forcing any rte_dual_state_t transition - only total loss (DOWN) is a negotiator-relevant liveness event. More... | |
Functions | |
| rte_status_t | rte_dual_channel_init (rte_dual_channel_t *channel, const rte_dual_channel_config_t *config) |
| Initializes a rte_dual_channel_t: initializes every configured redundant link (rte_dual_msgchannel_init()) and starts rte_dual_channel_get_status() at RTE_DUAL_CHANNEL_STATUS_DOWN (no traffic has been sent/received yet). | |
| rte_status_t | rte_dual_channel_send (rte_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. | |
| rte_status_t | rte_dual_channel_receive (rte_dual_channel_t *channel, uint8_t *out_payload, uint8_t max_size, rte_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 rte_dual_channel_send()'s own doc) if none was already staged from a previous rte_dual_channel_send() call's own incidental polling. | |
| rte_status_t | rte_dual_channel_send_heartbeat (rte_dual_channel_t *channel, uint32_t *out_ack_count) |
| Transmits a connection maintenance heartbeat frame across every configured link and waits up to ack_timeout_ms for an ACK on each. | |
| rte_status_t | rte_dual_channel_send_state_frame (rte_dual_channel_t *channel, rte_dual_state_t state, bool channel_degraded, uint64_t timestamp_ms) |
| Sends a rte_dual_state_frame_t (rte_dual_frames.h) on every configured redundant link - fire-and-forget, no ACK wait (unlike rte_dual_channel_send()'s DATA frames), matching the periodic-beacon nature of state negotiation. Intended to be called by a rte_dual_negotiator_t, not directly by application code - see ADR-020 section 3. | |
| rte_status_t | rte_dual_channel_receive_state_frame (rte_dual_channel_t *channel, rte_duration_ms_t timeout_ms, rte_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 rte_dual_negotiator_t - see ADR-020 section 3. | |
| rte_dual_channel_status_t | rte_dual_channel_get_status (const rte_dual_channel_t *channel) |
| Returns the aggregate connection status across every configured redundant link, as of the most recent rte_dual_channel_send() call (ADR-020 section 2). RTE_DUAL_CHANNEL_STATUS_DOWN before the first send. | |
| bool | rte_dual_channel_is_link_up (const rte_dual_channel_t *channel, uint32_t link_index) |
| Returns whether one specific configured link is currently considered up, as of the most recent rte_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 rte_dual_channel_get_status() for the aggregate). | |
| rte_status_t | rte_dual_channel_set_resync_on_sequence_error (rte_dual_channel_t *channel, bool enable) |
| rte_status_t | rte_dual_msgchannel_set_resync_on_sequence_error (rte_dual_msgchannel_t *channel, bool enable) |
| Turns sequence resynchronisation on or off (default off after init). | |
| rte_status_t | rte_dual_msgchannel_init (rte_dual_msgchannel_t *channel, const rte_dual_msgchannel_config_t *config) |
| Initializes a rte_dual_msgchannel_t: starts both sequence counters at 0. | |
| rte_status_t | rte_dual_msgchannel_send (rte_dual_msgchannel_t *channel, const uint8_t *payload, uint8_t payload_size, rte_duration_ms_t timeout_ms, uint32_t *out_sequence) |
| Wraps payload in a rte_vital_message_t (this channel's own sender_id and next sequence_number) and sends it over config->link, blocking at most timeout_ms. | |
| rte_status_t | rte_dual_msgchannel_receive (rte_dual_msgchannel_t *channel, uint8_t *out_payload, uint8_t payload_max_size, rte_duration_ms_t timeout_ms, uint8_t *out_payload_size, uint32_t *out_sequence) |
| Receives one frame over config->link, blocking at most timeout_ms, verifies its CRC-64 and sequence continuity (rte_checksum_vital_message_verify() against channel->expected_sequence) and its sender_id against config->expected_peer_id, and extracts the payload. | |
| rte_status_t | rte_dual_msgchannel_reset_sequence (rte_dual_msgchannel_t *channel) |
| Resets both sequence counters to 0. Intended to be called by the caller (typically rte_dual_channel_t) exactly once, immediately after config->link has been freshly (re)established with the peer - the same idea as a mechanism RBC_GP once had and has since removed (2026-10-04): a cycle-counter reset after a peer-link reconnect. A fresh link needs a fresh, mutually agreed starting sequence rather than fighting over whatever counters were left over from before the disconnect. | |
| rte_status_t | rte_dual_negotiator_init (rte_dual_negotiator_t *negotiator, const rte_dual_negotiator_config_t *config) |
| Initializes a rte_dual_negotiator_t. Captures this instance's own startup timestamp once (rte_timer_now(), degrading to 0 if no timer OSAdapter is registered - same best-effort posture as rte_log_write_event()'s Timestamp field) for use on every beacon this negotiator ever sends - see rte_dual_state_frame_t's own doc on why this must stay fixed - UNLESS config->resume_own_state/resume_own_startup_timestamp_ms opt into resuming a prior identity instead (see their own doc). peer_state always starts at RTE_DUAL_STATE_IDLE; own_state does too unless a resume was requested. | |
| rte_status_t | rte_dual_negotiator_execute (rte_dual_negotiator_t *negotiator, rte_duration_ms_t receive_timeout_ms) |
| Drives one round of state negotiation: refreshes own_channel_degraded from the attached channel's current rte_dual_channel_get_status(), sends this instance's own beacon, drains and processes every currently-pending inbound STATE frame, then recomputes both own and peer rte_dual_state_t: | |
| rte_dual_state_t | rte_dual_negotiator_get_own_state (const rte_dual_negotiator_t *negotiator) |
| Returns this instance's own current rte_dual_state_t. | |
| rte_dual_state_t | rte_dual_negotiator_get_peer_state (const rte_dual_negotiator_t *negotiator) |
| Returns this instance's last-known view of the peer's rte_dual_state_t. | |
| uint64_t | rte_dual_negotiator_get_own_startup_timestamp_ms (const rte_dual_negotiator_t *negotiator) |
| Returns this instance's own startup timestamp (captured at rte_dual_negotiator_init() time, or resumed from config - see rte_dual_negotiator_config_t::resume_own_startup_timestamp_ms). Diagnostic use (e.g. logging alongside the peer's own, below) - never itself consulted by this module's own tie-break logic after init. | |
| uint64_t | rte_dual_negotiator_get_peer_startup_timestamp_ms (const rte_dual_negotiator_t *negotiator) |
| Returns this instance's last-known view of the peer's own startup timestamp (0/unset until the first valid STATE frame arrives). Diagnostic use only, same posture as rte_dual_negotiator_get_own_startup_timestamp_ms() above. | |
| uint32_t | rte_dual_negotiator_get_own_id (const rte_dual_negotiator_t *negotiator) |
| Returns this instance's own tie-break identifier (rte_dual_negotiator_config_t::own_id at init time). Diagnostic use only. | |
| uint32_t | rte_dual_negotiator_get_peer_id (const rte_dual_negotiator_t *negotiator) |
| Returns the expected peer's tie-break identifier (rte_dual_negotiator_config_t::peer_id at init time). Diagnostic use only. | |
| const char * | rte_dual_state_to_string (rte_dual_state_t state) |
| Returns a short, static, human-readable string for a rte_dual_state_t. Intended for diagnostics/logging only (e.g. as the Info= field of a rte_log_write_event() call); never on a safety-decision path. | |
| const char * | rte_dual_channel_status_to_string (rte_dual_channel_status_t status) |
| Returns a short, static, human-readable string for a rte_dual_channel_status_t. Same diagnostics-only contract as rte_dual_state_to_string(). | |
Which of two redundant instances is active, and how well-backed is the standby one (ADR-020).
| #define RTE_DUAL_CHANNEL_MAX_LINKS 4U |
Maximum number of redundant links one rte_dual_channel_t may be configured with. Fixed, not dynamic (REQ-OAL-COMMON-010).
Definition at line 66 of file rte_dual_channel.h.
| #define RTE_DUAL_CHANNEL_MAX_PAYLOAD (RTE_DUAL_MSGCHANNEL_MAX_PAYLOAD - 4U) |
Max application payload bytes usable via rte_dual_channel_send()/_receive() - Layer-1's own RTE_DUAL_MSGCHANNEL_MAX_PAYLOAD minus this layer's 4-byte rte_dual_frame_header_t.
Definition at line 72 of file rte_dual_channel.h.
| #define RTE_DUAL_MSGCHANNEL_MAX_PAYLOAD 248U |
Max payload bytes usable via rte_dual_msgchannel_send()/ _receive() - bounded by rte_vital_message_t's own fixed 248-byte payload field (rte_checksum.h).
Definition at line 58 of file rte_dual_msgchannel.h.
| typedef void(*) rte_dual_channel_status_callback_t(rte_dual_channel_status_t new_status, rte_dual_channel_status_t old_status, void *user_ctx) |
Optional callback invoked whenever rte_dual_channel_get_status()'s value changes (ADR-020 section 2's "indicate to the user via callback if registered" requirement). Called synchronously from inside rte_dual_channel_send() (the only place aggregate status is recomputed) - keep this fast; it is on the same call path as the send it was triggered by.
| new_status | Status just transitioned to. |
| old_status | Status just transitioned from. |
| user_ctx | Caller-supplied context from rte_dual_channel_config_t. |
Definition at line 85 of file rte_dual_channel.h.
| typedef void(*) rte_dual_negotiator_state_change_callback_t(rte_dual_state_t new_own_state, rte_dual_state_t old_own_state, rte_dual_state_t new_peer_state, rte_dual_state_t old_peer_state, void *user_ctx) |
Optional callback invoked whenever either the own or the peer rte_dual_state_t changes, from inside rte_dual_negotiator_execute().
| new_own_state | Own state just transitioned to. |
| old_own_state | Own state just transitioned from. |
| new_peer_state | Peer state just transitioned to. |
| old_peer_state | Peer state just transitioned from. |
| user_ctx | Caller-supplied context from rte_dual_negotiator_config_t. |
Definition at line 71 of file rte_dual_negotiator.h.
Which kind of Layer-2 frame a given Layer-1 payload holds. Stored as the first byte of every rte_dual_channel_t frame so DATA, ACK, and STATE traffic sharing the same redundant links can never be misinterpreted as each other.
Explicit numeric values are fixed and part of the wire format: do not renumber existing entries, only append.
| Enumerator | |
|---|---|
| RTE_DUAL_FRAME_KIND_DATA | Application payload (rte_dual_channel_send()/_receive()); expects a RTE_DUAL_FRAME_KIND_ACK frame back. |
| RTE_DUAL_FRAME_KIND_ACK | Acknowledges one DATA frame's sequence_number (acked_sequence below) - checked, not just "some ACK arrived", against the specific send it corresponds to (ADR-020 section 1). |
| RTE_DUAL_FRAME_KIND_STATE | rte_dual_negotiator_t's own state beacon - fire-and-forget, periodic, no ACK expected (unlike DATA). |
| RTE_DUAL_FRAME_KIND_HEARTBEAT | Liveness heartbeat frame - sent periodically to maintain connection, expects a RTE_DUAL_FRAME_KIND_ACK frame back. |
Definition at line 41 of file rte_dual_frames.h.
| enum rte_dual_state_t |
State of one instance in a dual (two-redundant-instance) relationship, as decided by rte_dual_negotiator_t (ADR-020 section 3). Both this instance's own state and its last-known view of the peer's state use this same enum - see rte_dual_negotiator_get_own_state()/_get_peer_state().
Explicit numeric values are fixed and part of the ABI (this value travels on the wire inside rte_dual_state_frame_t::state): do not renumber existing entries, only append.
Definition at line 37 of file rte_dual_types.h.
Aggregate connection status of a rte_dual_channel_t across all of its configured redundant links (ADR-020 section 2). Independent of rte_dual_state_t: losing some (not all) of the redundant links degrades this status without by itself forcing any rte_dual_state_t transition - only total loss (DOWN) is a negotiator-relevant liveness event.
Definition at line 65 of file rte_dual_types.h.
| rte_status_t rte_dual_channel_init | ( | rte_dual_channel_t * | channel, |
| const rte_dual_channel_config_t * | config ) |
Initializes a rte_dual_channel_t: initializes every configured redundant link (rte_dual_msgchannel_init()) and starts rte_dual_channel_get_status() at RTE_DUAL_CHANNEL_STATUS_DOWN (no traffic has been sent/received yet).
| channel | Caller-owned storage to initialize. Must not be NULL. |
| config | Configuration. Must not be NULL; config->link_count must be in [1, RTE_DUAL_CHANNEL_MAX_LINKS]; every config->links[0..link_count-1] must not be NULL. |
Definition at line 183 of file rte_dual_channel.c.
| rte_status_t rte_dual_channel_send | ( | rte_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.
After every configured link has been tried, recomputes rte_dual_channel_get_status() and invokes config->status_callback if it changed (ADR-020 section 2).
| channel | Initialized channel. Must not be NULL. |
| payload | Payload to send. May be NULL only if payload_size is 0. |
| payload_size | Payload size in bytes; must be <= RTE_DUAL_CHANNEL_MAX_PAYLOAD. |
| out_ack_link_count | Optional; if not NULL, receives how many of the configured links ACKed this send. May be NULL. |
REQ-DUAL-CHANNEL-007: The per-link ACK wait keeps polling within config->ack_timeout_ms even when rte_timer_now() shows no progress between polls, bounded by a fixed cap (RTE_DUAL_CHANNEL_STALL_POLL_LIMIT) on consecutive no-progress polls. REQ-DUAL-CHANNEL-008: If no link ACKed and at least one link's own send/receive reported RTE_STATUS_HARDWARE_FAULT, that status is returned instead of RTE_STATUS_TIMEOUT; RTE_STATUS_DATA_CORRUPTION on an otherwise healthy link still folds into RTE_STATUS_TIMEOUT.
Definition at line 353 of file rte_dual_channel.c.
| rte_status_t rte_dual_channel_receive | ( | rte_dual_channel_t * | channel, |
| uint8_t * | out_payload, | ||
| uint8_t | max_size, | ||
| rte_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 rte_dual_channel_send()'s own doc) if none was already staged from a previous rte_dual_channel_send() call's own incidental polling.
| channel | Initialized channel. Must not be NULL. |
| out_payload | Destination buffer. Must not be NULL. |
| max_size | Usable size of out_payload; must be > 0. |
| timeout_ms | Maximum total time to actively poll the configured links if nothing was already staged (split evenly across links); 0 = check only what is already staged. |
| out_size | Receives the actual payload size. Must not be NULL. |
REQ-DUAL-CHANNEL-008: If no link produced a usable frame and at least one link's own receive reported RTE_STATUS_HARDWARE_FAULT, that status is returned instead of RTE_STATUS_TIMEOUT; RTE_STATUS_DATA_CORRUPTION on an otherwise healthy link still folds into RTE_STATUS_TIMEOUT.
Definition at line 426 of file rte_dual_channel.c.
| rte_status_t rte_dual_channel_send_heartbeat | ( | rte_dual_channel_t * | channel, |
| uint32_t * | out_ack_count ) |
Transmits a connection maintenance heartbeat frame across every configured link and waits up to ack_timeout_ms for an ACK on each.
| channel | Initialized channel. Must not be NULL. |
| out_ack_count | Optional; receives the number of links that ACKed. |
Definition at line 491 of file rte_dual_channel.c.
| rte_status_t rte_dual_channel_send_state_frame | ( | rte_dual_channel_t * | channel, |
| rte_dual_state_t | state, | ||
| bool | channel_degraded, | ||
| uint64_t | timestamp_ms ) |
Sends a rte_dual_state_frame_t (rte_dual_frames.h) on every configured redundant link - fire-and-forget, no ACK wait (unlike rte_dual_channel_send()'s DATA frames), matching the periodic-beacon nature of state negotiation. Intended to be called by a rte_dual_negotiator_t, not directly by application code - see ADR-020 section 3.
| channel | Initialized channel. Must not be NULL. |
| state | This instance's own rte_dual_state_t to advertise. |
| channel_degraded | This instance's own current rte_dual_channel_get_status() != FULL, as a single bit (so the peer can tell HOTSTANDBY from COLDSTANDBY for itself). |
| timestamp_ms | Caller-supplied value for the frame's own timestamp_ms field. This function does not source it from rte_timer_now() itself: a rte_dual_negotiator_t needs the same fixed value on every beacon it ever sends (captured once at its own init) for its startup tie-break to remain stable call to call - see rte_dual_state_frame_t's own doc. |
Definition at line 550 of file rte_dual_channel.c.
| rte_status_t rte_dual_channel_receive_state_frame | ( | rte_dual_channel_t * | channel, |
| rte_duration_ms_t | timeout_ms, | ||
| rte_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 rte_dual_negotiator_t - see ADR-020 section 3.
| channel | Initialized channel. Must not be NULL. |
| timeout_ms | Maximum total time to actively poll if nothing was already staged (split evenly across links); 0 = check only what is already staged. |
| out_frame | Receives the frame. Must not be NULL. |
Definition at line 584 of file rte_dual_channel.c.
| rte_dual_channel_status_t rte_dual_channel_get_status | ( | const rte_dual_channel_t * | channel | ) |
Returns the aggregate connection status across every configured redundant link, as of the most recent rte_dual_channel_send() call (ADR-020 section 2). RTE_DUAL_CHANNEL_STATUS_DOWN before the first send.
| channel | Channel to query. May be NULL (returns DOWN, defensive default). |
Definition at line 618 of file rte_dual_channel.c.
| bool rte_dual_channel_is_link_up | ( | const rte_dual_channel_t * | channel, |
| uint32_t | link_index ) |
Returns whether one specific configured link is currently considered up, as of the most recent rte_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 rte_dual_channel_get_status() for the aggregate).
| channel | Channel to query. May be NULL (returns false). |
| link_index | Index into the configured links, 0..link_count-1. |
Definition at line 627 of file rte_dual_channel.c.
| rte_status_t rte_dual_channel_set_resync_on_sequence_error | ( | rte_dual_channel_t * | channel, |
| bool | enable ) |
Enables sequence resynchronisation on every link of channel (see rte_dual_msgchannel_set_resync_on_sequence_error()).
Definition at line 636 of file rte_dual_channel.c.
| rte_status_t rte_dual_msgchannel_set_resync_on_sequence_error | ( | rte_dual_msgchannel_t * | channel, |
| bool | enable ) |
Turns sequence resynchronisation on or off (default off after init).
When on, an inbound frame with a valid CRC and the right sender_id but the wrong sequence number is still rejected (never delivered), but the expected sequence is set to that frame's number plus one, so the next frame from the same peer is accepted. For a link whose peer can restart on its own (the inter-site negotiation link): each end restarts at sequence 0, the surviving end keeps expecting the old number, and without this both ends reject each other for good. CRC and sender checks stay in force.
Definition at line 162 of file rte_dual_msgchannel.c.
| rte_status_t rte_dual_msgchannel_init | ( | rte_dual_msgchannel_t * | channel, |
| const rte_dual_msgchannel_config_t * | config ) |
Initializes a rte_dual_msgchannel_t: starts both sequence counters at 0.
| channel | Caller-owned storage to initialize. Must not be NULL. |
| config | Configuration. Must not be NULL; config->link must not be NULL. |
Local makros Local types declarations Local variables declarations Global variables declarations Local function declarations Global functions
Definition at line 20 of file rte_dual_msgchannel.c.
| rte_status_t rte_dual_msgchannel_send | ( | rte_dual_msgchannel_t * | channel, |
| const uint8_t * | payload, | ||
| uint8_t | payload_size, | ||
| rte_duration_ms_t | timeout_ms, | ||
| uint32_t * | out_sequence ) |
Wraps payload in a rte_vital_message_t (this channel's own sender_id and next sequence_number) and sends it over config->link, blocking at most timeout_ms.
| channel | Initialized channel. Must not be NULL. |
| payload | Payload to send. May be NULL only if payload_size is 0. |
| payload_size | Payload size in bytes; must be <= RTE_DUAL_MSGCHANNEL_MAX_PAYLOAD. |
| timeout_ms | Maximum time to wait for the underlying rte_netlink_send() to complete (REQ-DUAL-MSGCHANNEL-002). |
| out_sequence | Optional; if not NULL, receives the sequence_number this frame was sent with (the caller needs this to correlate a later ACK - see rte_dual_channel.h). May be NULL. |
Definition at line 38 of file rte_dual_msgchannel.c.
| rte_status_t rte_dual_msgchannel_receive | ( | rte_dual_msgchannel_t * | channel, |
| uint8_t * | out_payload, | ||
| uint8_t | payload_max_size, | ||
| rte_duration_ms_t | timeout_ms, | ||
| uint8_t * | out_payload_size, | ||
| uint32_t * | out_sequence ) |
Receives one frame over config->link, blocking at most timeout_ms, verifies its CRC-64 and sequence continuity (rte_checksum_vital_message_verify() against channel->expected_sequence) and its sender_id against config->expected_peer_id, and extracts the payload.
| channel | Initialized channel. Must not be NULL. |
| out_payload | Destination buffer. Must not be NULL. |
| payload_max_size | Usable size of out_payload; must be > 0. |
| timeout_ms | Maximum time to wait for a frame to arrive. |
| out_payload_size | Receives the actual payload size. Must not be NULL. |
| out_sequence | Optional; receives the frame's own sequence_number (e.g. so a DATA frame's sequence can be echoed back in an ACK - see rte_dual_channel.h). May be NULL. |
Definition at line 81 of file rte_dual_msgchannel.c.
| rte_status_t rte_dual_msgchannel_reset_sequence | ( | rte_dual_msgchannel_t * | channel | ) |
Resets both sequence counters to 0. Intended to be called by the caller (typically rte_dual_channel_t) exactly once, immediately after config->link has been freshly (re)established with the peer - the same idea as a mechanism RBC_GP once had and has since removed (2026-10-04): a cycle-counter reset after a peer-link reconnect. A fresh link needs a fresh, mutually agreed starting sequence rather than fighting over whatever counters were left over from before the disconnect.
| channel | Channel to reset. Must not be NULL. |
Definition at line 149 of file rte_dual_msgchannel.c.
| rte_status_t rte_dual_negotiator_init | ( | rte_dual_negotiator_t * | negotiator, |
| const rte_dual_negotiator_config_t * | config ) |
Initializes a rte_dual_negotiator_t. Captures this instance's own startup timestamp once (rte_timer_now(), degrading to 0 if no timer OSAdapter is registered - same best-effort posture as rte_log_write_event()'s Timestamp field) for use on every beacon this negotiator ever sends - see rte_dual_state_frame_t's own doc on why this must stay fixed - UNLESS config->resume_own_state/resume_own_startup_timestamp_ms opt into resuming a prior identity instead (see their own doc). peer_state always starts at RTE_DUAL_STATE_IDLE; own_state does too unless a resume was requested.
| negotiator | Caller-owned storage to initialize. Must not be NULL. |
| config | Configuration. Must not be NULL; config->channel must not be NULL. |
Definition at line 127 of file rte_dual_negotiator.c.
| rte_status_t rte_dual_negotiator_execute | ( | rte_dual_negotiator_t * | negotiator, |
| rte_duration_ms_t | receive_timeout_ms ) |
Drives one round of state negotiation: refreshes own_channel_degraded from the attached channel's current rte_dual_channel_get_status(), sends this instance's own beacon, drains and processes every currently-pending inbound STATE frame, then recomputes both own and peer rte_dual_state_t:
Invokes config->state_change_callback if either state changed.
| negotiator | Initialized negotiator. Must not be NULL. |
| receive_timeout_ms | Maximum time to wait for at least one inbound STATE frame if none is already pending on the attached channel (passed through to rte_dual_channel_receive_state_frame()); 0 = do not block, only process what is already pending. |
Definition at line 162 of file rte_dual_negotiator.c.
| rte_dual_state_t rte_dual_negotiator_get_own_state | ( | const rte_dual_negotiator_t * | negotiator | ) |
Returns this instance's own current rte_dual_state_t.
| negotiator | Negotiator to query. May be NULL (returns RTE_DUAL_STATE_IDLE, defensive default). |
Definition at line 197 of file rte_dual_negotiator.c.
| rte_dual_state_t rte_dual_negotiator_get_peer_state | ( | const rte_dual_negotiator_t * | negotiator | ) |
Returns this instance's last-known view of the peer's rte_dual_state_t.
| negotiator | Negotiator to query. May be NULL (returns RTE_DUAL_STATE_IDLE, defensive default). |
Definition at line 206 of file rte_dual_negotiator.c.
| uint64_t rte_dual_negotiator_get_own_startup_timestamp_ms | ( | const rte_dual_negotiator_t * | negotiator | ) |
Returns this instance's own startup timestamp (captured at rte_dual_negotiator_init() time, or resumed from config - see rte_dual_negotiator_config_t::resume_own_startup_timestamp_ms). Diagnostic use (e.g. logging alongside the peer's own, below) - never itself consulted by this module's own tie-break logic after init.
| negotiator | Negotiator to query. May be NULL (returns 0). |
Definition at line 215 of file rte_dual_negotiator.c.
| uint64_t rte_dual_negotiator_get_peer_startup_timestamp_ms | ( | const rte_dual_negotiator_t * | negotiator | ) |
Returns this instance's last-known view of the peer's own startup timestamp (0/unset until the first valid STATE frame arrives). Diagnostic use only, same posture as rte_dual_negotiator_get_own_startup_timestamp_ms() above.
| negotiator | Negotiator to query. May be NULL (returns 0). |
Definition at line 224 of file rte_dual_negotiator.c.
| uint32_t rte_dual_negotiator_get_own_id | ( | const rte_dual_negotiator_t * | negotiator | ) |
Returns this instance's own tie-break identifier (rte_dual_negotiator_config_t::own_id at init time). Diagnostic use only.
| negotiator | Negotiator to query. May be NULL (returns 0). |
Definition at line 233 of file rte_dual_negotiator.c.
| uint32_t rte_dual_negotiator_get_peer_id | ( | const rte_dual_negotiator_t * | negotiator | ) |
Returns the expected peer's tie-break identifier (rte_dual_negotiator_config_t::peer_id at init time). Diagnostic use only.
| negotiator | Negotiator to query. May be NULL (returns 0). |
Definition at line 242 of file rte_dual_negotiator.c.
| const char * rte_dual_state_to_string | ( | rte_dual_state_t | state | ) |
Returns a short, static, human-readable string for a rte_dual_state_t. Intended for diagnostics/logging only (e.g. as the Info= field of a rte_log_write_event() call); never on a safety-decision path.
| state | Value to render; an unrecognized value (defensive only - not reachable through the public enum) renders as "UNKNOWN_STATE". |
Local makros Local types declarations Local variables declarations Global variables declarations Local function declarations Global functions
Definition at line 21 of file rte_dual_types.c.
| const char * rte_dual_channel_status_to_string | ( | rte_dual_channel_status_t | status | ) |
Returns a short, static, human-readable string for a rte_dual_channel_status_t. Same diagnostics-only contract as rte_dual_state_to_string().
| status | Value to render; an unrecognized value renders as "UNKNOWN_STATUS". |
Definition at line 50 of file rte_dual_types.c.