15 const void *a,
const void *b,
size_t size)
19 if (cmp->config.
compare != NULL)
25 equal = (memcmp(a, b, size) == 0);
35 if ((storage == NULL) || (config == NULL))
44 return lifecycle_status;
47 storage->config = *config;
48 storage->channel_a = NULL;
49 storage->channel_b = NULL;
50 storage->registered_count = 0U;
51 storage->total_disagreements = 0U;
52 storage->initialized =
true;
62 if ((cmp == NULL) || (channel == NULL))
66 if (!cmp->initialized)
76 return lifecycle_status;
79 if (cmp->registered_count == 0U)
81 cmp->channel_a = channel;
82 cmp->registered_count = 1U;
84 else if (cmp->registered_count == 1U)
86 cmp->channel_b = channel;
87 cmp->registered_count = 2U;
98 void *out_data,
size_t *out_size)
108 if ((cmp == NULL) || (data_size == 0U))
112 if (!cmp->initialized)
120 if (cmp->registered_count != 2U)
145 else if (cross_comparator_data_equal(cmp, buf_a, buf_b, data_size))
157 *result = local_result;
162 if (out_data != NULL)
164 (void)memcpy(out_data, buf_a, data_size);
166 if (out_size != NULL)
168 *out_size = data_size;
173 if (out_size != NULL)
180 cmp->total_disagreements++;
200 uint32_t *healthy_count,
201 uint32_t *total_disagreements)
212 if (cmp->registered_count >= 1U)
220 if (cmp->registered_count >= 2U)
229 if (healthy_count != NULL)
231 *healthy_count = healthy;
233 if (total_disagreements != NULL)
235 *total_disagreements = cmp->total_disagreements;
246 cmp->initialized =
false;
sapi_status_t sapi_lifecycle_check_setup_allowed(void)
Convenience check for a setup-only constructor: call this as one of the first checks in any function ...
void sapi_log_write(sapi_log_level_t level, const char *tag, const char *message)
Emits one log message. Non-blocking; never fails the caller's control flow even if the message is dro...
#define SAPI_SAFESTATE(level, reason)
Explicitly enters the given safe-state level with a reason code, capturing the call site automaticall...
#define SAPI_SAFESTATE_REASON_UNSPECIFIED
@ SAPI_SAFESTATE_LEVEL_SAFE
sapi_status_t
Common result/status codes.
@ SAPI_STATUS_HARDWARE_FAULT
@ SAPI_STATUS_INVALID_PARAM
@ SAPI_STATUS_RESOURCE_EXHAUSTED
@ SAPI_STATUS_NOT_INITIALIZED
sapi_status_t sapi_channel_get_health(const sapi_channel_t *handle, sapi_channel_health_t *out_health)
Queries this channel's health statistics.
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_status_t sapi_cross_comparator_get_aggregated_health(const sapi_cross_comparator_t *cmp, uint32_t *healthy_count, uint32_t *total_disagreements)
Aggregated health across both registered channels.
#define SAPI_CROSS_COMPARATOR_MAX_MESSAGE_SIZE
Maximum payload size sapi_cross_comparator_execute() supports.
sapi_status_t sapi_cross_comparator_init(sapi_cross_comparator_storage_t *storage, const sapi_cross_comparator_config_t *config)
Initializes a cross-comparator with zero registered channels.
sapi_cross_comparator_storage_t sapi_cross_comparator_t
Opaque handle to a cross-comparator instance.
sapi_status_t sapi_cross_comparator_destroy(sapi_cross_comparator_t *cmp)
Destroys a cross-comparator instance.
sapi_status_t sapi_cross_comparator_register_channel(sapi_cross_comparator_t *cmp, sapi_channel_t *channel)
Registers one already-initialized channel (channel A, then B).
sapi_status_t sapi_cross_comparator_execute(sapi_cross_comparator_t *cmp, size_t data_size, sapi_voting_result_t *result, void *out_data, size_t *out_size)
Receives from both registered channels and compares them.
sapi_voting_result_t
Outcome of one sapi_voter_receive() call.
@ SAPI_VOTING_INSUFFICIENT_QUORUM
Pairwise comparison between exactly 2 registered sapi_channel_t links (ADR-025).
Process-wide application setup-phase lock (ADR-026).
OS Abstraction Layer - Logging/diagnostics service.
Safe-state transitions and checked assertions (ADR-004).
Health statistics for one vital channel.
Configuration for sapi_cross_comparator_init().
sapi_voter_compare_fn compare
void * disagreement_context
void(*) on_disagreement(void *context, sapi_voting_result_t result)
uint32_t channel_timeout_ms
bool trigger_safestate_on_disagreement
Storage for one cross-comparator instance (opaque to caller). No dynamic memory.