RTE RBC 2oo2 Generic Application 0.1.0 build 308eda7
IL/CTC route and train logic for the RBC_GP 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 "rte/utils/buffer/rte_buffer.h"
10#include "rte/oal/memory/rte_mem_util.h"
11
12#include "common_config.h" /* RTE_EXAMPLE_LOG, RTE_EXAMPLE_MAX_TRAINS,
13 * RTE_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[RTE_EXAMPLE_MAX_TRAINS];
67static bool g_train_info_built[RTE_EXAMPLE_MAX_TRAINS];
75static bool g_connected_built[RTE_EXAMPLE_MAX_TRAINS];
78static bool g_ma_granted_built[RTE_EXAMPLE_MAX_TRAINS];
79static ab_gp_train_context_t g_last_train_ctx[RTE_EXAMPLE_MAX_TRAINS];
84static bool g_train_ctx_known[RTE_EXAMPLE_MAX_TRAINS];
89static void ctc_wire_encode(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], const rbc_envelope_t *env);
99static void compute_train_info_signals(const uint16_t route_ids[RTE_EXAMPLE_MAX_ROUTES_PER_TRAIN],
100 uint8_t route_count, uint32_t d_lrbg, uint16_t *out_front_signal,
101 uint32_t *out_dist_to_front, uint16_t *out_target_signal);
102
103
105/* ab_ga_ctc_init() REMOVED - its entire body was one GP registration, now
106 * owned by ab_ga_dispatch.c's own single subscription (see this file's
107 * own module doc and ab_ga_dispatch.h). */
108
109void ab_ga_ctc_build_connected(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], uint8_t train_id, uint32_t d_lrbg)
110{
111 rbc_envelope_t env;
112
113 rte_mem_set(&env, 0, sizeof(env));
114 env.kind = RBC_MSG_CTC_CONNECTED;
115 env.train_id = train_id;
116 env.d_lrbg = d_lrbg;
117 ctc_wire_encode(out, &env);
118}
119
120void ab_ga_ctc_build_ma_granted(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], uint8_t train_id, uint32_t ma_seq,
121 uint32_t ma_length)
122{
123 rbc_envelope_t env;
124
125 rte_mem_set(&env, 0, sizeof(env));
126 env.kind = RBC_MSG_CTC_MA_GRANTED;
127 env.train_id = train_id;
128 env.ma_seq = ma_seq;
129 env.ma_length = ma_length;
130 ctc_wire_encode(out, &env);
131}
132
133void ab_ga_ctc_build_ma_extended(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], uint8_t train_id, uint32_t ma_seq,
134 uint32_t ma_length)
135{
136 rbc_envelope_t env;
137
138 rte_mem_set(&env, 0, sizeof(env));
139 env.kind = RBC_MSG_CTC_MA_EXTENDED;
140 env.train_id = train_id;
141 env.ma_seq = ma_seq;
142 env.ma_length = ma_length;
143 ctc_wire_encode(out, &env);
144}
145
146/* ab_ga_ctc_build_alarm() - MOVED to GP (AB/GP/main/ab_gp_ga_hooks.c's own
147 * ab_gp_build_ctc_alarm()), later session, on direct request. */
148
149void ab_ga_ctc_build_train_info(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], uint8_t train_id, uint32_t d_lrbg,
150 uint32_t ma_seq, uint32_t granted_length, bool ma_granted,
151 uint16_t front_signal, uint32_t dist_to_front_signal, uint16_t target_signal,
152 uint32_t nid_lrbg, uint32_t v_train, uint32_t m_mode)
153{
154 rbc_envelope_t env;
155 int32_t ma_offset;
156
157 rte_mem_set(&env, 0, sizeof(env));
158 env.kind = RBC_MSG_CTC_TRAIN_INFO;
159 env.train_id = train_id;
160 env.d_lrbg = d_lrbg;
161 env.ma_seq = ma_seq;
162 env.msg_type = ma_granted ? 1U : 0U; /* ma_status: 0=NONE, 1=GRANTED - see this
163 * kind's own doc, rbc_wire_types.h. */
164 env.route_len = (uint32_t)target_signal; /* MA target signal - reuses the slot that's
165 * otherwise always 0 for every CTC_* kind. */
166 env.t_train = (uint32_t)front_signal; /* front signal - reuses alarm's own timestamp
167 * slot, 0 for every other kind. */
168 env.cycle = dist_to_front_signal; /* distance to front signal - reuses alarm's
169 * own cycle slot. */
170 ma_offset = (int32_t)d_lrbg - (int32_t)granted_length; /* negative while approaching, 0 at
171 * the limit - see this kind's own
172 * doc for why "MA length in
173 * relation to balise" is not a
174 * separate field (it is -ma_offset). */
175 env.ma_length = (uint32_t)ma_offset; /* signed value, two's-complement bit pattern -
176 * decode as (int32_t) on the reading side. */
177 env.nid_lrbg = nid_lrbg; /* appended fields (on direct request) - see
178 * ctc_wire_encode()'s own doc for why these
179 * are appended after ma_length, not inserted
180 * into the base 24-byte layout. */
181 env.v_train = v_train;
182 env.m_mode = m_mode;
183 ctc_wire_encode(out, &env);
184}
185
186uint8_t ab_ga_ctc_build_outputs(const ab_gp_train_session_t *sessions, ab_gp_db_t *db,
187 ab_gp_ctc_pending_output_t out[AB_GP_CTC_MAX_PENDING_OUTPUTS])
188{
189 uint8_t count = 0U;
190 uint8_t i;
191
192 /* ISS-047: what an earlier, never-confirmed build marked must not be
193 * applied by a later confirm of a build without that output (e.g.
194 * after GP reset the latches for a new session). */
195 for (i = 0U; i < (uint8_t)RTE_EXAMPLE_MAX_TRAINS; i++)
196 {
197 g_connected_built[i] = false;
198 g_ma_granted_built[i] = false;
199 }
200
201 for (i = 0U; i < (uint8_t)RTE_EXAMPLE_MAX_TRAINS; i++)
202 {
203 uint8_t train_id = (uint8_t)(i + 1U);
204 /* Every field this loop reads below (in_use/ctc_ma_granted_sent/
205 * d_lrbg/ma_pending_send/ctc_ma_notify_pending/ma_seq/
206 * granted_length) now comes from this ONE context read - the
207 * individual session getters this used to call one field at a
208 * time are gone (later session, on direct request). */
209 ab_gp_train_context_t tctx;
210
211 (void)ab_gp_get_train_context(sessions, db, train_id, &tctx);
212 /* CTC_CONNECTED: re-emitted every should_forward_to_c cycle from
213 * connect until the train's first CTC_MA_GRANTED supersedes it
214 * (was a one-shot latch on ctc_connected_sent). A one-shot fire
215 * is lost outright if C's own sim-facing link is not up yet the
216 * exact cycle it goes out - a real race at env startup, worse now
217 * that every train's P0 co-arrives on one multiplexed link
218 * (ADR-036) and C's CTC gateway is its own process (ADR-037). The
219 * CTC sim de-dups by nid_engine ("not a queue", DESIGN.md 4.2),
220 * and this branch stops as soon as CTC_MA_GRANTED starts, so a
221 * connected train with an MA emits exactly one CTC frame/cycle -
222 * count stays within AB_GP_CTC_MAX_PENDING_OUTPUTS (MAX_TRAINS*2). */
223 if (tctx.in_use && !tctx.ctc_ma_granted_sent)
224 {
225 ab_ga_ctc_build_connected(out[count].bytes, train_id, tctx.d_lrbg);
226 rte_mem_copy(out[count].tag, "CTC_CONNECTED", sizeof("CTC_CONNECTED"));
227 count++;
228 g_connected_built[i] = true; /* latched at confirm, not here (ISS-047) */
229 }
230 /* ctc_ma_notify_pending: the real Subset-026/ERTMS MA-grant path
231 * (ab_gp_proc_dispatch.c's handle_msg_132()) sets THIS instead of
232 * ma_pending_send, deliberately - see ab_gp_train_session_t's own
233 * doc for why the two must stay separate (ma_pending_send also
234 * drives the flat scheme's own ab_gp_train_build_outputs(), which
235 * an ERTMS grant must NOT also trigger). Either flag is enough to
236 * fire the CTC_MA_GRANTED/_EXTENDED notification below - CTC does
237 * not care which scheme actually produced the grant. */
238 if (tctx.ma_pending_send || tctx.ctc_ma_notify_pending)
239 {
240 if (!tctx.ctc_ma_granted_sent)
241 {
242 ab_ga_ctc_build_ma_granted(out[count].bytes, train_id, tctx.ma_seq, tctx.granted_length);
243 rte_mem_copy(out[count].tag, "CTC_MA_GRANTED", sizeof("CTC_MA_GRANTED"));
244 g_ma_granted_built[i] = true; /* latched at confirm, not here (ISS-047): a build
245 * that is not forwarded is rebuilt as GRANTED */
246 }
247 else
248 {
249 ab_ga_ctc_build_ma_extended(out[count].bytes, train_id, tctx.ma_seq, tctx.granted_length);
250 rte_mem_copy(out[count].tag, "CTC_MA_EXTENDED", sizeof("CTC_MA_EXTENDED"));
251 }
252 /* ADR-034: this CTC output (MA granted/extended) is finalized
253 * here, right before GP stages it for send - see
254 * ab_ga_il.c's own AB_GA_CHECKPOINT_MARK() call for why. */
255 AB_GA_CHECKPOINT_MARK();
256 count++;
257 }
258
259 /* RBC_MSG_CTC_TRAIN_INFO: reactive, not a per-cycle poll+diff scan
260 * (interface-simplification pass - see this module's own header
261 * doc). g_train_info_pending[]/g_last_train_ctx[] are set by
262 * ab_ga_ctc_on_train_context_changed() below, itself called only
263 * when GP's own push notification
264 * (ab_gp_register_train_context_notify()) fires a REAL change -
265 * no more per-train getter calls or "did anything change since
266 * last sent" comparison here at all. */
267 if (tctx.in_use && g_train_info_pending[i])
268 {
269 const ab_gp_train_context_t *ctx = &g_last_train_ctx[i];
270 uint16_t front_signal = 0U;
271 uint32_t dist_to_front = 0U;
272 uint16_t target_signal = 0U;
273 bool ma_granted = ctx->has_ma;
274
275 compute_train_info_signals(ctx->route_ids, ctx->route_count, ctx->d_lrbg, &front_signal, &dist_to_front,
276 &target_signal);
277 ab_ga_ctc_build_train_info(out[count].bytes, train_id, ctx->d_lrbg, ctx->ma_seq, ctx->granted_length,
278 ma_granted, front_signal, dist_to_front, target_signal, ctx->nid_lrbg,
279 ctx->v_train, ctx->m_mode);
280 rte_mem_copy(out[count].tag, "CTC_TRAIN_INFO", sizeof("CTC_TRAIN_INFO"));
281 count++;
282 g_train_info_built[i] = true;
283 }
284 }
285 return count;
286}
287
288void ab_ga_ctc_confirm_outputs_sent(ab_gp_train_session_t *sessions)
289{
290 uint8_t i;
291
292 for (i = 0U; i < (uint8_t)RTE_EXAMPLE_MAX_TRAINS; i++)
293 {
294 uint8_t train_id = (uint8_t)(i + 1U);
295
296 if (g_connected_built[i])
297 {
298 if (sessions != NULL)
299 {
300 (void)ab_gp_train_session_set_ctc_connected_sent(sessions, train_id, true);
301 }
302 g_connected_built[i] = false;
303 }
304 if (g_ma_granted_built[i])
305 {
306 if (sessions != NULL)
307 {
308 (void)ab_gp_train_session_set_ctc_ma_granted_sent(sessions, train_id, true);
309 }
310 g_ma_granted_built[i] = false;
311 }
312 if (g_train_info_built[i])
313 {
314 g_train_info_pending[i] = false;
315 g_train_info_built[i] = false;
316 }
317 }
318}
319
320
321/****Local functions ****/
322
323void ab_ga_ctc_on_route_context_changed(const ab_gp_route_context_t *ctx, ab_gp_route_update_type_t update_type)
324{
325 extern char *g_ga_role_tag; /* GA-wide, set once at ab_ga_ma_logic_adaptation_init() -
326 * see that file's own definition; used for logging only,
327 * same as every other GA module. */
328
329 if (update_type != AB_ROUTE_CONNECTED)
330 {
331 return; /* CTC only ever logged the connect side - see this file's own module doc */
332 }
333 RTE_EXAMPLE_LOG("[%s] CTC notified: route %u connected to train %u\n", g_ga_role_tag,
334 (unsigned int)ctx->id, (unsigned int)ctx->train_id);
335}
336
337void ab_ga_ctc_on_train_context_changed(const ab_gp_train_context_t *ctx, ab_gp_train_update_type_t update_type)
338{
339 uint8_t idx;
340 bool d_lrbg_changed;
341 bool nid_lrbg_changed;
342 bool v_train_changed;
343 bool m_mode_changed;
344 bool granted_length_changed;
345 bool ma_seq_changed;
346 bool has_ma_changed;
347
348 (void)update_type;
349 if ((ctx->train_id == 0U) || (ctx->train_id > (uint8_t)RTE_EXAMPLE_MAX_TRAINS))
350 {
351 return;
352 }
353 idx = (uint8_t)(ctx->train_id - 1U);
354
355 if (!ctx->in_use)
356 {
357 /* Train disconnected/removed - GP's own session/db state for this
358 * slot is fully zeroed by now (ab_gp_train_remove(), see
359 * ab_gp_train.c's RBC_MSG_TRAIN_DISCONNECT handling), but
360 * g_last_train_ctx[]/g_train_ctx_known[] are a SEPARATE, GA-local
361 * comparison cache GP has no way to reach - without this reset
362 * they silently survive the disconnect, so the next real
363 * connection for this same train_id slot (a genuine reconnect, or
364 * - in the Robot suite - the next test file reusing the same
365 * nid_engine) gets its first CTC_TRAIN_INFO telemetry diffed
366 * against this now-stale leftover snapshot instead of being
367 * treated as a first-ever context. Found live: exactly this
368 * caused CTC_TRAIN_INFO to go missing or report stale fields
369 * (nid_lrbg stuck at an old value) only when a test ran after
370 * another test had used the same train slot, never in isolation -
371 * see ISSUES.md's cross-test state accumulation entry. */
372 g_train_ctx_known[idx] = false;
373 g_train_info_pending[idx] = false;
374 return;
375 }
376
377 /* GP fires this notification on EVERY M136 (position report),
378 * whether or not anything actually changed - a stationary train
379 * still reports periodically. Comparing against the last-KNOWN
380 * context here (not GP's own responsibility any more, see this
381 * file's own module doc) is what keeps CTC_TRAIN_INFO genuinely
382 * on-change - without this comparison, a stationary/idle train would
383 * get re-sent every single M136 cycle, exactly the poll-and-resend
384 * behavior this whole redesign was meant to remove. front_signal/
385 * target_signal/dist_to_front are NOT compared here (they are not
386 * part of ab_gp_train_context_t - ab_ga_ctc_build_outputs() computes
387 * them fresh from the route chain each time it actually sends) - a
388 * route-boundary-only change with every other field unchanged is
389 * covered by AB_ROUTE_CONNECTED/_DISCONNECTED already re-arming
390 * g_train_info_pending via handle_route_add()'s/_release()'s own
391 * explicit AB_TRAIN_MA_CHANGED trigger (granted_length/ma_seq always
392 * change alongside a route boundary change too). */
393 if (!g_train_ctx_known[idx])
394 {
395 g_last_train_ctx[idx] = *ctx;
396 g_train_ctx_known[idx] = true;
397 g_train_info_pending[idx] = true; /* first-ever context for this train - always send */
398 return;
399 }
400
401 d_lrbg_changed = (ctx->d_lrbg != g_last_train_ctx[idx].d_lrbg);
402 nid_lrbg_changed = (ctx->nid_lrbg != g_last_train_ctx[idx].nid_lrbg);
403 v_train_changed = (ctx->v_train != g_last_train_ctx[idx].v_train);
404 m_mode_changed = (ctx->m_mode != g_last_train_ctx[idx].m_mode);
405 granted_length_changed = (ctx->granted_length != g_last_train_ctx[idx].granted_length);
406 ma_seq_changed = (ctx->ma_seq != g_last_train_ctx[idx].ma_seq);
407 has_ma_changed = (ctx->has_ma != g_last_train_ctx[idx].has_ma);
408
409 g_last_train_ctx[idx] = *ctx;
410 if (d_lrbg_changed || nid_lrbg_changed || v_train_changed || m_mode_changed || granted_length_changed ||
411 ma_seq_changed || has_ma_changed)
412 {
413 g_train_info_pending[idx] = true;
414 }
415}
416
424static void compute_train_info_signals(const uint16_t route_ids[RTE_EXAMPLE_MAX_ROUTES_PER_TRAIN],
425 uint8_t route_count, uint32_t d_lrbg, uint16_t *out_front_signal,
426 uint32_t *out_dist_to_front, uint16_t *out_target_signal)
427{
428 uint32_t cumulative = 0U;
429 bool front_found = false;
430 uint16_t cur_id;
431 uint8_t visited;
432
433 *out_front_signal = 0U;
434 *out_dist_to_front = 0U;
435 *out_target_signal = 0U;
436
437 if (route_count == 0U)
438 {
439 return;
440 }
441
442 /* Chain head = the held route whose prev_route_id is NOT itself held
443 * - route_ids[]'s own array order is not a documented ordering
444 * guarantee, so this walks ab_siteGA.h's real prev/next_route_id
445 * chain instead of assuming array order matches grant/path order. */
446 cur_id = 0U;
447 for (visited = 0U; visited < route_count; visited++)
448 {
449 const ab_site_ga_route_layout_t *rt = ab_site_ga_get_route(route_ids[visited]);
450 bool prev_is_held = false;
451 uint8_t j;
452
453 if (rt == NULL)
454 {
455 continue;
456 }
457 for (j = 0U; j < route_count; j++)
458 {
459 if (route_ids[j] == rt->prev_route_id)
460 {
461 prev_is_held = true;
462 }
463 }
464 if (!prev_is_held)
465 {
466 cur_id = route_ids[visited];
467 }
468 }
469
470 /* Walk the chain forward from the head, accumulating length, to find
471 * both the front signal (first not-yet-reached boundary) and the MA
472 * target signal (end of the last held route visited). Bounded by
473 * route_count so a corrupt/cyclic next_route_id chain can't loop
474 * forever. */
475 for (visited = 0U; (visited < route_count) && (cur_id != 0U); visited++)
476 {
478 uint32_t boundary;
479 uint16_t next_id;
480 uint8_t j;
481
482 if (rt == NULL)
483 {
484 break;
485 }
486 boundary = cumulative + rt->length_m;
487 if (!front_found && (d_lrbg < boundary))
488 {
489 *out_front_signal = rt->end_signal;
490 *out_dist_to_front = boundary - d_lrbg;
491 front_found = true;
492 }
493 *out_target_signal = rt->end_signal;
494 cumulative = boundary;
495
496 next_id = 0U;
497 for (j = 0U; j < route_count; j++)
498 {
499 if (route_ids[j] == rt->next_route_id)
500 {
501 next_id = route_ids[j];
502 }
503 }
504 cur_id = next_id;
505 }
506
507 if (!front_found)
508 {
509 /* Train already past every held route's own boundary (or the
510 * held-route data disagrees with d_lrbg) - report the MA target
511 * itself as the front signal, distance 0, rather than leaving
512 * stale zeros that would misleadingly read as "no MA". */
513 *out_front_signal = *out_target_signal;
514 *out_dist_to_front = 0U;
515 }
516}
517
518static void ctc_wire_encode(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], const rbc_envelope_t *env)
519{
520 rte_buffer_t buf;
521 /* RBC_MSG_CTC_TRAIN_INFO alone also carries nid_lrbg/v_train/m_mode -
522 * these are NOT appended after the base 24-byte content at a
523 * CTC-local offset; every field in this shared envelope lives at
524 * one fixed, kind-independent byte offset across EVERY kind
525 * (rbc_wire_types.h's own file doc, and SimCore's rbc_wire.py's own
526 * near-identical doc: "aliasing different kinds' own extension
527 * fields onto the same wire bytes" is exactly what NOT branching on
528 * kind for field position prevents) - so these three go at the SAME
529 * offsets M136 already defines for them (40/64/72 - skipping
530 * t_train_ack/q_dirlrbg-through-q_length/q_dirtrain, which this kind
531 * leaves at zero), not sequential ones. Found live: an earlier
532 * attempt at this exact addition used sequential CTC-local offsets
533 * instead, landing nid_lrbg on top of t_train_ack's own wire slot
534 * and v_train/m_mode on top of nid_lrbg/q_dirlrbg's - every existing
535 * consumer of those M136 fields would have silently decoded garbage
536 * had any kind ever mixed them with a CTC_TRAIN_INFO reader on the
537 * same session. */
538 bool is_train_info = (env->kind == RBC_MSG_CTC_TRAIN_INFO);
539 /* l_message must cover through m_mode's own offset (72-75) for
540 * THIS kind - every other CTC_* kind's l_message is unchanged. */
541 uint16_t l_message = is_train_info ? 76U : (uint16_t)(CTC_WIRE_HEADER_SIZE + CTC_WIRE_CONTENT_SIZE_BASE);
542
543 rte_mem_set(out, 0, RBC_ENVELOPE_WIRE_SIZE);
544 (void)rte_buffer_init(&buf, out, RBC_ENVELOPE_WIRE_SIZE);
545 out[0] = (uint8_t)env->kind;
546 out[1] = env->train_id;
547 out[2] = 0U; /* no real Subset-026 nid_message for any CTC_* kind */
548 out[3] = 0U; /* reserved */
549 (void)rte_buffer_set_length(&buf, 4U);
550 (void)rte_buffer_write_u16_le(&buf, l_message); /* offset 4-5 */
551 (void)rte_buffer_write_u16_le(&buf, 0U); /* offset 6-7, reserved */
552 (void)rte_buffer_write_u32_le(&buf, env->t_train); /* offset 8-11 - alarm's own timestamp_ms, 0 for
553 * every other CTC_* kind */
554 (void)rte_buffer_write_u32_le(&buf, env->cycle); /* offset 12-15 - alarm's own cycle, 0 for every
555 * other CTC_* kind, see this file's own header
556 * for why the offset stays */
557 (void)rte_buffer_write_u32_le(&buf, env->d_lrbg); /* offset 16-19 */
558 (void)rte_buffer_write_u32_le(&buf, env->msg_type); /* offset 20-23 - alarm's own rbc_alarm_severity_t,
559 * 0 for every other CTC_* kind */
560 (void)rte_buffer_write_u32_le(&buf, env->route_len); /* offset 24-27 - not CTC's own field - always 0
561 * for every kind except TRAIN_INFO's own reuse */
562 (void)rte_buffer_write_u32_le(&buf, env->ma_seq); /* offset 28-31 - alarm's own numeric code; MA_GRANTED/
563 * _EXTENDED's own MA sequence number for those kinds */
564 (void)rte_buffer_write_u32_le(&buf, env->ma_length); /* offset 32-35 */
565 if (is_train_info)
566 {
567 /* offset 36-39 (t_train_ack) left zero - not this kind's field. */
568 (void)rte_buffer_set_length(&buf, 40U);
569 (void)rte_buffer_write_u32_le(&buf, env->nid_lrbg); /* offset 40-43, M136's own canonical slot */
570 /* offset 44-63 (q_dirlrbg/q_dlrbg/l_doubtover/l_doubtunder/
571 * q_length) left zero - not this kind's fields. */
572 (void)rte_buffer_set_length(&buf, 64U);
573 (void)rte_buffer_write_u32_le(&buf, env->v_train); /* offset 64-67, M136's own canonical slot */
574 /* offset 68-71 (q_dirtrain) left zero - not this kind's field. */
575 (void)rte_buffer_set_length(&buf, 72U);
576 (void)rte_buffer_write_u32_le(&buf, env->m_mode); /* offset 72-75, M136's own canonical slot */
577 }
578}
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:109
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:120
static bool g_ma_granted_built[RTE_EXAMPLE_MAX_TRAINS]
Definition ab_ga_ctc.c:78
static void ctc_wire_encode(uint8_t out[RBC_ENVELOPE_WIRE_SIZE], const rbc_envelope_t *env)
Definition ab_ga_ctc.c:518
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:149
void ab_ga_ctc_confirm_outputs_sent(ab_gp_train_session_t *sessions)
Consumes what the immediately-preceding ab_ga_ctc_build_outputs() call actually included in its own o...
Definition ab_ga_ctc.c:288
static bool g_train_info_pending[RTE_EXAMPLE_MAX_TRAINS]
Definition ab_ga_ctc.c:61
#define CTC_WIRE_HEADER_SIZE
Definition ab_ga_ctc.c:28
static void compute_train_info_signals(const uint16_t route_ids[RTE_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:424
static bool g_train_info_built[RTE_EXAMPLE_MAX_TRAINS]
Definition ab_ga_ctc.c:67
static bool g_connected_built[RTE_EXAMPLE_MAX_TRAINS]
Definition ab_ga_ctc.c:75
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:337
uint8_t ab_ga_ctc_build_outputs(const 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:186
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:133
static bool g_train_ctx_known[RTE_EXAMPLE_MAX_TRAINS]
Definition ab_ga_ctc.c:84
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:323
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