|
Safe API Framework
Layered API framework for safety-related applications (ERTMS RBC reference targeting CENELEC EN 50128 SIL 4)
|
Files | |
| file | src/redundancy/voter/sapi_voter.c |
| N-way voting engine (ADR-025): validates parameters, dispatches send/receive to every registered healthy channel, and - for receive - groups the responses by mutual agreement and picks the largest group meeting quorum. | |
Data Structures | |
| struct | sapi_voter_config_t |
| Configuration for sapi_voter_init(). More... | |
| struct | sapi_voter_storage_t |
| Storage for one voter instance (opaque to caller). No dynamic memory. More... | |
Macros | |
| #define | SAPI_VOTER_MAX_CHANNELS 8U |
| Maximum number of channels a single voter can register. | |
| #define | SAPI_VOTER_MAX_MESSAGE_SIZE 256U |
| Maximum payload size sapi_voter_send()/_receive() supports. | |
Typedefs | |
| typedef bool(*) | sapi_voter_compare_fn(const void *a, const void *b, size_t size, void *user_ctx) |
| Optional custom comparison callback. | |
| typedef sapi_voter_storage_t | sapi_voter_t |
| Opaque handle to a voter instance. | |
Enumerations | |
| enum | sapi_voting_strategy_t { SAPI_VOTING_2OO2 = 1 , SAPI_VOTING_2OO3 = 2 , SAPI_VOTING_NMR = 3 } |
| Voting strategy: how many registered channels must agree. More... | |
| enum | sapi_voting_result_t { SAPI_VOTING_AGREED = 0 , SAPI_VOTING_DISAGREED = 1 , SAPI_VOTING_TIMEOUT = 2 , SAPI_VOTING_INSUFFICIENT_QUORUM = 3 } |
| Outcome of one sapi_voter_receive() call. More... | |
Functions | |
| sapi_status_t | sapi_voter_init (sapi_voter_storage_t *storage, const sapi_voter_config_t *config) |
| Initializes a voter with zero registered channels. | |
| sapi_status_t | sapi_voter_register_channel (sapi_voter_t *voter, sapi_channel_t *channel) |
| Registers one already-initialized channel with this voter. | |
| sapi_status_t | sapi_voter_send (sapi_voter_t *voter, const void *data, size_t data_size) |
| Broadcasts data to every registered, healthy channel. | |
| sapi_status_t | sapi_voter_receive (sapi_voter_t *voter, void *data, size_t data_size, sapi_voting_result_t *result, size_t *bytes_received) |
| Receives from every registered, healthy channel and votes. | |
| sapi_status_t | sapi_voter_get_aggregated_health (const sapi_voter_t *voter, uint32_t *healthy_count, uint32_t *total_disagreements) |
| Aggregated health across every registered channel. | |
| 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. | |
| sapi_channel_t * | sapi_voter_get_channel_by_name (const sapi_voter_t *voter, const char *name) |
| Direct access to one registered channel, by name (e.g. "ChannelAtoB") - the name each channel was given via sapi_channel_config_t::name at its own sapi_channel_init() time. | |
| sapi_status_t | sapi_voter_destroy (sapi_voter_t *voter) |
| Destroys a voter instance. | |
| #define SAPI_VOTER_MAX_CHANNELS 8U |
Maximum number of channels a single voter can register.
Definition at line 111 of file sapi_voter.h.
| #define SAPI_VOTER_MAX_MESSAGE_SIZE 256U |
Maximum payload size sapi_voter_send()/_receive() supports.
Definition at line 114 of file sapi_voter.h.
| typedef bool(*) sapi_voter_compare_fn(const void *a, const void *b, size_t size, void *user_ctx) |
Optional custom comparison callback.
If not registered (sapi_voter_config_t::compare == NULL), the default is a full byte compare (memcmp(a, b, size) == 0) - the payloads being compared have already had their transport-integrity CRC verified by the channel layer (sapi_checksum) if the backend uses sapi_checksum_vital_message_verify(); this callback is about semantic/value comparison, not integrity checking.
| [in] | a | First buffer. |
| [in] | b | Second buffer. |
| [in] | size | Number of bytes to compare. |
| [in] | user_ctx | sapi_voter_config_t::compare_context, passed through verbatim. |
Definition at line 73 of file sapi_voter.h.
| typedef sapi_voter_storage_t sapi_voter_t |
Opaque handle to a voter instance.
Definition at line 128 of file sapi_voter.h.
Voting strategy: how many registered channels must agree.
| Enumerator | |
|---|---|
| SAPI_VOTING_2OO2 | 2 out of 2: both channels must agree. |
| SAPI_VOTING_2OO3 | 2 out of 3: majority among 3 channels, tolerates 1 fault. |
| SAPI_VOTING_NMR | N out of M: sapi_voter_config_t::quorum_size of registered channels must agree. |
Definition at line 33 of file sapi_voter.h.
| enum sapi_voting_result_t |
Outcome of one sapi_voter_receive() call.
Definition at line 45 of file sapi_voter.h.
| sapi_status_t sapi_voter_init | ( | sapi_voter_storage_t * | storage, |
| const sapi_voter_config_t * | config ) |
Initializes a voter with zero registered channels.
| [out] | storage | Pre-allocated storage. Must not be NULL. |
| [in] | config | Voting configuration. Must not be NULL. For SAPI_VOTING_NMR, config->quorum_size must be >= 1. |
REQ-VOTER-001: No dynamic allocation; fixed SAPI_VOTER_MAX_CHANNELS array. REQ-VOTER-002: Rejects an unrecognized voting_strategy, or NMR with quorum_size == 0.
Definition at line 97 of file sapi_voter.c.
| sapi_status_t sapi_voter_register_channel | ( | sapi_voter_t * | voter, |
| sapi_channel_t * | channel ) |
Registers one already-initialized channel with this voter.
| [in] | voter | Voter handle. Must not be NULL and must be initialized. |
| [in] | channel | Already sapi_channel_init()'d channel. Must not be NULL. |
Definition at line 136 of file sapi_voter.c.
| sapi_status_t sapi_voter_send | ( | sapi_voter_t * | voter, |
| const void * | data, | ||
| size_t | data_size ) |
Broadcasts data to every registered, healthy channel.
| [in] | voter | Voter handle. Must not be NULL and initialized. |
| [in] | data | Data to send. Must not be NULL. |
| [in] | data_size | Size in bytes; must be > 0 and <= SAPI_VOTER_MAX_MESSAGE_SIZE. |
REQ-VOTER-003: Requires the registered-channel count to match the configured strategy before sending.
Definition at line 165 of file sapi_voter.c.
| sapi_status_t sapi_voter_receive | ( | sapi_voter_t * | voter, |
| void * | data, | ||
| size_t | data_size, | ||
| sapi_voting_result_t * | result, | ||
| size_t * | bytes_received ) |
Receives from every registered, healthy channel and votes.
Groups the channels that responded successfully by mutual agreement (per config->compare, default memcmp); the largest group that meets the configured quorum wins - AGREED, with *data set to that group's value. If no group is large enough, DISAGREED. If fewer than 2 channels responded at all, TIMEOUT (0 responded) or INSUFFICIENT_QUORUM (1 responded, or not enough healthy channels to possibly meet quorum before even trying).
| [in] | voter | Voter handle. Must not be NULL and initialized. |
| [out] | data | Buffer to receive the winning group's data. Must not be NULL. |
| [in] | data_size | Size of data buffer; must be > 0 and <= SAPI_VOTER_MAX_MESSAGE_SIZE. |
| [out] | result | Voting outcome. Can be NULL. |
| [out] | bytes_received | Bytes written to data. Can be NULL. |
REQ-VOTER-003: Requires the registered-channel count to match the configured strategy before receiving/voting. REQ-VOTER-004: Groups responses by mutual agreement and selects the largest quorum-meeting group (majority vote), not a pairwise compare against a single reference channel. REQ-VOTER-005: On DISAGREED, enters SAPI_SAFESTATE_LEVEL_SAFE when trigger_safestate_on_disagreement is true, and always invokes on_disagreement (if registered) regardless of that flag.
Definition at line 227 of file sapi_voter.c.
| sapi_status_t sapi_voter_get_aggregated_health | ( | const sapi_voter_t * | voter, |
| uint32_t * | healthy_count, | ||
| uint32_t * | total_disagreements ) |
Aggregated health across every registered channel.
| [in] | voter | Voter handle. Must not be NULL. |
| [out] | healthy_count | Number of currently-healthy registered channels. Can be NULL. |
| [out] | total_disagreements | Running count of DISAGREED results returned by this voter. Can be NULL. |
Definition at line 412 of file sapi_voter.c.
| uint32_t sapi_voter_get_channel_count | ( | const sapi_voter_t * | voter | ) |
Number of channels currently registered with this voter.
Intended for callers (e.g. sapi_channel_checkpoint()) that need to iterate the voter's registered channels directly rather than through send()/receive()'s own voting.
| [in] | voter | Voter handle. Must not be NULL. |
Definition at line 431 of file sapi_voter.c.
| sapi_channel_t * sapi_voter_get_channel | ( | const sapi_voter_t * | voter, |
| uint32_t | index ) |
Direct access to one registered channel, by index.
| [in] | voter | Voter handle. Must not be NULL. |
| [in] | index | 0-based index; must be < sapi_voter_get_channel_count(voter). |
Definition at line 436 of file sapi_voter.c.
| sapi_channel_t * sapi_voter_get_channel_by_name | ( | const sapi_voter_t * | voter, |
| const char * | name ) |
Direct access to one registered channel, by name (e.g. "ChannelAtoB") - the name each channel was given via sapi_channel_config_t::name at its own sapi_channel_init() time.
Linear search over the registered channels (channel counts here are small - SAPI_VOTER_MAX_CHANNELS - so this is not a hot-path lookup by design); compares with strcmp(), so an exact, case-sensitive match is required.
| [in] | voter | Voter handle. Must not be NULL. |
| [in] | name | Name to search for. Must not be NULL. |
Definition at line 445 of file sapi_voter.c.
| sapi_status_t sapi_voter_destroy | ( | sapi_voter_t * | voter | ) |
Destroys a voter instance.
No dynamic memory to free; registered channels are NOT destroyed (caller retains ownership).
| [in] | voter | Voter handle. May be NULL. |
Definition at line 465 of file sapi_voter.c.