SafeAPI RBC 2oo2 Generic Application
IL/CTC route and train logic for the safeAPIRBC2oo2 reference RBC
Loading...
Searching...
No Matches
ab_ga_ctc.c
Go to the documentation of this file.
1
7#include "ab_ga_ctc.h"
8
9#include "safeapi/utils/buffer/sapi_buffer.h"
10#include "safeapi/oal/memory/sapi_mem_util.h"
11
12#include "common_config.h" /* SAFEAPI_EXAMPLE_LOG, SAFEAPI_EXAMPLE_MAX_TRAINS,
13 * SAFEAPI_EXAMPLE_MAX_ROUTES_PER_TRAIN */
14#include "ga_interface.h" /* ab_gp_train_session_*() - bare calls now, see that file's own doc */
15#include "ab_siteGA.h" /* ab_site_ga_get_route(), ab_site_ga_route_layout_t - GA's own
16 * static route table, see this file's own compute_train_info_signals()
17 * doc for why. */
18
28#define CTC_WIRE_HEADER_SIZE 12U
29#define CTC_WIRE_CONTENT_SIZE_BASE 24U
30
32
34
36
49/* ctc_on_route_connected forward decl REMOVED - ab_ga_ctc_on_route_context_changed()
50 * (ab_ga_ctc.h) is now the ONE public function GA's dispatch module
51 * calls, not a GP-registered callback - see this file's own module doc. */
52
61static bool g_train_info_pending[SAFEAPI_EXAMPLE_MAX_TRAINS];
62static ab_gp_train_context_t g_last_train_ctx[SAFEAPI_EXAMPLE_MAX_TRAINS];
67static bool g_train_ctx_known[SAFEAPI_EXAMPLE_MAX_TRAINS];
72static void ctc_wire_encode(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], const rbc_envelope_t *env);
82static void compute_train_info_signals(const uint16_t route_ids[SAFEAPI_EXAMPLE_MAX_ROUTES_PER_TRAIN],
83 uint8_t route_count, uint32_t d_lrbg, uint16_t *out_front_signal,
84 uint32_t *out_dist_to_front, uint16_t *out_target_signal);
85
86
88/* ab_ga_ctc_init() REMOVED - its entire body was one GP registration, now
89 * owned by ab_ga_dispatch.c's own single subscription (see this file's
90 * own module doc and ab_ga_dispatch.h). */
91
92void ab_ga_ctc_build_connected(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], uint8_t train_id, uint32_t d_lrbg)
93{
94 rbc_envelope_t env;
95
96 sapi_mem_set(&env, 0, sizeof(env));
97 env.kind = RBC_MSG_CTC_CONNECTED;
98 env.train_id = train_id;
99 env.d_lrbg = d_lrbg;
100 ctc_wire_encode(out, &env);
101}
102
103void ab_ga_ctc_build_ma_granted(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], uint8_t train_id, uint32_t ma_seq,
104 uint32_t ma_length)
105{
106 rbc_envelope_t env;
107
108 sapi_mem_set(&env, 0, sizeof(env));
109 env.kind = RBC_MSG_CTC_MA_GRANTED;
110 env.train_id = train_id;
111 env.ma_seq = ma_seq;
112 env.ma_length = ma_length;
113 ctc_wire_encode(out, &env);
114}
115
116void ab_ga_ctc_build_ma_extended(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], uint8_t train_id, uint32_t ma_seq,
117 uint32_t ma_length)
118{
119 rbc_envelope_t env;
120
121 sapi_mem_set(&env, 0, sizeof(env));
122 env.kind = RBC_MSG_CTC_MA_EXTENDED;
123 env.train_id = train_id;
124 env.ma_seq = ma_seq;
125 env.ma_length = ma_length;
126 ctc_wire_encode(out, &env);
127}
128
129/* ab_ga_ctc_build_alarm() - MOVED to GP (AB/GP/main/ab_gp_ga_hooks.c's own
130 * ab_gp_build_ctc_alarm()), later session, on direct request. */
131
132void ab_ga_ctc_build_train_info(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], uint8_t train_id, uint32_t d_lrbg,
133 uint32_t ma_seq, uint32_t granted_length, bool ma_granted,
134 uint16_t front_signal, uint32_t dist_to_front_signal, uint16_t target_signal,
135 uint32_t nid_lrbg, uint32_t v_train, uint32_t m_mode)
136{
137 rbc_envelope_t env;
138 int32_t ma_offset;
139
140 sapi_mem_set(&env, 0, sizeof(env));
141 env.kind = RBC_MSG_CTC_TRAIN_INFO;
142 env.train_id = train_id;
143 env.d_lrbg = d_lrbg;
144 env.ma_seq = ma_seq;
145 env.msg_type = ma_granted ? 1U : 0U; /* ma_status: 0=NONE, 1=GRANTED - see this
146 * kind's own doc, rbc_wire_types.h. */
147 env.route_len = (uint32_t)target_signal; /* MA target signal - reuses the slot that's
148 * otherwise always 0 for every CTC_* kind. */
149 env.t_train = (uint32_t)front_signal; /* front signal - reuses alarm's own timestamp
150 * slot, 0 for every other kind. */
151 env.cycle = dist_to_front_signal; /* distance to front signal - reuses alarm's
152 * own cycle slot. */
153 ma_offset = (int32_t)d_lrbg - (int32_t)granted_length; /* negative while approaching, 0 at
154 * the limit - see this kind's own
155 * doc for why "MA length in
156 * relation to balise" is not a
157 * separate field (it is -ma_offset). */
158 env.ma_length = (uint32_t)ma_offset; /* signed value, two's-complement bit pattern -
159 * decode as (int32_t) on the reading side. */
160 env.nid_lrbg = nid_lrbg; /* appended fields (on direct request) - see
161 * ctc_wire_encode()'s own doc for why these
162 * are appended after ma_length, not inserted
163 * into the base 24-byte layout. */
164 env.v_train = v_train;
165 env.m_mode = m_mode;
166 ctc_wire_encode(out, &env);
167}
168
169uint8_t ab_ga_ctc_build_outputs(ab_gp_train_session_t *sessions, ab_gp_db_t *db,
170 ab_gp_ctc_pending_output_t out[AB_GP_CTC_MAX_PENDING_OUTPUTS])
171{
172 uint8_t count = 0U;
173 uint8_t i;
174
175 for (i = 0U; i < (uint8_t)SAFEAPI_EXAMPLE_MAX_TRAINS; i++)
176 {
177 uint8_t train_id = (uint8_t)(i + 1U);
178 /* Every field this loop reads below (in_use/ctc_ma_granted_sent/
179 * d_lrbg/ma_pending_send/ctc_ma_notify_pending/ma_seq/
180 * granted_length) now comes from this ONE context read - the
181 * individual session getters this used to call one field at a
182 * time are gone (later session, on direct request). */
183 ab_gp_train_context_t tctx;
184
185 (void)ab_gp_get_train_context(sessions, db, train_id, &tctx);
186 /* CTC_CONNECTED: re-emitted every should_forward_to_c cycle from
187 * connect until the train's first CTC_MA_GRANTED supersedes it
188 * (was a one-shot latch on ctc_connected_sent). A one-shot fire
189 * is lost outright if C's own sim-facing link is not up yet the
190 * exact cycle it goes out - a real race at env startup, worse now
191 * that every train's P0 co-arrives on one multiplexed link
192 * (ADR-036) and C's CTC gateway is its own process (ADR-037). The
193 * CTC sim de-dups by nid_engine ("not a queue", DESIGN.md 4.2),
194 * and this branch stops as soon as CTC_MA_GRANTED starts, so a
195 * connected train with an MA emits exactly one CTC frame/cycle -
196 * count stays within AB_GP_CTC_MAX_PENDING_OUTPUTS (MAX_TRAINS*2). */
197 if (tctx.in_use && !tctx.ctc_ma_granted_sent)
198 {
199 ab_ga_ctc_build_connected(out[count].bytes, train_id, tctx.d_lrbg);
200 sapi_mem_copy(out[count].tag, "CTC_CONNECTED", sizeof("CTC_CONNECTED"));
201 count++;
202 (void)ab_gp_train_session_set_ctc_connected_sent(sessions, train_id, true);
203 }
204 /* ctc_ma_notify_pending: the real Subset-026/ERTMS MA-grant path
205 * (ab_gp_proc_dispatch.c's handle_msg_132()) sets THIS instead of
206 * ma_pending_send, deliberately - see ab_gp_train_session_t's own
207 * doc for why the two must stay separate (ma_pending_send also
208 * drives the flat scheme's own ab_gp_train_build_outputs(), which
209 * an ERTMS grant must NOT also trigger). Either flag is enough to
210 * fire the CTC_MA_GRANTED/_EXTENDED notification below - CTC does
211 * not care which scheme actually produced the grant. */
212 if (tctx.ma_pending_send || tctx.ctc_ma_notify_pending)
213 {
214 if (!tctx.ctc_ma_granted_sent)
215 {
216 ab_ga_ctc_build_ma_granted(out[count].bytes, train_id, tctx.ma_seq, tctx.granted_length);
217 sapi_mem_copy(out[count].tag, "CTC_MA_GRANTED", sizeof("CTC_MA_GRANTED"));
218 (void)ab_gp_train_session_set_ctc_ma_granted_sent(sessions, train_id, true);
219 }
220 else
221 {
222 ab_ga_ctc_build_ma_extended(out[count].bytes, train_id, tctx.ma_seq, tctx.granted_length);
223 sapi_mem_copy(out[count].tag, "CTC_MA_EXTENDED", sizeof("CTC_MA_EXTENDED"));
224 }
225 /* ADR-034: this CTC output (MA granted/extended) is finalized
226 * here, right before GP stages it for send - see
227 * ab_ga_il.c's own AB_GA_CHECKPOINT_MARK() call for why. */
228 AB_GA_CHECKPOINT_MARK();
229 count++;
230 }
231
232 /* RBC_MSG_CTC_TRAIN_INFO: reactive, not a per-cycle poll+diff scan
233 * (interface-simplification pass - see this module's own header
234 * doc). g_train_info_pending[]/g_last_train_ctx[] are set by
235 * ab_ga_ctc_on_train_context_changed() below, itself called only
236 * when GP's own push notification
237 * (ab_gp_register_train_context_notify()) fires a REAL change -
238 * no more per-train getter calls or "did anything change since
239 * last sent" comparison here at all. */
240 if (tctx.in_use && g_train_info_pending[i])
241 {
242 const ab_gp_train_context_t *ctx = &g_last_train_ctx[i];
243 uint16_t front_signal = 0U;
244 uint32_t dist_to_front = 0U;
245 uint16_t target_signal = 0U;
246 bool ma_granted = ctx->has_ma;
247
248 compute_train_info_signals(ctx->route_ids, ctx->route_count, ctx->d_lrbg, &front_signal, &dist_to_front,
249 &target_signal);
250 ab_ga_ctc_build_train_info(out[count].bytes, train_id, ctx->d_lrbg, ctx->ma_seq, ctx->granted_length,
251 ma_granted, front_signal, dist_to_front, target_signal, ctx->nid_lrbg,
252 ctx->v_train, ctx->m_mode);
253 sapi_mem_copy(out[count].tag, "CTC_TRAIN_INFO", sizeof("CTC_TRAIN_INFO"));
254 count++;
255 g_train_info_pending[i] = false;
256 }
257 }
258 return count;
259}
260
261
262/****Local functions ****/
263
264void ab_ga_ctc_on_route_context_changed(const ab_gp_route_context_t *ctx, ab_gp_route_update_type_t update_type)
265{
266 extern char *g_ga_role_tag; /* GA-wide, set once at ab_ga_ma_logic_adaptation_init() -
267 * see that file's own definition; used for logging only,
268 * same as every other GA module. */
269
270 if (update_type != AB_ROUTE_CONNECTED)
271 {
272 return; /* CTC only ever logged the connect side - see this file's own module doc */
273 }
274 SAFEAPI_EXAMPLE_LOG("[%s] CTC notified: route %u connected to train %u\n", g_ga_role_tag,
275 (unsigned int)ctx->id, (unsigned int)ctx->train_id);
276}
277
278void ab_ga_ctc_on_train_context_changed(const ab_gp_train_context_t *ctx, ab_gp_train_update_type_t update_type)
279{
280 uint8_t idx;
281 bool d_lrbg_changed;
282 bool nid_lrbg_changed;
283 bool v_train_changed;
284 bool m_mode_changed;
285 bool granted_length_changed;
286 bool ma_seq_changed;
287 bool has_ma_changed;
288
289 (void)update_type;
290 if ((ctx->train_id == 0U) || (ctx->train_id > (uint8_t)SAFEAPI_EXAMPLE_MAX_TRAINS))
291 {
292 return;
293 }
294 idx = ctx->train_id - 1U;
295
296 /* GP fires this notification on EVERY M136 (position report),
297 * whether or not anything actually changed - a stationary train
298 * still reports periodically. Comparing against the last-KNOWN
299 * context here (not GP's own responsibility any more, see this
300 * file's own module doc) is what keeps CTC_TRAIN_INFO genuinely
301 * on-change - without this comparison, a stationary/idle train would
302 * get re-sent every single M136 cycle, exactly the poll-and-resend
303 * behavior this whole redesign was meant to remove. front_signal/
304 * target_signal/dist_to_front are NOT compared here (they are not
305 * part of ab_gp_train_context_t - ab_ga_ctc_build_outputs() computes
306 * them fresh from the route chain each time it actually sends) - a
307 * route-boundary-only change with every other field unchanged is
308 * covered by AB_ROUTE_CONNECTED/_DISCONNECTED already re-arming
309 * g_train_info_pending via handle_route_add()'s/_release()'s own
310 * explicit AB_TRAIN_MA_CHANGED trigger (granted_length/ma_seq always
311 * change alongside a route boundary change too). */
312 if (!g_train_ctx_known[idx])
313 {
314 g_last_train_ctx[idx] = *ctx;
315 g_train_ctx_known[idx] = true;
316 g_train_info_pending[idx] = true; /* first-ever context for this train - always send */
317 return;
318 }
319
320 d_lrbg_changed = (ctx->d_lrbg != g_last_train_ctx[idx].d_lrbg);
321 nid_lrbg_changed = (ctx->nid_lrbg != g_last_train_ctx[idx].nid_lrbg);
322 v_train_changed = (ctx->v_train != g_last_train_ctx[idx].v_train);
323 m_mode_changed = (ctx->m_mode != g_last_train_ctx[idx].m_mode);
324 granted_length_changed = (ctx->granted_length != g_last_train_ctx[idx].granted_length);
325 ma_seq_changed = (ctx->ma_seq != g_last_train_ctx[idx].ma_seq);
326 has_ma_changed = (ctx->has_ma != g_last_train_ctx[idx].has_ma);
327
328 g_last_train_ctx[idx] = *ctx;
329 if (d_lrbg_changed || nid_lrbg_changed || v_train_changed || m_mode_changed || granted_length_changed ||
330 ma_seq_changed || has_ma_changed)
331 {
332 g_train_info_pending[idx] = true;
333 }
334}
335
343static void compute_train_info_signals(const uint16_t route_ids[SAFEAPI_EXAMPLE_MAX_ROUTES_PER_TRAIN],
344 uint8_t route_count, uint32_t d_lrbg, uint16_t *out_front_signal,
345 uint32_t *out_dist_to_front, uint16_t *out_target_signal)
346{
347 uint32_t cumulative = 0U;
348 bool front_found = false;
349 uint16_t cur_id;
350 uint8_t visited;
351
352 *out_front_signal = 0U;
353 *out_dist_to_front = 0U;
354 *out_target_signal = 0U;
355
356 if (route_count == 0U)
357 {
358 return;
359 }
360
361 /* Chain head = the held route whose prev_route_id is NOT itself held
362 * - route_ids[]'s own array order is not a documented ordering
363 * guarantee, so this walks ab_siteGA.h's real prev/next_route_id
364 * chain instead of assuming array order matches grant/path order. */
365 cur_id = 0U;
366 for (visited = 0U; visited < route_count; visited++)
367 {
368 const ab_site_ga_route_layout_t *rt = ab_site_ga_get_route(route_ids[visited]);
369 bool prev_is_held = false;
370 uint8_t j;
371
372 if (rt == NULL)
373 {
374 continue;
375 }
376 for (j = 0U; j < route_count; j++)
377 {
378 if (route_ids[j] == rt->prev_route_id)
379 {
380 prev_is_held = true;
381 }
382 }
383 if (!prev_is_held)
384 {
385 cur_id = route_ids[visited];
386 }
387 }
388
389 /* Walk the chain forward from the head, accumulating length, to find
390 * both the front signal (first not-yet-reached boundary) and the MA
391 * target signal (end of the last held route visited). Bounded by
392 * route_count so a corrupt/cyclic next_route_id chain can't loop
393 * forever. */
394 for (visited = 0U; (visited < route_count) && (cur_id != 0U); visited++)
395 {
397 uint32_t boundary;
398 uint16_t next_id;
399 uint8_t j;
400
401 if (rt == NULL)
402 {
403 break;
404 }
405 boundary = cumulative + rt->length_m;
406 if (!front_found && (d_lrbg < boundary))
407 {
408 *out_front_signal = rt->end_signal;
409 *out_dist_to_front = boundary - d_lrbg;
410 front_found = true;
411 }
412 *out_target_signal = rt->end_signal;
413 cumulative = boundary;
414
415 next_id = 0U;
416 for (j = 0U; j < route_count; j++)
417 {
418 if (route_ids[j] == rt->next_route_id)
419 {
420 next_id = route_ids[j];
421 }
422 }
423 cur_id = next_id;
424 }
425
426 if (!front_found)
427 {
428 /* Train already past every held route's own boundary (or the
429 * held-route data disagrees with d_lrbg) - report the MA target
430 * itself as the front signal, distance 0, rather than leaving
431 * stale zeros that would misleadingly read as "no MA". */
432 *out_front_signal = *out_target_signal;
433 *out_dist_to_front = 0U;
434 }
435}
436
437static void ctc_wire_encode(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], const rbc_envelope_t *env)
438{
439 sapi_buffer_t buf;
440 /* RBC_MSG_CTC_TRAIN_INFO alone also carries nid_lrbg/v_train/m_mode -
441 * these are NOT appended after the base 24-byte content at a
442 * CTC-local offset; every field in this shared envelope lives at
443 * one fixed, kind-independent byte offset across EVERY kind
444 * (rbc_wire_types.h's own file doc, and SimCore's rbc_wire.py's own
445 * near-identical doc: "aliasing different kinds' own extension
446 * fields onto the same wire bytes" is exactly what NOT branching on
447 * kind for field position prevents) - so these three go at the SAME
448 * offsets M136 already defines for them (40/64/72 - skipping
449 * t_train_ack/q_dirlrbg-through-q_length/q_dirtrain, which this kind
450 * leaves at zero), not sequential ones. Found live: an earlier
451 * attempt at this exact addition used sequential CTC-local offsets
452 * instead, landing nid_lrbg on top of t_train_ack's own wire slot
453 * and v_train/m_mode on top of nid_lrbg/q_dirlrbg's - every existing
454 * consumer of those M136 fields would have silently decoded garbage
455 * had any kind ever mixed them with a CTC_TRAIN_INFO reader on the
456 * same session. */
457 bool is_train_info = (env->kind == RBC_MSG_CTC_TRAIN_INFO);
458 /* l_message must cover through m_mode's own offset (72-75) for
459 * THIS kind - every other CTC_* kind's l_message is unchanged. */
460 uint16_t l_message = is_train_info ? 76U : (uint16_t)(CTC_WIRE_HEADER_SIZE + CTC_WIRE_CONTENT_SIZE_BASE);
461
462 sapi_mem_set(out, 0, RBC_ENVELOPE_WIRE_SIZE);
463 (void)sapi_buffer_init(&buf, out, RBC_ENVELOPE_WIRE_SIZE);
464 out[0] = (uint8_t)env->kind;
465 out[1] = env->train_id;
466 out[2] = 0U; /* no real Subset-026 nid_message for any CTC_* kind */
467 out[3] = 0U; /* reserved */
468 (void)sapi_buffer_set_length(&buf, 4U);
469 (void)sapi_buffer_write_u16_le(&buf, l_message); /* offset 4-5 */
470 (void)sapi_buffer_write_u16_le(&buf, 0U); /* offset 6-7, reserved */
471 (void)sapi_buffer_write_u32_le(&buf, env->t_train); /* offset 8-11 - alarm's own timestamp_ms, 0 for
472 * every other CTC_* kind */
473 (void)sapi_buffer_write_u32_le(&buf, env->cycle); /* offset 12-15 - alarm's own cycle, 0 for every
474 * other CTC_* kind, see this file's own header
475 * for why the offset stays */
476 (void)sapi_buffer_write_u32_le(&buf, env->d_lrbg); /* offset 16-19 */
477 (void)sapi_buffer_write_u32_le(&buf, env->msg_type); /* offset 20-23 - alarm's own rbc_alarm_severity_t,
478 * 0 for every other CTC_* kind */
479 (void)sapi_buffer_write_u32_le(&buf, env->route_len); /* offset 24-27 - not CTC's own field - always 0
480 * for every kind except TRAIN_INFO's own reuse */
481 (void)sapi_buffer_write_u32_le(&buf, env->ma_seq); /* offset 28-31 - alarm's own numeric code; MA_GRANTED/
482 * _EXTENDED's own MA sequence number for those kinds */
483 (void)sapi_buffer_write_u32_le(&buf, env->ma_length); /* offset 32-35 */
484 if (is_train_info)
485 {
486 /* offset 36-39 (t_train_ack) left zero - not this kind's field. */
487 (void)sapi_buffer_set_length(&buf, 40U);
488 (void)sapi_buffer_write_u32_le(&buf, env->nid_lrbg); /* offset 40-43, M136's own canonical slot */
489 /* offset 44-63 (q_dirlrbg/q_dlrbg/l_doubtover/l_doubtunder/
490 * q_length) left zero - not this kind's fields. */
491 (void)sapi_buffer_set_length(&buf, 64U);
492 (void)sapi_buffer_write_u32_le(&buf, env->v_train); /* offset 64-67, M136's own canonical slot */
493 /* offset 68-71 (q_dirtrain) left zero - not this kind's field. */
494 (void)sapi_buffer_set_length(&buf, 72U);
495 (void)sapi_buffer_write_u32_le(&buf, env->m_mode); /* offset 72-75, M136's own canonical slot */
496 }
497}
void ab_ga_ctc_build_connected(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], uint8_t train_id, uint32_t d_lrbg)
Builds and wire-encodes the outbound CTC_CONNECTED indication for train_id (kind=RBC_MSG_CTC_CONNECTE...
Definition ab_ga_ctc.c:92
void ab_ga_ctc_build_ma_granted(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], uint8_t train_id, uint32_t ma_seq, uint32_t ma_length)
Builds and wire-encodes the outbound CTC_MA_GRANTED indication for train_id (kind=RBC_MSG_CTC_MA_GRAN...
Definition ab_ga_ctc.c:103
static void compute_train_info_signals(const uint16_t route_ids[SAFEAPI_EXAMPLE_MAX_ROUTES_PER_TRAIN], uint8_t route_count, uint32_t d_lrbg, uint16_t *out_front_signal, uint32_t *out_dist_to_front, uint16_t *out_target_signal)
Definition ab_ga_ctc.c:343
static void ctc_wire_encode(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], const rbc_envelope_t *env)
Definition ab_ga_ctc.c:437
void ab_ga_ctc_build_train_info(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], uint8_t train_id, uint32_t d_lrbg, uint32_t ma_seq, uint32_t granted_length, bool ma_granted, uint16_t front_signal, uint32_t dist_to_front_signal, uint16_t target_signal, uint32_t nid_lrbg, uint32_t v_train, uint32_t m_mode)
Builds and wire-encodes a severity-leveled operational alarm (kind=RBC_MSG_CTC_ALARM) directly into o...
Definition ab_ga_ctc.c:132
#define CTC_WIRE_HEADER_SIZE
Definition ab_ga_ctc.c:28
uint8_t ab_ga_ctc_build_outputs(ab_gp_train_session_t *sessions, ab_gp_db_t *db, ab_gp_ctc_pending_output_t out[AB_GP_CTC_MAX_PENDING_OUTPUTS])
Decides which trains need a CTC indication THIS cycle and builds all of them - see this file's own mo...
Definition ab_ga_ctc.c:169
void ab_ga_ctc_on_train_context_changed(const ab_gp_train_context_t *ctx, ab_gp_train_update_type_t update_type)
GA's dispatch module fans every train-context change here - stores the received snapshot and marks th...
Definition ab_ga_ctc.c:278
static bool g_train_ctx_known[SAFEAPI_EXAMPLE_MAX_TRAINS]
Definition ab_ga_ctc.c:67
void ab_ga_ctc_build_ma_extended(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], uint8_t train_id, uint32_t ma_seq, uint32_t ma_length)
Builds and wire-encodes the outbound CTC_MA_EXTENDED indication for train_id (kind=RBC_MSG_CTC_MA_EXT...
Definition ab_ga_ctc.c:116
static bool g_train_info_pending[SAFEAPI_EXAMPLE_MAX_TRAINS]
Definition ab_ga_ctc.c:61
void ab_ga_ctc_on_route_context_changed(const ab_gp_route_context_t *ctx, ab_gp_route_update_type_t update_type)
GA's single dispatch module (safeAPIRBC2oo2GA/src/AB/main/ ab_ga_dispatch.c) is the ONLY thing that r...
Definition ab_ga_ctc.c:264
A/B's own outbound messages to CtcRBCSim. Two layers, same split as AB/GP/train/ab_gp_train....
char * g_ga_role_tag
GA's own site data: route composition, built from GP's raw physical elements (railML interlocking <ro...
const ab_site_ga_route_layout_t * ab_site_ga_get_route(uint16_t route_id)
Looks up a route by its ID.
One route's static layout entry (railML interlocking <route>) - GA's own full definition (not a reduc...
Definition ab_siteGA.h:69