jmri_nce.detect

Auto-detect the NCE command-set variant via SW_REV_CMD (opcode 0xAA).

The query returns 3 bytes: major version, minor version, and a model byte. We use the model byte to choose between the three production variants; falls back to PH-Pro 2006+ if the model is unknown (the most permissive of the three).

 1"""Auto-detect the NCE command-set variant via ``SW_REV_CMD`` (opcode 0xAA).
 2
 3The query returns 3 bytes: major version, minor version, and a model byte.
 4We use the model byte to choose between the three production variants;
 5falls back to PH-Pro 2006+ if the model is unknown (the most permissive
 6of the three).
 7"""
 8from __future__ import annotations
 9
10import logging
11
12from jmri_nce.command_set import (
13    NCE_PH_PRO_2006,
14    NCE_POWERCAB,
15    NCE_SB5,
16    NceCommandSet,
17)
18from jmri_nce.messages import NceCommandError, query_command_version
19from jmri_nce.traffic import NceTrafficController
20
21_log = logging.getLogger(__name__)
22
23
24# Model byte values per the NCE binary command reference.
25MODEL_POWERPRO  = 0x00
26MODEL_SB5       = 0x01
27MODEL_POWERCAB  = 0x02
28MODEL_TWIN      = 0x03
29
30
31def model_to_command_set(model: int) -> NceCommandSet:
32    """Choose the canonical command set for an NCE model byte."""
33    if model == MODEL_POWERCAB:
34        return NCE_POWERCAB
35    if model == MODEL_SB5:
36        return NCE_SB5
37    # PowerPro, Twin, and unknowns all use the PH-Pro 2006+ map.
38    return NCE_PH_PRO_2006
39
40
41async def detect_command_set(
42    tc: NceTrafficController, *, fallback: NceCommandSet = NCE_PH_PRO_2006
43) -> NceCommandSet:
44    """Query the command station and pick the matching command set.
45
46    On any error (timeout, unsupported by old firmware, NACK) we log a
47    warning and return *fallback* so the connection still opens.
48    """
49    try:
50        reply = await tc.send_command(query_command_version())
51    except (TimeoutError, NceCommandError) as e:
52        _log.warning("NCE version query failed (%s); falling back to %s", e, fallback.name)
53        return fallback
54    if len(reply.data) < 3:
55        _log.warning("NCE version reply too short: %r", reply.data)
56        return fallback
57    major, minor, model = reply.data[0], reply.data[1], reply.data[2]
58    cs = model_to_command_set(model)
59    _log.info("NCE firmware v%d.%d, model=%#x → %s", major, minor, model, cs.name)
60    return cs
MODEL_POWERPRO = 0
MODEL_SB5 = 1
MODEL_POWERCAB = 2
MODEL_TWIN = 3
def model_to_command_set(model: int) -> jmri_nce.NceCommandSet:
32def model_to_command_set(model: int) -> NceCommandSet:
33    """Choose the canonical command set for an NCE model byte."""
34    if model == MODEL_POWERCAB:
35        return NCE_POWERCAB
36    if model == MODEL_SB5:
37        return NCE_SB5
38    # PowerPro, Twin, and unknowns all use the PH-Pro 2006+ map.
39    return NCE_PH_PRO_2006

Choose the canonical command set for an NCE model byte.

async def detect_command_set( tc: jmri_nce.NceTrafficController, *, fallback: jmri_nce.NceCommandSet = 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)) -> jmri_nce.NceCommandSet:
42async def detect_command_set(
43    tc: NceTrafficController, *, fallback: NceCommandSet = NCE_PH_PRO_2006
44) -> NceCommandSet:
45    """Query the command station and pick the matching command set.
46
47    On any error (timeout, unsupported by old firmware, NACK) we log a
48    warning and return *fallback* so the connection still opens.
49    """
50    try:
51        reply = await tc.send_command(query_command_version())
52    except (TimeoutError, NceCommandError) as e:
53        _log.warning("NCE version query failed (%s); falling back to %s", e, fallback.name)
54        return fallback
55    if len(reply.data) < 3:
56        _log.warning("NCE version reply too short: %r", reply.data)
57        return fallback
58    major, minor, model = reply.data[0], reply.data[1], reply.data[2]
59    cs = model_to_command_set(model)
60    _log.info("NCE firmware v%d.%d, model=%#x → %s", major, minor, model, cs.name)
61    return cs

Query the command station and pick the matching command set.

On any error (timeout, unsupported by old firmware, NACK) we log a warning and return fallback so the connection still opens.