RTE RBC 2oo2 Reference Application 0.1.0 build 0006685
SIL 4 2oo2 Dual-Site Fault-Tolerant ERTMS Radio Block Centre Reference Architecture
Loading...
Searching...
No Matches
pre_execute.c
Go to the documentation of this file.
1
9
11
12#include <stdio.h>
13#include <string.h>
14
15#include "rte/oal/log/rte_log.h"
16#include "rte/oal/memory/rte_mem_util.h"
17#include "rte/utils/safestate/rte_safestate.h"
18#include "rte/oal/timer/rte_timer.h"
19#include "rte/redundancy/watchdog/rte_watchdog.h"
20
35#include "ab_gp_ga_hooks.h" /* ab_gp_dispatch_il_envelope() - see that file's own doc */
36
42
49
51static uint32_t saf_now_ms(const ab_gp_channel_context_t *ctx)
52{
53 return ctx->cyc_cycle * ctx->config.timers.cycle_period_ms;
54}
55
57static void saf_stage_to_train(ab_gp_channel_context_t *ctx, uint8_t train_id, const uint8_t *frame, size_t len)
58{
60
61 if (!ab_gp_saf_envelope_encode(train_id, frame, len, env) ||
63 RTE_STATUS_OK))
64 {
65 rte_log_write_event(RTE_LOG_LEVEL_ERROR, site_config_name(ctx->site), ctx->cyc_cycle, ctx->role_tag, "Train",
66 "SAF", "could not stage a SaF frame for the train", NULL);
67 }
68}
69
71static void saf_apply_result(ab_gp_channel_context_t *ctx, relay_poll_context_t *poll_ctx, uint8_t train_id,
72 const ab_gp_saf_result_t *res)
73{
74 char info[48];
75
76 switch (res->action)
77 {
79 saf_stage_to_train(ctx, train_id, res->frame, res->frame_len);
80 if (res->share_rb)
81 {
82 uint8_t peer_frame[PEER_WIRE_FRAME_SIZE] = { 0 };
83
84 peer_frame[0] = PEER_MSG_KIND_SAF_RB;
85 rte_mem_copy(&peer_frame[1], res->rb_share, sizeof(res->rb_share));
86 (void)ab_gp_channel_send_peer((ab_gp_channel_handle_t)ctx, peer_frame, sizeof(peer_frame));
87 }
88 break;
90 if ((poll_ctx != NULL) &&
92 res->app, res->app_len, ctx->cyc_cycle, saf_now_ms(ctx)))
93 {
94 poll_ctx->have_channel_data = true;
95 }
96 break;
98 (void)snprintf(info, sizeof(info), "train=%u status=%d", (unsigned int)train_id, (int)res->status);
99 rte_log_write_event(RTE_LOG_LEVEL_WARNING, site_config_name(ctx->site), ctx->cyc_cycle, "Train",
100 ctx->role_tag, "SAF", "frame rejected", info);
101 break;
103 (void)snprintf(info, sizeof(info), "train=%u", (unsigned int)train_id);
104 rte_log_write_event(RTE_LOG_LEVEL_INFO, site_config_name(ctx->site), ctx->cyc_cycle, "Train",
105 ctx->role_tag, "SAF", "train released the safe connection", info);
106 break;
107 default:
108 break;
109 }
110}
111
112static void on_saf_envelope(relay_poll_context_t *poll_ctx, const uint8_t *bytes)
113{
114 ab_gp_channel_context_t *ctx = poll_ctx->ctx;
115 uint8_t train_id = 0U;
116 const uint8_t *frame = NULL;
117 size_t len = 0U;
119
120 if (!ctx->saf_train.enabled || !ab_gp_saf_envelope_decode(bytes, &train_id, &frame, &len))
121 {
122 rte_log_write_event(RTE_LOG_LEVEL_WARNING, site_config_name(ctx->site), ctx->cyc_cycle, "Train",
123 ctx->role_tag, "SAF", "SaF envelope dropped (protection off or malformed)", NULL);
124 return;
125 }
126 ab_gp_saf_train_on_frame(&ctx->saf_train, train_id, frame, len, saf_now_ms(ctx), &res);
127 saf_apply_result(ctx, poll_ctx, train_id, &res);
128}
129
130static void on_relay_envelope_received(void *user_ctx, rte_example_relay_kind_t kind, uint8_t index,
131 const uint8_t *bytes)
132{
133 relay_poll_context_t *poll_ctx = (relay_poll_context_t *)user_ctx;
134 ab_gp_channel_context_t *ctx = poll_ctx->ctx;
135
136 (void)index; /* ADR-036: one link per kind - routing is by env->train_id */
137
138 if (!ctx->is_online)
139 {
140 return;
141 }
142
144 {
145 /* ADR-036: C keepalives the multiplexed Train relay every idle
146 * cycle (gateway_c_train_handler.c) - recognise and drop it here,
147 * before ab_gp_train_apply_envelope() would reject it as a
148 * malformed train envelope. Same guard the IL branch below has. */
149 if (rbc_envelope_is_keepalive(bytes))
150 {
151 /* dropped */
152 }
153 else if (bytes[0] == (uint8_t)RBC_MSG_SAF_ENVELOPE)
154 {
155 on_saf_envelope(poll_ctx, bytes);
156 }
157 else if ((bytes[0] == (uint8_t)RBC_MSG_ERTMS_ENVELOPE) && ctx->saf_train.enabled)
158 {
159 /* REQ-SC-004: with the train link protected, an unprotected ERTMS frame never reaches the procedures. */
160 rte_log_write_event(RTE_LOG_LEVEL_WARNING, site_config_name(ctx->site), ctx->cyc_cycle, "Train",
161 ctx->role_tag, "SAF", "unprotected ERTMS frame dropped", NULL);
162 }
163 else if (bytes[0] == (uint8_t)RBC_MSG_ERTMS_ENVELOPE)
164 {
165 /* Real Subset-026 traffic on top of an already P0-connected
166 * session slot - see rbc_wire_types.h's own doc for this
167 * kind's 2-byte kind+train_id prefix, which ab_gp_train.c's
168 * own flat-scheme switch never sees. */
169 if (ab_gp_proc_dispatch_train_inbound((ab_gp_channel_handle_t)ctx, ctx->sessions, &ctx->db, bytes[1],
170 &bytes[2], RBC_TRAIN_ENVELOPE_WIRE_SIZE - 2U, ctx->cyc_cycle,
171 ctx->cyc_cycle * ctx->config.timers.cycle_period_ms))
172 {
173 poll_ctx->have_channel_data = true;
174 }
175 else
176 {
177 RTE_EXAMPLE_LOG("[%s] cycle %u: rejected malformed/unknown RBC_MSG_ERTMS_ENVELOPE frame (train %u)\n",
178 ctx->role_tag, ctx->cyc_cycle, (unsigned int)bytes[1]);
179 rte_log_write_event(RTE_LOG_LEVEL_WARNING, site_config_name(ctx->site), ctx->cyc_cycle, "Train",
180 ctx->role_tag, "ERTMS_ENVELOPE", "rejected malformed/unknown frame", NULL);
181 }
182 }
183 else if (ab_gp_train_apply_envelope(ctx->sessions, &ctx->db, bytes, ctx->cyc_cycle, ctx->is_role_a,
184 ctx->site, ctx->role_tag, ctx->cyc_msg_type_due,
186 {
187 poll_ctx->have_channel_data = true;
188 }
189 }
190 else if (kind == RTE_EXAMPLE_RELAY_KIND_IL)
191 {
192 uint8_t req_level = 0U;
193
194 if (rbc_envelope_is_set_log_level(bytes, &req_level))
195 {
196 /* Diagnostic control frame fanned out by C's gateway_c_logctl.c
197 * (rte_log is non-safety, ADR-001 4) - apply it and stop, do
198 * NOT run the IL domain decode on it. rte_log_set_level()
199 * itself ignores an out-of-range value. */
200 rte_log_set_level((rte_log_level_t)req_level);
201 /* Logged AT the just-set level so the confirmation is never
202 * self-suppressed (a raise to WARNING would otherwise hide
203 * its own "now at WARNING" line). */
204 rte_log_write_event((rte_log_level_t)req_level, site_config_name(ctx->site), ctx->cyc_cycle,
205 ctx->role_tag, "C", "LOG_LEVEL", "applied from C",
206 rte_log_level_to_string((rte_log_level_t)req_level));
207 }
208 else if (!rbc_envelope_is_keepalive(bytes))
209 {
210 if (ab_gp_dispatch_il_envelope(ctx->sessions, &ctx->db, bytes, ctx->cyc_cycle, ctx->site, ctx->role_tag))
211 {
212 poll_ctx->have_channel_data = true;
213 }
214 }
215 else
216 {
217 /* IL keepalive drained without action */
218 }
219 }
220 else
221 {
222 /* CTC keepalives drained without action */
223 }
224}
225
226static void on_crosscompare_frame_received(void *user_ctx, uint8_t kind, const uint8_t *payload, size_t size)
227{
228 peer_poll_context_t *poll_ctx = (peer_poll_context_t *)user_ctx;
229 ab_gp_channel_context_t *ctx = poll_ctx->ctx;
230
231 if (kind == PEER_MSG_KIND_AB_SAMPLE)
232 {
233 if (size >= AB_SAMPLE_WIRE_SIZE)
234 {
235 rte_mem_copy(poll_ctx->peer_bytes, payload, AB_SAMPLE_WIRE_SIZE);
236 poll_ctx->have_peer_data = true;
238 }
239 }
240}
241
242static void on_peer_frame_received(void *user_ctx, uint8_t kind, const uint8_t *payload, size_t size)
243{
244 peer_poll_context_t *poll_ctx = (peer_poll_context_t *)user_ctx;
245 ab_gp_channel_context_t *ctx = poll_ctx->ctx;
246
247 if (kind == PEER_MSG_KIND_SITE_STATE)
248 {
249 /* No cycle stamp here: rte_site_role stamps the cycle of the execute that takes the frame (REQ-SITEROLE-016). */
250 (void)ab_gp_sibling_state_store(&ctx->peer_site_state, payload, size);
251 }
252 else if (kind == PEER_MSG_KIND_CHECKPOINT_REQUEST)
253 {
254 uint8_t reply_frame[PEER_WIRE_FRAME_SIZE] = { 0 };
255 reply_frame[0] = PEER_MSG_KIND_CHECKPOINT_REPLY;
256 /* Peer ran its own checkpoint stage this recently - feeds the
257 * lookback check in ab_gp_channel_checkpoint_backend_recv(). */
259 if (size >= sizeof(rte_vital_message_t))
260 {
261 rte_mem_copy(&reply_frame[1], payload, sizeof(rte_vital_message_t));
262 /* Retain the peer's own arrival too (see ab_gp_channel_types.h):
263 * on an active cycle it carries this cycle's id and can
264 * confirm this side's rendezvous when the retained reply
265 * (older id) cannot. */
266 rte_mem_copy(ctx->cached_checkpoint_request, payload, sizeof(rte_vital_message_t));
268 }
269 (void)ab_gp_channel_send_peer((ab_gp_channel_handle_t)ctx, reply_frame, sizeof(reply_frame));
270 }
271 else if (kind == PEER_MSG_KIND_CHECKPOINT_REPLY)
272 {
273 /* Reply to a CHECKPOINT_REQUEST this side sent from a prior
274 * cycle's post_execute(), arriving after that rendezvous
275 * attempt's short receive window already closed. Retain it (it
276 * was previously dropped here) so this cycle's rendezvous
277 * consumes it instead of timing out - see ab_gp_channel_types.h. */
279 if (size >= sizeof(rte_vital_message_t))
280 {
281 rte_mem_copy(ctx->cached_checkpoint_reply, payload, sizeof(rte_vital_message_t));
282 ctx->has_cached_checkpoint_reply = true;
283 }
284 }
285 else if (kind == PEER_MSG_KIND_SAF_RB)
286 {
287 /* B: the responder random A drew for a train's AU1 - see ab_gp_saf_train.h. */
289
290 ab_gp_saf_train_on_peer_rb(&ctx->saf_train, payload, size, saf_now_ms(ctx), &res);
291 if (size >= (size_t)AB_GP_SAF_PEER_RB_SIZE)
292 {
293 saf_apply_result(ctx, NULL, payload[0], &res);
294 }
295 }
296 else if (kind == PEER_MSG_KIND_KM114_DIGEST)
297 {
298 /* Platform_Protocol_KM114 step 3: cross-check this side's own decoded KMAC against the
299 * A/B sibling's - see ab_gp_km114_client.c's own doc. */
300 (void)ab_gp_km114_client_on_peer_digest(payload, size, ctx->role_tag, ctx->site);
301 }
302 else if (kind == PEER_MSG_KIND_STARTUP_TS)
303 {
304 /* The sibling restarted and asks for the site's startup timestamp (ADR-040 step 5a); a reply is cached only. */
306 }
307 else
308 {
309 /* Unrecognized peer message kind ignored */
310 }
311}
312
319static void log_role_transition(ab_gp_channel_context_t *ctx, uint32_t cycle)
320{
321 if (ctx->is_online && !ctx->was_online)
322 {
323 RTE_EXAMPLE_LOG("[%s] promoted to ONLINE\n", ctx->role_tag);
324 rte_log_write_event(RTE_LOG_LEVEL_INFO, site_config_name(ctx->site), cycle, ctx->role_tag, "-", "ROLE",
325 "promoted to ONLINE", NULL);
326 }
327 else if (!ctx->is_online && ctx->was_online)
328 {
329 RTE_EXAMPLE_LOG("[%s] demoted to STANDBY\n", ctx->role_tag);
330 rte_log_write_event(RTE_LOG_LEVEL_INFO, site_config_name(ctx->site), cycle, ctx->role_tag, "-", "ROLE",
331 "demoted to STANDBY", NULL);
332 }
333 ctx->was_online = ctx->is_online;
334}
335
345{
346 rte_status_t status;
347 uint8_t i;
348 uint32_t peer_cycle = 0U;
350
351 ctx->cyc_crc_ok = false;
352 if (peer_poll->have_peer_data)
353 {
354 void *dests[AB_GP_CHANNEL_PAYLOAD_MAX_COLLECTORS] = { NULL };
355
356 dests[ab_gp_train_payload_collector_id()] = peer_sessions;
357 status = ab_gp_channel_payload_decode_ab_sample(peer_poll->peer_bytes, &peer_cycle, dests);
358 if (status == RTE_STATUS_DATA_CORRUPTION)
359 {
360 RTE_EXAMPLE_LOG("[%s] cycle %u: CRC-64 mismatch on peer link - data cannot be trusted, entering SAFE state\n",
361 ctx->role_tag, ctx->cyc_cycle);
362 rte_log_write_event(RTE_LOG_LEVEL_ERROR, site_config_name(ctx->site), ctx->cyc_cycle, ctx->is_role_a ? "B" : "A", ctx->role_tag,
363 "AB_SAMPLE", "CRC-64 mismatch - entering SAFE state", NULL);
364 RTE_SAFESTATE(RTE_SAFESTATE_LEVEL_SAFE, RTE_EXAMPLE_REASON_AB_CRC_MISMATCH);
365 }
366 else if (status != RTE_STATUS_OK)
367 {
368 RTE_EXAMPLE_LOG("[%s] cycle %u: malformed peer message (%s)\n", ctx->role_tag, ctx->cyc_cycle,
369 rte_status_to_string(status));
370 rte_log_write_event(RTE_LOG_LEVEL_ERROR, site_config_name(ctx->site), ctx->cyc_cycle, ctx->is_role_a ? "B" : "A", ctx->role_tag,
371 "AB_SAMPLE", rte_status_to_string(status), NULL);
372 }
373 else
374 {
375 ctx->cyc_crc_ok = true;
376 for (i = 0U; i < (uint8_t)RTE_EXAMPLE_MAX_TRAINS; i++)
377 {
378 ctx->cyc_peer_sessions[i] = peer_sessions[i];
379 }
380 RTE_EXAMPLE_LOG("[%s] cycle %u: dual transfer received sample from peer (peer_cycle=%u, CRC=OK)\n",
381 ctx->role_tag, ctx->cyc_cycle, (unsigned int)peer_cycle);
382 rte_log_write_event(RTE_LOG_LEVEL_DEBUG, site_config_name(ctx->site), ctx->cyc_cycle,
383 ctx->is_role_a ? "B" : "A", ctx->role_tag, "DUAL_TRANSFER",
384 "received sample from peer (CRC=OK)", NULL);
385 }
386 }
387
388 ctx->cyc_have_peer_data = peer_poll->have_peer_data;
389 ctx->cyc_peer_cycle = peer_cycle;
390 ctx->cyc_agree = false;
391}
392
397{
398 if (ctx->is_online && !ctx->single_mode && (ctx->last_peer_sample_cycle > 0U))
399 {
400 uint32_t timeout_cycles = (ctx->config.timers.dual_transfer_timeout_ms + (ctx->config.timers.cycle_period_ms - 1U)) /
402 if (timeout_cycles == 0U)
403 {
404 timeout_cycles = 1U;
405 }
406 if ((cycle > ctx->last_peer_sample_cycle) && ((cycle - ctx->last_peer_sample_cycle) >= timeout_cycles))
407 {
409 }
410 }
411}
412
413rte_status_t ab_gp_channel_pre_execute(void *context)
414{
416 rte_status_t status;
417 uint8_t own_role_byte;
418 uint32_t cycle;
419 uint32_t drained_count;
420 uint8_t i;
421 relay_poll_context_t relay_poll;
422 peer_poll_context_t peer_poll;
423
424 if (ctx == NULL)
425 {
426 return RTE_STATUS_INVALID_PARAM;
427 }
428
429 /* ADR-034: clear last cycle's staged-output queue before this cycle
430 * (post_execute()) can stage anything new into it - see
431 * ab_gp_channel_stage.h. Any prior cycle's queue is always already
432 * empty by now (on_checkpoint_result() flushes or discards it every
433 * cycle), so this is defensive, not load-bearing - but cheap and
434 * unconditional, matching this function's own role as the per-cycle
435 * reset point ahead of this cycle's own work. */
437
439 if (status != RTE_STATUS_OK)
440 {
441 return status;
442 }
443
444 cycle = ctx->cyc_cycle;
445
446 if (ctx->watchdog != NULL)
447 {
448 rte_watchdog_timer_tick();
449 }
450
451 /* The A/B peer link is drained BEFORE this cycle's site-role step (G1 step 5b-2 review fix): rte_site_role takes
452 * the sibling's site-state frame through the sibling source inside ab_gp_channel_negotiate_execute(), so the
453 * frame this cycle's poll delivers must already be stored for the role decision and the A/B agreement check of
454 * the same cycle (the check then compares role(N) with the frame received in N, as the old GP-side check did;
455 * polling after the step would add one cycle of check lag and a fourth cycle to the reachability window).
456 * Everything else these frames do is independent of the site-role step and of the relay poll below: checkpoint
457 * request/reply caching and the reply send, SAF_RB (the SAF module accepts AU1 and the peer RB in either order),
458 * KM114_DIGEST (compared in whichever order the two installs and the frame arrive) and STARTUP_TS (answered from
459 * the fixed startup timestamp). The deferred frames are those the checkpoint rendezvous read last cycle. */
460 peer_poll.ctx = ctx;
461 rte_mem_set(peer_poll.peer_bytes, 0, sizeof(peer_poll.peer_bytes));
462 peer_poll.have_peer_data = false;
463
464 for (i = 0U; i < ctx->deferred_peer_count; i++)
465 {
466 on_peer_frame_received(&peer_poll, ctx->deferred_peer_frames[i][0], &ctx->deferred_peer_frames[i][1],
467 (size_t)PEER_WIRE_FRAME_SIZE - 1U);
468 }
469 ctx->deferred_peer_count = 0U;
471
473
474 own_role_byte = ctx->own_faulted ? (uint8_t)RTE_EXAMPLE_SITE_ROLE_FAULTED
475 : (ctx->is_online ? (uint8_t)RTE_EXAMPLE_SITE_ROLE_ONLINE
477
478 log_role_transition(ctx, cycle);
479
480 for (i = 0U; i < (uint8_t)RTE_EXAMPLE_MAX_TRAINS; i++)
481 {
482 ctx->cyc_position_reply_due[i] = false;
483 }
484
485 relay_poll.ctx = ctx;
486 relay_poll.have_channel_data = false;
487
488 if (ctx->saf_train.enabled)
489 {
490 /* REQ-SC-004: a protected link silent for longer than the supervision time is declared lost; the train's
491 * ERTMS session then times out exactly as it does on any other lost link. */
492 uint32_t lost = ab_gp_saf_train_supervise(&ctx->saf_train, saf_now_ms(ctx));
493
494 for (i = 0U; i < (uint8_t)RTE_EXAMPLE_MAX_TRAINS; i++)
495 {
496 if ((lost & ((uint32_t)1U << i)) != 0U)
497 {
498 char info[16];
499
500 (void)snprintf(info, sizeof(info), "train=%u", (unsigned int)(i + 1U));
501 rte_log_write_event(RTE_LOG_LEVEL_WARNING, site_config_name(ctx->site), cycle, "Train",
502 ctx->role_tag, "SAF", "safe connection supervision expired - link lost", info);
503 }
504 }
505 }
506
509 if (drained_count > 0U)
510 {
511 ctx->last_relay_rx_cycle = cycle;
512 }
513
514 if (drained_count == 0U)
515 {
516 RTE_EXAMPLE_LOG("[%s] cycle %u: no envelopes from C yet - skipping this cycle's decision\n",
517 ctx->role_tag, cycle);
518 rte_log_write_event(RTE_LOG_LEVEL_DEBUG, site_config_name(ctx->site), cycle, "C", ctx->role_tag,
519 "ENVELOPE", "none received", NULL);
520 }
521 else if (!ctx->is_online)
522 {
523 RTE_EXAMPLE_LOG("[%s] cycle %u: [%s] %u envelope(s) received - standby, not processed\n",
524 ctx->role_tag, cycle, ab_gp_channel_dual_role_byte_to_string(own_role_byte),
525 (unsigned int)drained_count);
526 rte_log_write_event(RTE_LOG_LEVEL_DEBUG, site_config_name(ctx->site), cycle, "C", ctx->role_tag,
527 "ENVELOPE", "received - standby, not processed", NULL);
528 }
529
531 /* The verdict of this cycle's rte_site_role_execute() (the peer poll above the site-role step fed it). */
533
534 decode_and_apply_peer_sample(ctx, &peer_poll);
535
536 check_dual_transfer_timeout(ctx, cycle);
537
538 return RTE_STATUS_OK;
539}
void ab_gp_channel_poll_peer(ab_gp_channel_handle_t handle, ab_gp_com_peer_frame_cb cb, void *user_ctx)
Polls the A<->B peer channel non-blockingly and invokes cb for every received frame.
rte_status_t ab_gp_channel_send_peer(ab_gp_channel_handle_t handle, const uint8_t *bytes, size_t size)
Sends a frame over the A<->B peer channel.
uint32_t ab_gp_channel_poll_relays(ab_gp_channel_handle_t handle, ab_gp_com_envelope_cb cb, void *user_ctx)
Polls all C relay channels non-blockingly and invokes cb for every received envelope.
rte_status_t ab_gp_channel_wait_cycle_tick(ab_gp_channel_handle_t handle)
Waits for the periodic cycle timer tick, advances cycle, and refreshes watchdog/checkpoint state.
void ab_gp_channel_poll_crosscompare(ab_gp_channel_handle_t handle, ab_gp_com_peer_frame_cb cb, void *user_ctx)
Polls the dedicated A<->B cross-compare channel non-blockingly and invokes cb for every received fram...
struct ab_gp_channel_context_s * ab_gp_channel_handle_t
Opaque handle over this component's own static per-process context.
void ab_gp_channel_crosscompare_check_site_state(ab_gp_channel_context_t *ctx)
Reacts to the A/B role agreement verdict: this channel's own independently-negotiated {online,...
The actual A-vs-B cross-compare decision: does this cycle's own M24/M15 answer match what the peer in...
Shared declarations for the four rte_appmanager_operations_t cyclic-executive hooks this component's ...
rte_status_t ab_gp_channel_pre_execute(void *context)
const char * ab_gp_channel_dual_role_byte_to_string(uint8_t role_byte)
void ab_gp_channel_dual_on_transfer_lost(void *context)
Everything related to this channel's own "dual transfer" state: the single-mode degradation reaction ...
void ab_gp_channel_negotiate_execute(ab_gp_channel_context_t *ctx, uint32_t cycle)
Runs one cycle's worth of inter-site negotiation: drives the negotiator's own STATE-frame exchange (d...
void ab_gp_channel_negotiate_on_startup_ts_frame(ab_gp_channel_context_t *ctx, const uint8_t *payload, size_t size)
Handles a PEER_MSG_KIND_STARTUP_TS frame that arrives after ab_gp_channel_negotiate_init() returned (...
This channel's own West<->East inter-site negotiation link - see ab_gp_channel.c's file header for ho...
rte_status_t ab_gp_channel_payload_decode_ab_sample(uint8_t in[AB_SAMPLE_WIRE_SIZE], uint32_t *out_cycle, void *const dests[AB_GP_CHANNEL_PAYLOAD_MAX_COLLECTORS])
Decodes and CRC-64-verifies an A<->B peer-link sample.
Generic, data-blind wire framing for the A<->B peer link's AB_SAMPLE frame (CRC-64-protected,...
#define AB_GP_CHANNEL_PAYLOAD_MAX_COLLECTORS
void ab_gp_channel_stage_reset(ab_gp_channel_handle_t handle)
Clears this cycle's pending-send queue.
rte_status_t ab_gp_channel_stage_relay(ab_gp_channel_handle_t handle, rte_example_relay_kind_t kind, uint8_t index, const uint8_t *bytes, size_t size)
Queues a relay-link send for this cycle - does not transmit yet.
Stage-then-commit output queue for this cycle's own DECISION output (ADR-034): the peer AB_SAMPLE and...
Modular type definitions for AB channel components (Com, Train, DB, Redundancy).
#define AB_SAMPLE_WIRE_SIZE
#define PEER_WIRE_FRAME_SIZE
#define PEER_MSG_KIND_KM114_DIGEST
#define PEER_MSG_KIND_CHECKPOINT_REQUEST
#define PEER_MSG_KIND_STARTUP_TS
#define PEER_MSG_KIND_AB_SAMPLE
#define PEER_MSG_KIND_CHECKPOINT_REPLY
#define PEER_MSG_KIND_SITE_STATE
#define PEER_MSG_KIND_SAF_RB
bool ab_gp_dispatch_il_envelope(ab_gp_train_session_t *sessions, ab_gp_db_t *db, const uint8_t env_bytes[RBC_ENVELOPE_WIRE_SIZE], uint32_t cycle, rte_example_site_t site, const char *role_tag)
Calls the registered IL envelope handler, if any - see ab_gp_register_il_envelope_handler()'s own doc...
GP's own dispatch side of the "GP calls into GA" surface - see ga_interface.h's own "functions GP cal...
int ab_gp_km114_client_on_peer_digest(const uint8_t *payload, size_t size, const char *role_tag, rte_example_site_t site)
Consumes a PEER_MSG_KIND_KM114_DIGEST frame from the A/B sibling (called from pre_execute....
A/B-side Subset-114 KMC message decoder - step 2 of Platform_Protocol_KM114's "Consumption design" (s...
bool ab_gp_proc_dispatch_train_inbound(ab_gp_channel_handle_t channel, ab_gp_train_session_t sessions[], ab_gp_db_t *db, uint8_t train_id, const uint8_t *payload, size_t payload_len, uint32_t cycle, uint32_t timestamp_ms)
Decodes one RBC_MSG_ERTMS_ENVELOPE payload and dispatches it into the ertms_procedures/ engine,...
Glue between RBC_MSG_ERTMS_ENVELOPE wire frames and the real Subset-026 procedure engine (ab_gp_ertms...
bool ab_gp_saf_envelope_decode(const uint8_t env[RBC_TRAIN_ENVELOPE_WIRE_SIZE], uint8_t *out_train_id, const uint8_t **out_frame, size_t *out_len)
Splits a received RBC_MSG_SAF_ENVELOPE relay frame.
void ab_gp_saf_train_on_peer_rb(ab_gp_saf_train_t *s, const uint8_t *payload, size_t size, uint32_t now_ms, ab_gp_saf_result_t *out)
B only: processes A's PEER_MSG_KIND_SAF_RB payload; answers the parked AU1 when its RA matches.
bool ab_gp_saf_envelope_encode(uint8_t train_id, const uint8_t *frame, size_t frame_len, uint8_t out[RBC_TRAIN_ENVELOPE_WIRE_SIZE])
Builds an RBC_MSG_SAF_ENVELOPE relay frame (RBC_TRAIN_ENVELOPE_WIRE_SIZE bytes).
uint32_t ab_gp_saf_train_supervise(ab_gp_saf_train_t *s, uint32_t now_ms)
Idle-link supervision of every connection in DATA (REQ-SC-004).
void ab_gp_saf_train_on_frame(ab_gp_saf_train_t *s, uint8_t train_id, const uint8_t *frame, size_t frame_len, uint32_t now_ms, ab_gp_saf_result_t *out)
Processes one SaF frame received from train slot train_id (1..RTE_EXAMPLE_MAX_TRAINS).
Train link safe communication (Subset-037 SaF) terminated inside A and B - REQ-SC-001,...
@ AB_GP_SAF_ACTION_REJECTED
@ AB_GP_SAF_ACTION_APP
@ AB_GP_SAF_ACTION_REPLY
@ AB_GP_SAF_ACTION_DISCONNECTED
#define AB_GP_SAF_PEER_RB_SIZE
PEER_MSG_KIND_SAF_RB payload: train_id(1) + RA(8) + RB(8).
bool ab_gp_sibling_state_store(ab_gp_sibling_state_t *st, const uint8_t *payload, size_t size)
Stores a received site-state frame payload: the rule of on_peer_frame_received() (the payload must ca...
The A/B sibling's last site-state frame (PEER_MSG_KIND_SITE_STATE), kept raw and handed to Platform_R...
bool ab_gp_train_apply_envelope(ab_gp_train_session_t sessions[], ab_gp_db_t *db, const uint8_t env_bytes[RBC_ENVELOPE_WIRE_SIZE], uint32_t cycle, bool is_role_a, rte_example_site_t site, const char *role_tag, uint32_t cyc_msg_type_due[], bool cyc_position_reply_due[])
THE single entry point com/'s ab_gp_channel.c calls for every raw envelope popped off its dedicated T...
uint32_t ab_gp_train_payload_collector_id(void)
A/B's own train lifecycle handling against db/'s runtime table.
#define RTE_EXAMPLE_SITE_ROLE_STANDBY
#define RTE_EXAMPLE_LOG(...)
#define RTE_EXAMPLE_REASON_AB_CRC_MISMATCH
#define RTE_EXAMPLE_SITE_ROLE_ONLINE
#define RBC_TRAIN_ENVELOPE_WIRE_SIZE
#define RTE_EXAMPLE_MAX_TRAINS
#define RTE_EXAMPLE_SITE_ROLE_FAULTED
static uint32_t saf_now_ms(const ab_gp_channel_context_t *ctx)
The channel's cycle clock in ms - the same time base ab_gp_proc_dispatch_train_inbound() is given.
Definition pre_execute.c:51
static void on_peer_frame_received(void *user_ctx, uint8_t kind, const uint8_t *payload, size_t size)
static void saf_apply_result(ab_gp_channel_context_t *ctx, relay_poll_context_t *poll_ctx, uint8_t train_id, const ab_gp_saf_result_t *res)
Acts on the outcome of one SaF frame (from the train or, for B, A's shared RB).
Definition pre_execute.c:71
static void saf_stage_to_train(ab_gp_channel_context_t *ctx, uint8_t train_id, const uint8_t *frame, size_t len)
Stages a SaF frame for a train on the Train relay (committed with this cycle's other outputs,...
Definition pre_execute.c:57
static void log_role_transition(ab_gp_channel_context_t *ctx, uint32_t cycle)
Log and record an ONLINE/STANDBY role transition, if one happened this cycle.
static void on_saf_envelope(relay_poll_context_t *poll_ctx, const uint8_t *bytes)
static void on_relay_envelope_received(void *user_ctx, rte_example_relay_kind_t kind, uint8_t index, const uint8_t *bytes)
static void on_crosscompare_frame_received(void *user_ctx, uint8_t kind, const uint8_t *payload, size_t size)
static void check_dual_transfer_timeout(ab_gp_channel_context_t *ctx, uint32_t cycle)
Declare a dual-transfer loss if no peer sample has arrived within the configured timeout.
static void decode_and_apply_peer_sample(ab_gp_channel_context_t *ctx, peer_poll_context_t *peer_poll)
Decode this cycle's dual-transfer peer sample (if any) and apply it to ctx.
static bool rbc_envelope_is_set_log_level(const uint8_t in[RBC_ENVELOPE_WIRE_SIZE], uint8_t *out_level)
true if in is a set-log-level control frame; *out_level (if non-NULL) then receives the requested lev...
@ RBC_MSG_SAF_ENVELOPE
@ RBC_MSG_ERTMS_ENVELOPE
static bool rbc_envelope_is_keepalive(const uint8_t in[RBC_ENVELOPE_WIRE_SIZE])
true if in is a keepalive frame - see rbc_envelope_write_keepalive()'s own doc. Callers on the receiv...
const char * site_config_name(rte_example_site_t site)
Definition site_config.c:52
West/East site identity and the per-site config derived from it (ports, container host lookup) - see ...
rte_example_relay_kind_t
Which client type a C<->A/C<->B relay link/port belongs to - this project's own dedicated-channel-per...
Definition site_config.h:39
@ RTE_EXAMPLE_RELAY_KIND_IL
Definition site_config.h:41
@ RTE_EXAMPLE_RELAY_KIND_TRAIN
Definition site_config.h:40
Central application context owned by composition root (main.c).
uint8_t deferred_peer_frames[AB_GP_DEFERRED_PEER_FRAMES][PEER_WIRE_FRAME_SIZE]
ab_gp_sibling_state_t peer_site_state
ab_gp_train_session_t sessions[RTE_EXAMPLE_MAX_TRAINS]
bool cyc_position_reply_due[RTE_EXAMPLE_MAX_TRAINS]
uint32_t cyc_msg_type_due[RTE_EXAMPLE_MAX_TRAINS]
ab_gp_train_session_t cyc_peer_sessions[RTE_EXAMPLE_MAX_TRAINS]
uint8_t cached_checkpoint_reply[sizeof(rte_vital_message_t)]
uint8_t cached_checkpoint_request[sizeof(rte_vital_message_t)]
ab_gp_config_timers_t timers
uint32_t dual_transfer_timeout_ms
Output of ab_gp_saf_train_on_frame() / _on_peer_rb().
safecomm_status_t status
uint8_t app[AB_GP_SAF_PDU_MAX]
uint8_t frame[SAFECOMM_SAF_AU2_LEN]
uint8_t rb_share[AB_GP_SAF_PEER_RB_SIZE]
ab_gp_saf_action_t action
uint8_t peer_bytes[AB_SAMPLE_WIRE_SIZE]
Definition pre_execute.c:46
ab_gp_channel_context_t * ctx
Definition pre_execute.c:45
ab_gp_channel_context_t * ctx
Definition pre_execute.c:39