20#define SAPI_CHECKPOINT_SENDER_ID ((uint32_t)0xC4EC0001U)
44#define SAPI_CHECKPOINT_RETRY_ROUND_MS ((sapi_duration_ms_t)250U)
67#define SAPI_CHECKPOINT_MIN_ROUNDS_PER_BUDGET ((sapi_duration_ms_t)3U)
79#define SAPI_CHECKPOINT_MAX_ROUNDS ((uint32_t)64U)
101 uint8_t payload_bytes[4];
116 sizeof(payload_bytes));
137 uint8_t payload_out[4];
138 uint8_t payload_size_out = 0U;
139 bool confirmed =
false;
141 reply, checkpoint_id, payload_out,
sizeof(payload_out), &payload_size_out);
143 if ((verify_status ==
SAPI_STATUS_OK) && (payload_size_out ==
sizeof(payload_out)))
149 uint32_t decoded_id = 0U;
157 && (decoded_id == checkpoint_id))
202 uint32_t channel_count;
206 if ((voter == NULL) || (config == NULL))
223 uint32_t confirmed_count = 0U;
228 uint32_t round_count = 0U;
233 if ((budget_based_round_cap_ms > 0U) && (budget_based_round_cap_ms < round_cap_ms))
235 round_cap_ms = budget_based_round_cap_ms;
240 channel_confirmed[i] =
false;
263 while ((confirmed_count < config->expected_node_count)
267 for (i = 0U; i < channel_count; i++)
280 last_send_status = send_status;
289 if (sub_budget_ms > round_cap_ms)
291 sub_budget_ms = round_cap_ms;
296 last_recv_status = recv_status;
301 channel_confirmed[i] =
true;
352 char diag_message[96];
354 (void)snprintf(diag_message,
sizeof(diag_message),
355 "checkpoint confirmed=%u expected=%u channels=%u last_send=%d last_recv=%d",
357 (
unsigned int)channel_count, (
int)last_send_status, (
int)last_recv_status);
363 (int32_t)__LINE__, diag_message);
sapi_status_t sapi_buffer_write_u32_le(sapi_buffer_t *buf, uint32_t value)
Appends a little-endian uint32_t at buf's current length.
sapi_status_t sapi_buffer_read_u32_le(const sapi_buffer_t *buf, size_t offset, uint32_t *out_value)
Reads a little-endian uint32_t at the given offset.
sapi_status_t sapi_buffer_init(sapi_buffer_t *buf, void *storage, size_t capacity)
Binds a buffer view to caller-owned storage. Initial length is 0.
sapi_status_t sapi_buffer_set_length(sapi_buffer_t *buf, size_t length)
Marks length bytes of already-written storage as valid.
sapi_status_t sapi_channel_checkpoint(sapi_voter_t *voter, const sapi_checkpoint_config_t *config)
Performs one bounded checkpoint rendezvous across every channel registered with a voter.
sapi_status_t sapi_checksum_vital_message_verify(const sapi_vital_message_t *msg, uint32_t expected_sequence, uint8_t *payload_out, size_t payload_max_size, uint8_t *payload_size_out)
Verify vital channel message and extract payload.
sapi_status_t sapi_checksum_vital_message_create(sapi_vital_message_t *msg_out, uint32_t sender_id, uint32_t sequence, const uint8_t *payload, size_t payload_size)
Create vital channel message with CRC.
#define SAPI_SAFESTATE_REASON_CHECKPOINT_TIMEOUT
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...
@ SAPI_SAFESTATE_LEVEL_SAFE
sapi_status_t
Common result/status codes.
@ SAPI_STATUS_INVALID_PARAM
sapi_status_t sapi_timer_now(sapi_timestamp_ms_t *out_now_ms)
Returns the current monotonic time base used by all timers.
uint32_t sapi_duration_ms_t
uint64_t sapi_timestamp_ms_t
sapi_status_t sapi_watchdog_kick(sapi_watchdog_t watchdog)
Kick (pet) watchdog - prove liveness.
sapi_status_t sapi_channel_send(sapi_channel_t *handle, const void *data, size_t data_size)
Sends data on this channel via its backend send callback.
sapi_status_t sapi_channel_receive(sapi_channel_t *handle, void *data, size_t data_size, uint32_t timeout_ms)
Receives data on this channel via its backend receive callback.
sapi_channel_storage_t sapi_channel_t
Opaque handle to a vital channel instance.
sapi_voter_storage_t sapi_voter_t
Opaque handle to a voter instance.
uint32_t sapi_voter_get_channel_count(const sapi_voter_t *voter)
Number of channels currently registered with this voter.
sapi_channel_t * sapi_voter_get_channel(const sapi_voter_t *voter, uint32_t index)
Direct access to one registered channel, by index.
#define SAPI_VOTER_MAX_CHANNELS
Maximum number of channels a single voter can register.
Cross-layer data buffer abstraction (ADR-002).
#define SAPI_CHECKPOINT_MIN_ROUNDS_PER_BUDGET
static bool reply_confirms_checkpoint(const sapi_vital_message_t *reply, uint32_t checkpoint_id)
Verifies a candidate reply's CRC/sequence (via sapi_checksum) and that its decoded payload matches ch...
static sapi_status_t build_arrival_message(uint32_t checkpoint_id, sapi_vital_message_t *out_msg)
Builds the checkpoint-arrival marker message.
#define SAPI_CHECKPOINT_SENDER_ID
#define SAPI_CHECKPOINT_RETRY_ROUND_MS
#define SAPI_CHECKPOINT_MAX_ROUNDS
static sapi_duration_ms_t remaining_budget_ms(sapi_timestamp_ms_t start_ms, sapi_timestamp_ms_t now_ms, sapi_duration_ms_t max_delay_ms)
Returns the time budget remaining until start_ms + max_delay_ms.
Bounded checkpoint rendezvous for distributed vital channels (ADR-017).
Checksum and CRC utilities for data integrity in redundant systems.
Safe-state transitions and checked assertions (ADR-004).
OS Abstraction Layer - Timer service.
Mutable, bounds-tracked view over caller-owned storage.
Checkpoint configuration.
uint32_t expected_node_count
sapi_duration_ms_t max_delay_ms
Vital channel message with integrated CRC-64.