|
SafeAPI RBC 2oo2 Test Environment
End-to-end Robot Framework test suite + Docker Compose stack for the safeAPIRBC2oo2 system
|
Status: proposed, not yet implemented - see DESIGN.md for the protocol shape (sendMessage/getMessage JSON commands) this document assumes. Field names and message kinds below are taken directly from the real wire protocol (rbc_wire_types.h, rbc_wire.py, ADR-029) - nothing here is invented; every field listed is an actual rbc_envelope_t member, and every message kind is an actual rbc_msg_kind_t value.
nidEngine/nid_engine below is always train_id on the wire (1 or 2
The only sim that both sends and receives meaningfully - it originates the train's own reports and acks, and is the target of the RBC's own decisions.
| Message | Packet | Fields | Meaning |
|---|---|---|---|
| P0 | P0 | (none) | Handshake - establishes this nid_engine with the RBC. Sent automatically once per site connection today (train_sim.py's own connect logic); exposing it via sendMessage mainly matters for tests that want to force a fresh P0 (e.g. simulating a re-handshake) rather than relying on the sim's own startup timing. |
| M136 | M136 | d_lrbg (position, meters), cycle (this train's own free-running report number) | Cyclic position report. Today's REPORT <d_lrbg> control command already does this on demand - Send Train Message with M136 is the structured equivalent, additionally letting a test set cycle explicitly rather than always using the sim's own auto-incrementing counter. |
| M146 | M146 | ma_seq (echoes the MA sequence being acknowledged) | Acks a received MA. Today sent automatically by train_sim.py immediately upon receiving an M3 - exposing it via sendMessage is mainly for fault-injection-style tests that want to test the RBC's OWN behavior when an ack is deliberately withheld or sent with a wrong ma_seq (not achievable at all with today's log-only interface). |
| Message | Packet | Fields | Meaning |
|---|---|---|---|
| M24_M15 | M24_M15 | cycle (the M136 cycle being acked), msg_type (24 or 15 - which of the two position-report acks this is; see SAFEAPI_EXAMPLE_MSG_M24/_M15, common_config.h) | Position-report ack. Today only visible as "WEST: M24 ack (cycle N)"/"M15 ack" log lines (train_sim.py) - getMessage <nid_engine> M24_M15 exposes the same fact with real fields, including telling M24 and M15 apart by msg_type rather than by which log-string substring matched. |
| M3 | M3 | ma_seq (monotonic MA sequence for this train), ma_length (cumulative granted length, meters) | Movement Authority grant/extend. Today's Train Log Should Contain ... Movement Authority - length=${N}m becomes Verify Packet <nid_engine> M3 M3 ma_length ${N} - same fact, but also makes ma_seq checkable, which the log line never exposed at all. |
| Message | Packet | Fields | Meaning |
|---|---|---|---|
| ROUTE_ADD | ROUTE_ADD | route_len (meters granted/extended by this one route) | Legacy flat-scheme route grant, route-tracking only now (MA comes from GP's own position gate). Set IL Route + Send IL Message. |
| IL_ROUTE_CMD | (dedicated, il_wire.py) | route_type {NoRoute,Locked}, route_status {NoStatus,FS,OS,SH,Used,Degraded}, degraded_status {NoStatus,Low,Medium,High}, release_route_request {No,Yes}, first_route_in_path {No,Yes}, route_id/start_signal/end_signal (int32, -1 = unset) | The full IL route command. Drives the per-route state machine (ab_ga_route_fsm.c): NO_ROUTE / LOCKED / FS / USED / release are real, OS / SH / DEGRADED are tracked-but-stubbed. Keyword: Send IL Route Command (enum args accept a name or an int; every arg's default is the spec default). |
| IL_STATUS | (dedicated, il_wire.py) | il_status {Down,Restarting,Up} | This IL's health. Announced UP at startup + every ROUTE_STATUS_PERIOD_S. Keyword: Set IL Status <down\|restarting\|up> (control command SET_IL_STATUS). The RBC's DOWN/RESTARTING hold reaction is stubbed (logged, not acted on). |
| Message | Packet | Fields | Meaning |
|---|---|---|---|
| TrainPositionInRoute | TrainPositionInRoute | start_signal, end_signal, route_status (0 noTrain / 1 trainInRoute) | Legacy liveness-first route occupancy indication. Wait For IL Message / Verify IL Packet. |
| IL_ROUTE_INDICATION | IL_ROUTE_INDICATION (flat dict, dedicated il_wire.py) | route_id, start_signal, end_signal, train_in_route (0/1), train_has_ma_in_route (0/1), allocated_train_nid_engine (-1 = none), emergency_in_route (0/1), emergency_type (-1 none / 0 SAM / 1 CEM / 2 UEM) | The richer per-route indication, pushed on every route change alongside TrainPositionInRoute. emergency_* are always "none" for now (no per-route emergency tracking wired). Keyed under getMessage by allocated_train_nid_engine. Keywords: Wait For IL Route Indication <nid_engine> / Verify IL Route Indication Field <nid_engine> <field> <expected>. |
Receive-only - CTC is a pure observer in this scenario (see ctc_sim.py's own header: "just logs whatever indications arrive").
nid_engine here identifies which train the indication is about, not a CTC identity (there is exactly one CTC instance, overseeing both sites - ctc_sim.py's own header) - getMessage against the CTC sim still takes nid_engine for symmetry with Train/IL, meaning "the indication concerning this train."
| Message | Packet | Fields | Meaning |
|---|---|---|---|
| CTC_CONNECTED | CTC_CONNECTED | d_lrbg (position at time of connection) | Train connected + its position. Today's CTC Log Should Contain ... train N connected - position Nm ... becomes Verify Packet <nid_engine> CTC_CONNECTED CTC_CONNECTED d_lrbg ${N}. |
| CTC_MA_GRANTED | CTC_MA_GRANTED | ma_seq, ma_length | Train has an MA (first grant specifically - see CTC_MA_EXTENDED below for the distinction the RBC itself already makes, channel_ab.c's own post_execute()). |
| CTC_MA_EXTENDED | CTC_MA_EXTENDED | ma_seq, ma_length | MA length updated (a subsequent grant for a train that already had one - not a fresh CTC_MA_GRANTED). Because getMessage returns only the most-recently-received instance (DESIGN.md section 4.2), a test that grants then extends an MA and wants to assert both events happened, in order, needs to Wait Train Message for CTC_MA_GRANTED before commanding the second ADD_ROUTE that produces CTC_MA_EXTENDED - sequencing the test's own steps, not something the interface enforces for it. |
None - CTC never transmits anything in this scenario.
| Field | Type (as encoded) | Appears in |
|---|---|---|
| d_lrbg | uint32, meters | M136, CTC_CONNECTED |
| cycle | uint32 | M136, M24_M15 |
| msg_type | uint32 (24 or 15) | M24_M15 |
| route_len | uint32, meters | ROUTE_ADD |
| ma_seq | uint32 | M3, M146, CTC_MA_GRANTED, CTC_MA_EXTENDED |
| ma_length | uint32, meters | M3, CTC_MA_GRANTED, CTC_MA_EXTENDED |
train_id/nid_engine and kind/message are not listed as "fields" here since they are the addressing/selection keys (sendMessage's nidEngine/message, getMessage's nidEngine/message), not part of a message's own fields/packets payload.