|
SimCore
Shared transport-layer plumbing for the ADR-029 Train/IL/CTC RBC simulators
|
Classes | |
| class | _ControlClient |
| class | ControlServer |
Non-blocking line-based TCP command server (ADR-029) - gives any sim
built on SimCore a real TCP/IP control port, with its own dedicated
command table: `ControlServer` takes @handlers/@json_handlers as
constructor arguments rather than owning any commands itself, so
Train/IL/CTC each wire up only the commands that make sense for that
sim (e.g. Train: REPORT/PING + sendMessage/getMessage; IL: ADD_ROUTE/
PING + sendMessage; CTC: PING + getMessage only - CTC is receive-only in
this scenario) - no sim sees another sim's commands, and SimCore itself
defines none. Lets Robot Framework (safeAPITestEnv/robot/) drive a
Train/IL sim's real, test-relevant actions on demand (e.g. "add a route
now", "report this position now") instead of only ever firing on a
fixed wall-clock schedule. Robot talks to this with its own built-in
Telnet library (no extra Python dependency needed) - see
safeAPITestEnv/robot/ for the keywords that use it.
Owns its own small selectors.DefaultSelector, polled non-blockingly
(timeout=0) once per iteration of the sim's own main loop, right
alongside that loop's own dual_link.py poll - a second cheap select()
syscall per iteration, not a separate thread. One accepted control
connection is served at a time per sim, which is all a test harness
needs.
Two command styles share this one port/line-framing, distinguished by
the line's own first character:
- **Plain-text commands** (original ADR-029 protocol): one command per
line, ASCII, `NAME arg1 arg2\\n`. Unrecognized commands get
"ERR unknown command\\n"; a command's own handler decides its own
success reply (e.g. "OK\\n"). Still used by REPORT/ADD_ROUTE/PING -
unchanged.
- **JSON commands** (safeAPITestEnv/doc/design/DESIGN.md - structured
sendMessage/getMessage): a line starting with `{` is parsed as one
JSON object, `{"cmd": "<name>", ...}`; the handler receives the whole
parsed dict and returns a dict, which is sent back JSON-encoded plus
a trailing newline. Kept as a genuinely separate dispatch path (not
merged into the plain-text one by, say, treating `{"cmd":...}` as a
single whitespace-free token) specifically because a JSON payload
routinely contains internal whitespace (`{"cmd": "sendMessage", ...}`)
that plain-text's own `line.split()` would incorrectly tokenize.
Neither style is part of the RBC's own rbc_envelope_t wire protocol -
this whole channel is kept deliberately separate (different port,
different framing) so a malformed/foreign line here can never be
confused for real RBC traffic.