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
post_execute.c
Go to the documentation of this file.
1
8
10
11#include <stdbool.h>
12#include <stdint.h>
13
14#include "rte/app/appmanager/rte_appmanager.h"
15#include "rte/oal/log/rte_log.h"
16#include "rte/redundancy/watchdog/rte_watchdog.h"
17
26#include "../com/ab_gp_status.h"
28#include "ab_gp_ga_hooks.h" /* ab_gp_drain_ctc_outputs()/_il_outputs() - see that file's own doc */
29
38{
39 if (ctx->is_online)
40 {
41 uint8_t out_bytes[PEER_WIRE_FRAME_SIZE] = { 0 };
42 const void *sources[AB_GP_CHANNEL_PAYLOAD_MAX_COLLECTORS] = { NULL };
43 rte_status_t stage_status;
44
46 out_bytes[0] = PEER_MSG_KIND_AB_SAMPLE;
47 ab_gp_channel_payload_encode_ab_sample(&out_bytes[1], cycle, sources);
48
49 RTE_CHECKPOINT_MARK();
50 stage_status = ab_gp_channel_stage_crosscompare(handle, PEER_MSG_KIND_AB_SAMPLE, &out_bytes[1], sizeof(out_bytes) - 1U);
51 if (stage_status == RTE_STATUS_OK)
52 {
53 RTE_EXAMPLE_LOG("[%s] cycle %u: dual transfer staged sample (%zu bytes) for peer\n",
54 ctx->role_tag, cycle, sizeof(out_bytes));
55 rte_log_write_event(RTE_LOG_LEVEL_DEBUG, site_config_name(ctx->site), cycle, ctx->role_tag,
56 ctx->is_role_a ? "B" : "A", "DUAL_TRANSFER", "sample staged for peer", "size=343");
57 }
58 }
59}
60
66{
67 if (ctx->is_online)
68 {
69 uint8_t keepalive[RBC_ENVELOPE_WIRE_SIZE];
70
71 /* ADR-036: one IL relay link now - one keepalive, not one per train. */
74 }
75}
76
86{
90 uint8_t train_count;
91 uint8_t ctc_count;
92 uint8_t il_count;
93 uint8_t i;
94 uint8_t k;
95 bool should_forward_to_c;
96
98 train_out);
99 ctc_count = ab_gp_drain_ctc_outputs(ctc_out);
100 il_count = ab_gp_drain_il_outputs(il_out);
101
102 should_forward_to_c = (ctx->cyc_agree) || (ctx->single_mode && ctx->cyc_have_channel_data);
103 if (!should_forward_to_c)
104 {
105 return;
106 }
107
108 /* Pending-output flags are only consumed HERE, once this cycle's
109 * built outputs are actually being staged for C - not
110 * unconditionally after building them above. A real, found-live
111 * bug: cyc_agree reflects the PEER's own confirmation of this
112 * channel's decision, which inherently lags by at least one
113 * cycle (the dual-transfer sample staged this cycle is only
114 * received/compared by the peer on a LATER cycle - see
115 * xcompare_recv_peer()'s own doc, ab_gp_channel_crosscompare.c).
116 * So the very first cycle a brand-new decision is computed (a
117 * fresh MA grant or extend, ma_pending_send just set true this
118 * same cycle by ab_ga_il_on_route_context_changed()), cyc_agree
119 * can legitimately still be false - the built M3 was discarded
120 * below (should_forward_to_c false), yet the flag that would
121 * have triggered a REBUILD next cycle was already cleared,
122 * silently losing that Movement Authority forever. Resetting
123 * only on the cycle that actually forwards means an unforwarded
124 * cycle's decision simply gets rebuilt (from whatever the
125 * session's current state is - always correct, never stale) and
126 * retried next cycle until it genuinely reaches C. */
127 for (i = 0U; i < (uint8_t)RTE_EXAMPLE_MAX_TRAINS; i++)
128 {
129 ctx->sessions[i].ma_pending_send = false;
130 ctx->sessions[i].position_reply_pending = false;
131 /* ctc_ma_notify_pending: ab_ga_ctc_build_outputs() (just
132 * staged as part of ctc_out[] above, via ctc_count) already
133 * consumed this cycle's real Subset-026/ERTMS MA-grant
134 * notification if it was set - see ab_gp_train_session_t's
135 * own doc on why this is a separate flag from
136 * ma_pending_send. Reset it here in the same place/manner
137 * ma_pending_send itself is reset, or it would stay true
138 * forever and CTC would never see ANOTHER grant/extend for
139 * this train (ctc_ma_granted_sent latches true after the
140 * first one, so nothing else would re-arm this path). */
141 ctx->sessions[i].ctc_ma_notify_pending = false;
142 }
143 /* Same reasoning as the flag resets just above, for IL's/CTC's
144 * own pending-output queues - those live in GA's private module
145 * statics, unreachable from here directly, hence these confirm
146 * callbacks instead of a direct reset. See
147 * ab_ga_il_confirm_outputs_sent()/ab_ga_ctc_confirm_outputs_sent()'s
148 * own doc for the full history (a real, previously-diagnosed-but-
149 * not-fully-fixed instance of this exact bug class). */
152
153 for (k = 0U; k < train_count; k++)
154 {
155 RTE_CHECKPOINT_MARK();
156 (void)ab_gp_channel_stage_relay(handle, RTE_EXAMPLE_RELAY_KIND_TRAIN, train_out[k].index,
157 train_out[k].bytes, RBC_ENVELOPE_WIRE_SIZE);
158 }
159 for (k = 0U; k < ctc_count; k++)
160 {
161 RTE_CHECKPOINT_MARK();
162 (void)ab_gp_channel_stage_relay(handle, RTE_EXAMPLE_RELAY_KIND_CTC, 0U, ctc_out[k].bytes,
164 }
165 for (k = 0U; k < il_count; k++)
166 {
167 RTE_CHECKPOINT_MARK();
168 (void)ab_gp_channel_stage_relay(handle, RTE_EXAMPLE_RELAY_KIND_IL, il_out[k].index, il_out[k].bytes,
170 }
171 if (ctc_count == 0U)
172 {
173 uint8_t keepalive[RBC_ENVELOPE_WIRE_SIZE];
174
177 }
178
179 if (train_count > 0U || ctc_count > 0U || il_count > 0U)
180 {
181 char extra_payload[96];
182 (void)snprintf(extra_payload, sizeof(extra_payload), "train_count=%u ctc_count=%u il_count=%u",
183 (unsigned int)train_count, (unsigned int)ctc_count, (unsigned int)il_count);
184 RTE_EXAMPLE_LOG("[%s] cycle %u: staged outputs for C (train=%u, ctc=%u, il=%u)\n",
185 ctx->role_tag, cycle, (unsigned int)train_count, (unsigned int)ctc_count, (unsigned int)il_count);
186 rte_log_write_event(RTE_LOG_LEVEL_DEBUG, site_config_name(ctx->site), cycle, ctx->role_tag, "C",
187 "OUTPUT_FORWARD", "staged outputs for C", extra_payload);
188 }
189}
190
198{
199 uint8_t frame[PEER_WIRE_FRAME_SIZE] = { 0 };
200
201 frame[0] = PEER_MSG_KIND_SITE_STATE;
202 frame[1] = ctx->is_online ? 1U : 0U;
204 frame[3] = ab_gp_site_status_ready_for_online(ctx) ? 1U : 0U;
205 (void)ab_gp_channel_send_peer(handle, frame, sizeof(frame));
206}
207
208rte_status_t ab_gp_channel_post_execute(void *context)
209{
212 uint32_t cycle;
213
214 if (ctx == NULL)
215 {
216 return RTE_STATUS_INVALID_PARAM;
217 }
218
219 cycle = ctx->cyc_cycle;
220
221 stage_peer_sample_if_online(ctx, handle, cycle);
222 send_il_keepalive_if_online(ctx, handle);
223 build_and_stage_outputs_to_c(ctx, handle, cycle);
224 send_site_state(ctx, handle);
225
226 /* Warm/hot standby: bring STANDBY up to date with THIS cycle's post-compute state before the staged
227 * outputs above are committed at the checkpoint stage. Never withholds output - a STANDBY that does
228 * not acknowledge is marked not working instead. No-op in cold mode. */
230
231 /* 5. Heartbeat kick for the cyclic executive watchdog */
232 if (ctx->watchdog != NULL)
233 {
234 (void)rte_watchdog_kick(ctx->watchdog);
235 }
236
237 /* 6. ADR-038: periodic status self-line + PUBLISH on the UTIL relay
238 * (non-safety monitoring - after everything else this cycle). */
239 ab_gp_status_tick(handle, ctx, cycle);
240
241 return RTE_STATUS_OK;
242}
243
252rte_status_t ab_gp_channel_on_checkpoint_result(void *context, bool committed)
253{
256
257 if (ctx == NULL)
258 {
259 return RTE_STATUS_INVALID_PARAM;
260 }
261
262 if (committed)
263 {
265 }
266
268 return RTE_STATUS_OK;
269}
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.
rte_status_t ab_gp_channel_send_relay(ab_gp_channel_handle_t handle, rte_example_relay_kind_t kind, uint8_t index, const uint8_t *bytes, size_t size)
Sends an envelope over a specific C relay channel.
struct ab_gp_channel_context_s * ab_gp_channel_handle_t
Opaque handle over this component's own static per-process context.
Shared declarations for the four rte_appmanager_operations_t cyclic-executive hooks this component's ...
rte_status_t ab_gp_channel_post_execute(void *context)
rte_status_t ab_gp_channel_on_checkpoint_result(void *context, bool committed)
rte_appmanager_operations_t::on_checkpoint_result for the AB channel (ADR-034) - flushes or discards ...
void ab_gp_channel_negotiate_sync_standby(ab_gp_channel_context_t *ctx, uint32_t cycle)
ONLINE only: send this cycle's post-compute snapshot to STANDBY and wait (bounded by the link's ack t...
This channel's own West<->East inter-site negotiation link - see ab_gp_channel.c's file header for ho...
void ab_gp_channel_payload_encode_ab_sample(uint8_t out[AB_SAMPLE_WIRE_SIZE], uint32_t cycle, const void *const sources[AB_GP_CHANNEL_PAYLOAD_MAX_COLLECTORS])
Encodes an A<->B peer-link sample: {cycle, every registered collector's own bytes in registration ord...
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_discard_pending_sends(ab_gp_channel_handle_t handle)
Discards every send queued this cycle without transmitting it, then clears the queue.
rte_status_t ab_gp_channel_stage_crosscompare(ab_gp_channel_handle_t handle, uint8_t kind, const uint8_t *payload, size_t size)
Queues a crosscompare-link send for this cycle - does not transmit yet.
rte_status_t ab_gp_channel_commit_pending_sends(ab_gp_channel_handle_t handle)
Transmits every send queued this cycle (through the real ab_gp_channel_send_peer()/_send_relay()),...
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 PEER_WIRE_FRAME_SIZE
#define PEER_MSG_KIND_AB_SAMPLE
#define PEER_MSG_KIND_SITE_STATE
uint8_t ab_gp_drain_ctc_outputs(ab_gp_ctc_pending_output_t out[AB_GP_CTC_MAX_PENDING_OUTPUTS])
Calls the registered CTC output producer, if any - see ab_gp_register_ctc_output_producer()'s own doc...
void ab_gp_confirm_il_outputs_sent(void)
Calls the registered IL output producer's own confirm callback, if any - see ab_gp_il_output_confirm_...
void ab_gp_confirm_ctc_outputs_sent(void)
Calls the registered CTC output producer's own confirm callback, if any - same contract as ab_gp_conf...
uint8_t ab_gp_drain_il_outputs(ab_gp_il_pending_output_t out[AB_GP_IL_MAX_PENDING_OUTPUTS])
Calls the registered IL output producer, if any - see ab_gp_register_il_output_producer()'s own doc,...
GP's own dispatch side of the "GP calls into GA" surface - see ga_interface.h's own "functions GP cal...
bool ab_gp_site_status_ready_for_online(const ab_gp_channel_context_t *ctx)
Whether this channel confirms it is ready to be ONLINE: the Gateway relay delivered a frame within th...
The site status monitor: collects, in one struct, the facts that decide and explain this channel's si...
void ab_gp_status_tick(ab_gp_channel_handle_t handle, const ab_gp_channel_context_t *ctx, uint32_t cycle)
Call once per cyclic-executive cycle from post_execute. Emits a status self line and publishes a STAT...
ADR-038: this A/B channel's periodic status - a self log line plus a PUBLISH(STATUS) rbc_util_frame_t...
uint8_t ab_gp_train_build_outputs(const ab_gp_train_session_t sessions[], const uint32_t cyc_msg_type_due[], const bool cyc_position_reply_due[], ab_gp_train_pending_output_t out[AB_GP_TRAIN_MAX_PENDING_OUTPUTS])
Decides which trains need a Train-directed envelope THIS cycle and builds all of them - see this file...
uint32_t ab_gp_train_payload_collector_id(void)
A/B's own train lifecycle handling against db/'s runtime table.
#define AB_GP_TRAIN_MAX_PENDING_OUTPUTS
#define RTE_EXAMPLE_LOG(...)
#define RTE_EXAMPLE_SINGLE_MODE_FLAG_DUAL
#define RBC_ENVELOPE_WIRE_SIZE
#define RTE_EXAMPLE_MAX_TRAINS
#define RTE_EXAMPLE_SINGLE_MODE_FLAG_SINGLE
#define AB_GP_IL_MAX_PENDING_OUTPUTS
#define AB_GP_CTC_MAX_PENDING_OUTPUTS
static void send_site_state(ab_gp_channel_context_t *ctx, ab_gp_channel_handle_t handle)
Step 4: send site state - protocol/negotiation-level state echo, not this cycle's own decision output...
static void build_and_stage_outputs_to_c(ab_gp_channel_context_t *ctx, ab_gp_channel_handle_t handle, uint32_t cycle)
Step 3: build this cycle's train/CTC/IL outputs and, if agreed (or single mode), stage them to C.
static void send_il_keepalive_if_online(ab_gp_channel_context_t *ctx, ab_gp_channel_handle_t handle)
Step 2: send IL keepalives if online - link-liveness traffic, not this cycle's own decision output,...
static void stage_peer_sample_if_online(ab_gp_channel_context_t *ctx, ab_gp_channel_handle_t handle, uint32_t cycle)
Step 1: stage this cycle's dual-transfer sample for the peer, if online.
static void rbc_envelope_write_keepalive(uint8_t out[RBC_ENVELOPE_WIRE_SIZE])
Fills out with a keepalive frame (RBC_MSG_RELAY_KEEPALIVE in byte 0, every other byte zero) - see tha...
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_CTC
Definition site_config.h:42
@ 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).
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]