jmri_nce.command_set
NCE command-set strategy — captures variations between firmware versions.
NCE command stations have evolved memory layouts and feature flags. The three production variants Stage 4 supports:
- PH-Pro 2006+ — full PowerPro/Smart Booster with the post-2006 binary command set; turnout/macro/consist tables at the canonical addresses.
- PowerCab — smaller command station, different turnout-memory base, same binary command opcodes.
- SB5 (Smart Booster) — booster-only variant; same memory map as PH-Pro 2006+ but a few features (e.g. macro recall) are unavailable.
The NceCommandSet dataclass captures every per-variant constant
so service code (turnout monitor, AIU poller, programmer) reads memory
addresses from the active command set rather than hard-coding.
1"""NCE command-set strategy — captures variations between firmware versions. 2 3NCE command stations have evolved memory layouts and feature flags. The 4three production variants Stage 4 supports: 5 6* **PH-Pro 2006+** — full PowerPro/Smart Booster with the post-2006 binary 7 command set; turnout/macro/consist tables at the canonical addresses. 8* **PowerCab** — smaller command station, different turnout-memory base, 9 same binary command opcodes. 10* **SB5 (Smart Booster)** — booster-only variant; same memory map as 11 PH-Pro 2006+ but a few features (e.g. macro recall) are unavailable. 12 13The :class:`NceCommandSet` dataclass captures every per-variant constant 14so service code (turnout monitor, AIU poller, programmer) reads memory 15addresses from the active command set rather than hard-coding. 16""" 17from __future__ import annotations 18 19from dataclasses import dataclass 20 21 22@dataclass(frozen=True, slots=True) 23class NceCommandSet: 24 """Per-firmware constants used by services.""" 25 26 name: str 27 turnout_memory_base: int # base of accessory/turnout status table 28 turnout_table_bytes: int # 8 turnouts per byte (256 bytes → 2048 turnouts) 29 macro_memory_base: int # base of macro table 30 consist_memory_base: int # base of consist table 31 supports_ops_mode_prog: bool 32 aiu_polling_supported: bool 33 34 35# ---- canonical instances -------------------------------------------------- 36 37 38NCE_PH_PRO_2006 = NceCommandSet( 39 name="PH-Pro 2006+", 40 turnout_memory_base=0xEC00, 41 turnout_table_bytes=256, 42 macro_memory_base=0xC800, 43 consist_memory_base=0xF500, 44 supports_ops_mode_prog=True, 45 aiu_polling_supported=True, 46) 47 48NCE_POWERCAB = NceCommandSet( 49 name="PowerCab", 50 turnout_memory_base=0xEC00, 51 turnout_table_bytes=64, # PowerCab supports fewer turnouts (~512) 52 macro_memory_base=0xC800, 53 consist_memory_base=0xF500, 54 supports_ops_mode_prog=True, 55 aiu_polling_supported=False, # AIU isn't typically used with PowerCab 56) 57 58NCE_SB5 = NceCommandSet( 59 name="Smart Booster SB5", 60 turnout_memory_base=0xEC00, 61 turnout_table_bytes=256, 62 macro_memory_base=0xC800, 63 consist_memory_base=0xF500, 64 supports_ops_mode_prog=True, 65 aiu_polling_supported=True, 66) 67 68 69COMMAND_SETS: dict[str, NceCommandSet] = { 70 cs.name: cs for cs in (NCE_PH_PRO_2006, NCE_POWERCAB, NCE_SB5) 71} 72 73 74def get_command_set(name: str) -> NceCommandSet: 75 """Look up a command set by friendly name. Raises ``KeyError`` if unknown.""" 76 if name not in COMMAND_SETS: 77 raise KeyError( 78 f"unknown NCE command set: {name!r} (have: {sorted(COMMAND_SETS)})" 79 ) 80 return COMMAND_SETS[name]
@dataclass(frozen=True, slots=True)
class
NceCommandSet:
23@dataclass(frozen=True, slots=True) 24class NceCommandSet: 25 """Per-firmware constants used by services.""" 26 27 name: str 28 turnout_memory_base: int # base of accessory/turnout status table 29 turnout_table_bytes: int # 8 turnouts per byte (256 bytes → 2048 turnouts) 30 macro_memory_base: int # base of macro table 31 consist_memory_base: int # base of consist table 32 supports_ops_mode_prog: bool 33 aiu_polling_supported: bool
Per-firmware constants used by services.
NCE_PH_PRO_2006 =
NceCommandSet(name='PH-Pro 2006+', turnout_memory_base=60416, turnout_table_bytes=256, macro_memory_base=51200, consist_memory_base=62720, supports_ops_mode_prog=True, aiu_polling_supported=True)
NCE_POWERCAB =
NceCommandSet(name='PowerCab', turnout_memory_base=60416, turnout_table_bytes=64, macro_memory_base=51200, consist_memory_base=62720, supports_ops_mode_prog=True, aiu_polling_supported=False)
NCE_SB5 =
NceCommandSet(name='Smart Booster SB5', turnout_memory_base=60416, turnout_table_bytes=256, macro_memory_base=51200, consist_memory_base=62720, supports_ops_mode_prog=True, aiu_polling_supported=True)
COMMAND_SETS: dict[str, NceCommandSet] =
{'PH-Pro 2006+': NceCommandSet(name='PH-Pro 2006+', turnout_memory_base=60416, turnout_table_bytes=256, macro_memory_base=51200, consist_memory_base=62720, supports_ops_mode_prog=True, aiu_polling_supported=True), 'PowerCab': NceCommandSet(name='PowerCab', turnout_memory_base=60416, turnout_table_bytes=64, macro_memory_base=51200, consist_memory_base=62720, supports_ops_mode_prog=True, aiu_polling_supported=False), 'Smart Booster SB5': NceCommandSet(name='Smart Booster SB5', turnout_memory_base=60416, turnout_table_bytes=256, macro_memory_base=51200, consist_memory_base=62720, supports_ops_mode_prog=True, aiu_polling_supported=True)}
75def get_command_set(name: str) -> NceCommandSet: 76 """Look up a command set by friendly name. Raises ``KeyError`` if unknown.""" 77 if name not in COMMAND_SETS: 78 raise KeyError( 79 f"unknown NCE command set: {name!r} (have: {sorted(COMMAND_SETS)})" 80 ) 81 return COMMAND_SETS[name]
Look up a command set by friendly name. Raises KeyError if unknown.