17 if (own_ts != peer_ts)
19 return own_ts < peer_ts;
21 return own_id < peer_id;
29 negotiator->peer_startup_timestamp_ms = frame->
timestamp_ms;
30 negotiator->have_peer_startup_timestamp =
true;
33 negotiator->last_peer_seen_ms = now_ms;
34 negotiator->have_last_peer_seen =
true;
41 bool peer_contact_recent =
false;
43 if (negotiator->have_last_peer_seen)
48 if (now_ms >= negotiator->last_peer_seen_ms)
60 if (!negotiator->have_last_peer_seen)
66 else if (!peer_contact_recent)
80 negotiator->peer_id, negotiator->peer_startup_timestamp_ms);
89 negotiator->peer_state =
105 negotiator->peer_state =
114 negotiator->own_state =
119 if (((negotiator->own_state != old_own) || (negotiator->peer_state != old_peer))
120 && (negotiator->state_change_callback != NULL))
122 negotiator->state_change_callback(negotiator->own_state, old_own, negotiator->peer_state, old_peer,
123 negotiator->state_change_callback_ctx);
132 if ((negotiator == NULL) || (config == NULL) || (config->
channel == NULL))
137 negotiator->channel = config->
channel;
138 negotiator->own_id = config->
own_id;
139 negotiator->peer_id = config->
peer_id;
145 negotiator->own_startup_timestamp_ms = now_ms;
146 negotiator->own_channel_degraded =
false;
148 negotiator->have_peer_startup_timestamp =
false;
149 negotiator->peer_startup_timestamp_ms = 0U;
150 negotiator->peer_channel_degraded =
false;
155 negotiator->have_last_peer_seen =
false;
156 negotiator->last_peer_seen_ms = 0U;
166 if (negotiator == NULL)
171 negotiator->own_channel_degraded =
174 (void)sapi_dual_channel_send_state_frame(negotiator->channel, negotiator->own_state,
175 negotiator->own_channel_degraded,
176 negotiator->own_startup_timestamp_ms);
181 negotiator_process_peer_frame(negotiator, &frame);
188 negotiator_process_peer_frame(negotiator, &frame);
191 negotiator_update_states(negotiator);
198 if (negotiator == NULL)
202 return negotiator->own_state;
207 if (negotiator == NULL)
211 return negotiator->peer_state;
sapi_dual_state_t sapi_dual_negotiator_get_own_state(const sapi_dual_negotiator_t *negotiator)
Returns this instance's own current sapi_dual_state_t.
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 w...
sapi_dual_state_t
State of one instance in a dual (two-redundant-instance) relationship, as decided by sapi_dual_negoti...
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_status_t sapi_dual_negotiator_execute(sapi_dual_negotiator_t *negotiator, sapi_duration_ms_t receive_timeout_ms)
Drives one round of state negotiation: refreshes own_channel_degraded from the attached channel's cur...
sapi_status_t sapi_dual_negotiator_init(sapi_dual_negotiator_t *negotiator, const sapi_dual_negotiator_config_t *config)
Initializes a sapi_dual_negotiator_t. Captures this instance's own startup timestamp once (sapi_timer...
sapi_dual_state_t sapi_dual_negotiator_get_peer_state(const sapi_dual_negotiator_t *negotiator)
Returns this instance's last-known view of the peer's sapi_dual_state_t.
@ SAPI_DUAL_STATE_COLDSTANDBY
@ SAPI_DUAL_STATE_HOTSTANDBY
@ SAPI_DUAL_STATE_UNKNOWN
@ SAPI_DUAL_CHANNEL_STATUS_FULL
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
static bool negotiator_decide_online(uint32_t own_id, uint64_t own_ts, uint32_t peer_id, uint64_t peer_ts)
Older-timestamp-wins tie-break, own_id/peer_id as the deterministic fallback on an exact tie - same r...
Dual state negotiator of ADR-020: decides sapi_dual_state_t for both this instance and its peer,...
OS Abstraction Layer - Timer service.
Configuration for sapi_dual_negotiator_init().
sapi_dual_channel_t * channel
void * state_change_callback_ctx
sapi_duration_ms_t peer_lost_timeout_ms
sapi_dual_negotiator_state_change_callback_t state_change_callback
One sapi_dual_negotiator_t instance's state. Caller-owned storage; every field is private - reach it ...
SAPI_DUAL_FRAME_KIND_STATE payload - sapi_dual_negotiator_t's own periodic beacon.