ILRBCSim
ADR-029 Interlocking simulator — grants/extends Movement Authority against the RBC wire protocol
Loading...
Searching...
No Matches
site_data.py
Go to the documentation of this file.
1"""site_data.py - IL sim's own tiny RailML reader.
2
3Independently re-parses safeAPIRBC2oo2SA/etc/site/ab_site.railml.xml -
4see TrainRBCSim/src/train/site_data.py's own header for the full "why a
5FOURTH independent reader, not a shared library call" rationale (matches
6the no-pipeline-coupling convention safeAPIRBC2oo2GP's/GA's own RailML
7generators already established).
8
9Unlike Train's own reader, this is genuinely NEW ground for IL - today's
10il_sim.py hardcodes no route data at all (every ROUTE_ADD's own
11start_signal/end_signal/route_len is entirely test/command-supplied, see
12that file's own header doc). This module gives IL its own real route
13table (id/name/start_signal/end_signal/length_m), the same shape
14safeAPIRBC2oo2GA/etc/scripts/generate_ab_site_ga.py's own
15ab_site_ga_route_layout_t table already carries and the SAME positional-
16id convention it uses (route/signal ids assigned by RailML document
17order, not parsed from the element's own @id string) - so a route id
18this module reports lines up numerically with what GP/GA's own C code
19means by that same id.
20"""
21
22import logging
23import os
24import xml.etree.ElementTree as ET
25
26_RAILML_NS = "https://www.railml.org/schemas/3.3"
27_SAPI_NS = "https://safeapirbc2oo2.example/schemas/sapi-ext/1"
28_NS = {"r": _RAILML_NS, "sapi": _SAPI_NS}
29
30# ILRBCSim/src/il/ -> up 3 (il, src, ILRBCSim) -> the SAPI workspace root
31# -> safeAPIRBC2oo2SA's own sibling checkout - same convention
32# TrainRBCSim/src/train/site_data.py's own DEFAULT_RAILML_PATH uses.
33_WORKSPACE_ROOT = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", ".."))
34DEFAULT_RAILML_PATH = os.path.join(_WORKSPACE_ROOT, "safeAPIRBC2oo2SA", "etc", "site", "ab_site.railml.xml")
35
36
37def routes(railml_path=None):
38 """@return a list of {"id", "name", "start_signal", "end_signal",
39 "length_m"} dicts, one per <route>, ordered and id-numbered exactly
40 the way generate_ab_site_ga.py's own parse_railml() derives them
41 (signal/route ids by document-order position, length_m read directly
42 from each route's own sapi:routeDescription/@lengthM extension - no
43 segment-length summation needed, that field is already explicit).
44 Raises on a genuinely missing/malformed RailML file - unlike Train's
45 balise_names() (a pure log-decoration convenience), a route table
46 this sim doesn't have at all today is real, load-bearing IL data
47 (this is what Phase D's own periodic route-status broadcast iterates
48 over) - a silent empty-table fallback here would make IL announce
49 "there are zero routes," which is materially wrong, not just
50 cosmetically incomplete like a missing balise name would be."""
51 path = railml_path or os.environ.get("SAPI_RAILML_PATH") or DEFAULT_RAILML_PATH
52 tree = ET.parse(path)
53 root = tree.getroot()
54 infra = root.find("r:infrastructure", _NS)
55 fi = infra.find("r:functionalInfrastructure", _NS)
56 il = root.find("r:interlocking", _NS)
57 afi = il.find("r:assetsForInterlockings/r:assetsForInterlocking", _NS)
58 routes_el = afi.find("r:routes", _NS)
59
60 signal_list = fi.find("r:signalsIS", _NS).findall("r:signalIS", _NS)
61 sig_pos_by_xmlid = {sig.get("id"): i for i, sig in enumerate(signal_list, start=1)}
62
63 result = []
64 for i, rt in enumerate(routes_el.findall("r:route", _NS), start=1):
65 entry = rt.find("r:routeEntry", _NS).get("refersTo")
66 exit_ = rt.find("r:routeExit", _NS).get("refersTo")
67 rext = rt.find("r:extensions/sapi:routeDescription", _NS)
68 result.append({
69 "id": i,
70 "name": rt.get("designator", rt.get("id", f"Route_{i}")),
71 "start_signal": sig_pos_by_xmlid[entry],
72 "end_signal": sig_pos_by_xmlid[exit_],
73 "length_m": int(rext.get("lengthM")),
74 })
75 if not result:
76 raise ValueError(f"RailML file at {path!r} parsed but yielded zero routes")
77 return result
routes(railml_path=None)
Definition site_data.py:37