jmri_core.beans.programmer
Programmer ABC + ProgrammingMode enum + ProgrammerManager.
A programmer reads and writes Configuration Variables (CVs) on a DCC decoder. Two operational modes:
- Service mode (programming track) — the decoder is electrically
isolated from the layout. Slow but works on any decoder; reads always
succeed when a decoder is on the track. Three sub-modes:
SERVICE_DIRECT(modern),SERVICE_PAGED(legacy),SERVICE_REGISTER(oldest). Most drivers expose only DIRECT. - Ops mode (also called "ops mode programming" or "POM") — write to a specific loco while it's running. Reads only work with RailCom; on a non-RailCom layout, ops-mode reads time out.
A driver implements Programmer once for service mode and once
per ops-mode address. ProgrammerManager is the registry that
hands these out — same shape as ThrottleManager.
1"""``Programmer`` ABC + ``ProgrammingMode`` enum + ``ProgrammerManager``. 2 3A *programmer* reads and writes Configuration Variables (CVs) on a DCC 4decoder. Two operational modes: 5 6* **Service mode** (programming track) — the decoder is electrically 7 isolated from the layout. Slow but works on any decoder; reads always 8 succeed when a decoder is on the track. Three sub-modes: 9 ``SERVICE_DIRECT`` (modern), ``SERVICE_PAGED`` (legacy), ``SERVICE_REGISTER`` 10 (oldest). Most drivers expose only DIRECT. 11* **Ops mode** (also called "ops mode programming" or "POM") — write to 12 a specific loco *while it's running*. Reads only work with RailCom; on 13 a non-RailCom layout, ops-mode reads time out. 14 15A driver implements :class:`Programmer` once for service mode and once 16per ops-mode address. :class:`ProgrammerManager` is the registry that 17hands these out — same shape as ``ThrottleManager``. 18""" 19from __future__ import annotations 20 21from abc import ABC, abstractmethod 22from enum import StrEnum 23 24 25class ProgrammingMode(StrEnum): 26 """How the programmer talks to the decoder.""" 27 28 SERVICE_DIRECT = "service_direct" 29 SERVICE_PAGED = "service_paged" 30 SERVICE_REGISTER = "service_register" 31 OPS_MODE = "ops_mode" 32 33 34class Programmer(ABC): 35 """Reads and writes one DCC decoder's CVs. 36 37 Subclasses implement the two abstract methods. They may raise 38 :class:`asyncio.TimeoutError` if the CS doesn't respond in time, or 39 any driver-specific exception on programming errors (no acknowledge 40 pulse, decoder refused write, etc.). 41 """ 42 43 @property 44 @abstractmethod 45 def mode(self) -> ProgrammingMode: 46 """Which mode this programmer instance uses.""" 47 48 @abstractmethod 49 async def read_cv(self, cv: int) -> int: 50 """Read CV *cv*, returns 0..255.""" 51 52 @abstractmethod 53 async def write_cv(self, cv: int, value: int) -> None: 54 """Write *value* to CV *cv*.""" 55 56 57class ProgrammerManager: 58 """Hands out programmer instances. 59 60 * :meth:`global_programmer` returns the service-mode programmer (one 61 per connection — the programming track is a singleton). 62 * :meth:`ops_programmer(address, long_address)` returns an ops-mode 63 programmer scoped to the given DCC address. 64 65 The base class returns ``None`` from both; drivers override. 66 """ 67 68 def global_programmer(self) -> Programmer | None: 69 return None 70 71 def ops_programmer( 72 self, address: int, *, long_address: bool = False 73 ) -> Programmer | None: 74 return None
26class ProgrammingMode(StrEnum): 27 """How the programmer talks to the decoder.""" 28 29 SERVICE_DIRECT = "service_direct" 30 SERVICE_PAGED = "service_paged" 31 SERVICE_REGISTER = "service_register" 32 OPS_MODE = "ops_mode"
How the programmer talks to the decoder.
35class Programmer(ABC): 36 """Reads and writes one DCC decoder's CVs. 37 38 Subclasses implement the two abstract methods. They may raise 39 :class:`asyncio.TimeoutError` if the CS doesn't respond in time, or 40 any driver-specific exception on programming errors (no acknowledge 41 pulse, decoder refused write, etc.). 42 """ 43 44 @property 45 @abstractmethod 46 def mode(self) -> ProgrammingMode: 47 """Which mode this programmer instance uses.""" 48 49 @abstractmethod 50 async def read_cv(self, cv: int) -> int: 51 """Read CV *cv*, returns 0..255.""" 52 53 @abstractmethod 54 async def write_cv(self, cv: int, value: int) -> None: 55 """Write *value* to CV *cv*."""
Reads and writes one DCC decoder's CVs.
Subclasses implement the two abstract methods. They may raise
asyncio.TimeoutError if the CS doesn't respond in time, or
any driver-specific exception on programming errors (no acknowledge
pulse, decoder refused write, etc.).
44 @property 45 @abstractmethod 46 def mode(self) -> ProgrammingMode: 47 """Which mode this programmer instance uses."""
Which mode this programmer instance uses.
58class ProgrammerManager: 59 """Hands out programmer instances. 60 61 * :meth:`global_programmer` returns the service-mode programmer (one 62 per connection — the programming track is a singleton). 63 * :meth:`ops_programmer(address, long_address)` returns an ops-mode 64 programmer scoped to the given DCC address. 65 66 The base class returns ``None`` from both; drivers override. 67 """ 68 69 def global_programmer(self) -> Programmer | None: 70 return None 71 72 def ops_programmer( 73 self, address: int, *, long_address: bool = False 74 ) -> Programmer | None: 75 return None
Hands out programmer instances.
global_programmer()returns the service-mode programmer (one per connection — the programming track is a singleton).ops_programmer(address, long_address)()returns an ops-mode programmer scoped to the given DCC address.
The base class returns None from both; drivers override.