|
RTE RBC 2oo2 Reference Application 0.1.0 build 0006685
SIL 4 2oo2 Dual-Site Fault-Tolerant ERTMS Radio Block Centre Reference Architecture
|
safeAPIRBC2oo2: channel A/B binary, started as role A or B, for site WEST or EAST. C is a separate binary (C/main_c.c) - see app_main_common.c for the runtime setup shared by both. This file is the whole AB channel's own composition root: it owns both how the process starts up and how its cyclic executive is wired - deliberately kept that way so a reader can open just this file and see the whole story, rather than having to also read AB/GP/com/ab_gp_channel.c to find out how the process comes up or what each cycle does. AB/GP/com/ab_gp_channel.c is the channel factory and the real per-cycle implementation this file wires onto - see that file's own header for the mechanism; this one is the narrative. More...
#include <stdbool.h>#include <stdio.h>#include <string.h>#include "rte/app/appmanager/rte_appmanager.h"#include "rte/oal/log/rte_log.h"#include "rte/oal/memory/rte_mem_util.h"#include "rte/posix_osadapter/rte_posix_osadapter.h"#include "ab_gp_channel_cycle_hooks.h"#include "../com/ab_gp_channel.h"#include "../com/ab_gp_jru_forward.h"#include "../../common/app_main_common.h"#include "../../common/rbc_util_frame.h"#include "../../common/site_config.h"#include "rte/core/rte_core_version.h"#include "rte_rbc2oo2_version.h"#include "rte_gp_run.h"Go to the source code of this file.
Functions | |
| static int | fatal_setup_step_failed (const char *step, rte_status_t status, ab_gp_channel_handle_t handle) |
| static rte_appmanager_config_t | ab_gp_channel_make_config (ab_gp_channel_handle_t handle) |
| Builds the rte_appmanager_config_t for running an already-opened, already-wired channel (ab_gp_channel_open_link() plus whichever of this file's own "Startup sequence" setup steps the caller already ran on it - see main()'s own body above). config.context is handle itself - safe to use for as long as the process keeps running (the underlying context is a static, single-instance- per-process object, never freed). | |
| static const char * | ab_gp_channel_get_name (void) |
| static const char * | ab_gp_channel_get_version (void) |
| int | rte_gp_run (int argc, char **argv) |
safeAPIRBC2oo2: channel A/B binary, started as role A or B, for site WEST or EAST. C is a separate binary (C/main_c.c) - see app_main_common.c for the runtime setup shared by both. This file is the whole AB channel's own composition root: it owns both how the process starts up and how its cyclic executive is wired - deliberately kept that way so a reader can open just this file and see the whole story, rather than having to also read AB/GP/com/ab_gp_channel.c to find out how the process comes up or what each cycle does. AB/GP/com/ab_gp_channel.c is the channel factory and the real per-cycle implementation this file wires onto - see that file's own header for the mechanism; this one is the narrative.
WEST: A <-> B EAST: A <-> B | | C C
A-WEST <-----> A-EAST (inter-site negotiation link, this channel's own) B-WEST <-----> B-EAST (inter-site negotiation link, this channel's own)
Hot standby: both sites always run their own full A/B/C group; only each site's own C tags its output ACTIVE (this site is ONLINE) or SUPPRESSED (STANDBY), per that site's own live role - negotiated directly between A and B, one independent negotiation link per channel (no standalone SITE role - see AB/GP/com/ab_gp_channel_negotiate.c, C/monitor_c_report.c, and README).
Usage: run six instances across these two binaries (role x site, in any order, in separate terminals/containers - or separate machines, once each CONNECT-role link's RTE_EXAMPLE_*_HOST_ENV is pointed at a real remote host instead of 127.0.0.1 - see common_config.h and docker-compose.yml): rte_example A WEST rte_example B WEST rte_monitor_c WEST rte_example A EAST rte_example B EAST rte_monitor_c EAST (etc/run_all.sh launches all six.)
After argv parsing and app_main_common_init() (installs SIGINT/SIGTERM handlers - see below), main() runs twelve setup steps against AB/GP/com/ab_gp_channel.c before ever calling rte_appmanager_run() - this is deliberate: ab_gp_channel_init() (the actual rte_appmanager_operations_t::init hook) is kept genuinely minimal (just resets this run's own per-cycle counters), so every one of these steps runs here instead, where a failure gets uniform cleanup via ab_gp_channel_close_link() - see that function's own doc, and ab_gp_channel.c's file header, for why that matters (rte_appmanager_run()'s own "shutdown on init failure" safety net only covers code that runs as the init() hook itself, which none of this does anymore):
ab_gp_channel_peer_rx_task_setup() - FATAL. Starts the background peer-rx task.
A and B then run their rte_appmanager loop forever (real 500ms cyclic executive), so something has to be able to stop them: app_main_common_init() installs SIGINT/SIGTERM handlers that call rte_appmanager_request_shutdown(), which the app manager checks at the top of its loop and turns into a graceful stop (ab_gp_channel_shutdown() still runs - links/watchdog/timer/task all get closed down cleanly, not just killed).
ab_gp_channel_pre_execute()/ab_gp_channel_execute()/ab_gp_channel_post_execute() (ab_gp_channel_cycle_hooks.h) - the rte_appmanager_operations_t hooks rte_appmanager_run() calls every cycle - are each their own file in this directory (pre_execute.c/execute.c/post_execute.c), not defined here: each is a short orchestrator sequencing calls into AB/GP/com/ab_gp_channel.c's own named, single-purpose step functions, which hold the real logic (that file's ab_gp_channel_context_t stays fully private to it - main/'s own files, including this one, only ever hold the opaque ab_gp_channel_handle_t returned by ab_gp_channel_open_link()). In short, each cycle: pre_execute() - gather this cycle's inputs: the latest M136 from C, the latest AB_SAMPLE from the peer, this channel's own West<->East negotiation result. execute() - the decision logic: AB/logic's route<->train connect sweep, then the actual AGREE/DISAGREE cross-compare. post_execute() - send this cycle's outputs: the peer sample (dual transfer) and, on AGREE (or SINGLE mode), the agreed M24/M15/M3/CTC_* answers forwarded to C. See ab_gp_channel.c's own file header for the full phase-by-phase breakdown (checkpoint/dual-transfer/inter-site-negotiation reasoning included) - this summary is deliberately the short version.
Definition in file main.c.
|
static |
Local makros Local types declarations Local variables declarations Global variables declarations Local function declarations
Logs step's own failing status, tears down handle via ab_gp_channel_close_link() (safe here since ab_gp_channel_open_link() has already succeeded by the time any of main()'s later setup steps can fail - see this file's own "Startup sequence" header doc), and returns the process exit code main() itself uses for every fatal setup-step failure after step 1.
|
static |
Builds the rte_appmanager_config_t for running an already-opened, already-wired channel (ab_gp_channel_open_link() plus whichever of this file's own "Startup sequence" setup steps the caller already ran on it - see main()'s own body above). config.context is handle itself - safe to use for as long as the process keeps running (the underlying context is a static, single-instance- per-process object, never freed).
| handle | A handle from a successful ab_gp_channel_open_link() call. |
|
static |
rte_appmanager_operations_t::get_name - trivial, no channel state needed, so this lives here rather than behind an accessor into ab_gp_channel.c's own private context.
|
static |
rte_appmanager_operations_t::get_version - see ab_gp_channel_get_name()'s own doc.
| int rte_gp_run | ( | int | argc, |
| char ** | argv ) |
Global functions Real entry point, exported from librte_gp (this project's own shared library, later session's own GP<->GA symmetric dummy-then-real linking pass - see safeAPIRBC2oo2GA/CLAUDE.md's own doc on why rte_example became a thin launcher over this library instead of a monolithic executable). Body unchanged from the old plain int main(int argc, char **argv) - only the name/export changed, so launcher_main.c's own int main() can call it.