Memory Configuration & CDI
Read and write a node’s configuration, CDI and identity through Memory Configuration datagrams, and lay out its CDI.
from pyolcb import MemoryConfiguration, cdi
mc = MemoryConfiguration(node, 0x020157000099)
layout = cdi.parse(mc.read_cdi())
for field in layout.fields():
print("/".join(field.path), field.decode(mc.read(field.space, field.address, field.size)))
mc.write(0xFB, 1, b"Yard throat\0")
mc.update_complete()
memory_config
Memory Configuration protocol: reading and writing a node’s configuration, CDI and identity through datagrams whose first byte is 0x20.
The codec functions build requests and decode replies without any I/O, and
MemoryConfiguration runs them against a remote node through
pyolcb.Node.datagram_exchange():
mc = MemoryConfiguration(node, 0x020157000099)
cdi = mc.read_cdi()
mc.write(SPACE_ACDI_USER, 1, b"Yard throat\0")
mc.update_complete()
- class pyolcb.memory_config.MemoryConfiguration(node, destination, timeout: float = 3.0)
A Memory Configuration client for one remote node.
- Parameters:
node (pyolcb.Node) – The local node to send from.
destination (Address | int) – The node to configure, as an
Addressor 48-bit node ID.timeout (float) – Seconds to wait for each answer.
- factory_reset(node_id: int)
Reset the node’s configuration to factory defaults.
node_idmust be the node’s own ID.
- lock(node_id: int) int
Reserve the node for
node_id(0 releases). Returns the node ID now holding the lock.
- options() dict
Get Configuration Options.
- read(space: int, address: int, length: int) bytes
Read
lengthbytes in as many 64-byte requests as it takes. Stops early, returning fewer bytes, at the end of the space.
- read_cdi() str
Read the node’s Configuration Description Information XML.
- read_space(space: int, stop_at_nul: bool = False, limit: int = 1048576) bytes
Read a whole space, sized with Get Address Space Information. With
stop_at_nulreading ends at the first NUL (for the CDI).
- reboot()
Ask the node to restart. A node that restarts before acknowledging is not an error.
- update_complete()
Tell the node the tool has finished writing, so it commits and applies the settings.
- write(space: int, address: int, data: bytes)
Write
datain as many 64-byte requests as it takes.
- class pyolcb.memory_config.SpaceInfo(space: int, present: bool, highest: int = 0, lowest: int = 0, read_only: bool = True, description: str = '')
What Get Address Space Information reports about a memory space.
- property size: int
Bytes from the lowest to the highest address, inclusive.
- pyolcb.memory_config.describe(data: bytes) str
A one-line summary of a Memory Configuration datagram, for traffic monitors.
- pyolcb.memory_config.factory_reset_request(node_id: int) bytes
Factory reset must name the target node, so a stray datagram cannot wipe the wrong one.
- pyolcb.memory_config.is_reply_to(request: bytes, reply: bytes) bool
True if
replyis the Memory Configuration answer torequest.
- pyolcb.memory_config.lock_request(node_id: int) bytes
Reserve a node for configuration (node ID 0 releases it).
- pyolcb.memory_config.parse_options_reply(reply: bytes) dict
Decode Get Configuration Options Reply.
- pyolcb.memory_config.parse_read_reply(reply: bytes) tuple[int, int, bytes]
Decode a read reply into
(space, address, data). RaisesMemoryConfigErrorfor a Read Failed reply.
- pyolcb.memory_config.parse_space_info_reply(reply: bytes) SpaceInfo
Decode
[0x20, 0x86|present, space, highest(4), flags, lowest(4)?, description?]. Flag bit 0 is read-only, bit 1 says a lowest address follows.
- pyolcb.memory_config.parse_write_reply(reply: bytes) None
Check a write reply; raises
MemoryConfigErrorfor Write Failed.
- pyolcb.memory_config.read_request(space: int, address: int, count: int) bytes
A read of
count(1-64) bytes, always in the explicit-space form.
- pyolcb.memory_config.write_request(space: int, address: int, data: bytes) bytes
A write of up to 64 bytes, in the explicit-space form.
CDI
cdi
Configuration Description Information: the XML a node serves from memory space 0xFF to describe its configuration memory.
parse() turns the XML into a layout tree in which every field carries
its absolute memory space and address, with group replication expanded:
layout = cdi.parse(xml)
for field in layout.fields():
print(field.path, field.space, hex(field.address), field.size)
Layout rules, per the OpenLCB CDI standard:
A
<segment>sets the memoryspaceand starts at itsorigin(default 0).Any element may have an
offsetattribute: bytes skipped (or, if negative, backed up) before the element.A
<group>is as large as its contents; withreplicationN it is laid out N times back to back, each copy named from its<repname>plus a number.<int>is 1, 2, 4 or 8 bytes (default 1), big-endian, with optional<min>,<max>,<default>and a<map>of named values.<string>has asizeand holds NUL-terminated UTF-8.<eventid>is always 8 bytes.<float>is 2, 4 or 8 bytes (default 4), IEEE 754 big-endian.<action>(a button that writes<value>) and<blob>takesizebytes.
- class pyolcb.cdi.Cdi(identification: dict, acdi: bool, segments: list[Segment])
A parsed CDI document.
- ranges() list[tuple[int, int, int]]
(space, start, length)spans covering every field, merged where they touch.
- class pyolcb.cdi.Field(kind, name, description, space, address, size, path, minimum=None, maximum=None, default=None, map=None, hints=None, button_text=None, dialog_text=None, value=None)
One configurable value at a fixed place in a node’s memory.
- kind
int,string,eventid,float,actionorblob.- Type:
str
- name, description
- Type:
str
- space, address, size
Where the value lives.
- Type:
int
- path
Names of the enclosing segment and groups, then the field’s own name.
- Type:
list[str]
- minimum, maximum, default
- Type:
int | float | None
- map
(property, label)pairs; anintwith a map is a choice.- Type:
list[tuple[str, str]]
- decode(data: bytes)
Turn the field’s bytes into a Python value (int, str, float, or dotted-hex event ID).
- encode(value) bytes
Turn a value back into exactly
sizebytes.
- class pyolcb.cdi.Group(name, description, children, label=None, index=None)
A named block of fields and groups; a replicated group has one
Groupper copy.
- class pyolcb.cdi.Replicated(name, description, replicas)
A group with
replication> 1: the copies, in memory order.
- class pyolcb.cdi.Segment(space, origin, name, description, children, end)
One
<segment>: fields in a single memory space.
Simple Node Information
snip
Simple Node Information Protocol (SNIP): the identity strings a node reports in reply to a Simple Node Ident Info Request.
The reply is a version byte (4), manufacturer, model, hardware version and software version as NUL-terminated strings, a second version byte (2), then the user-assigned name and description. Older nodes send version 1 in either place; both are accepted.
- class pyolcb.snip.SimpleNodeInfo(manufacturer: str = '', model: str = '', hardware_version: str = '', software_version: str = '', user_name: str = '', user_description: str = '')
The identity of a node.
- Parameters:
manufacturer (str) – Fixed at build time by the node’s maker.
model (str) – Fixed at build time by the node’s maker.
hardware_version (str) – Fixed at build time by the node’s maker.
software_version (str) – Fixed at build time by the node’s maker.
user_name (str) – Set by the user through Memory Configuration space 0xFB.
user_description (str) – Set by the user through Memory Configuration space 0xFB.
- classmethod from_bytes(data: bytes) SimpleNodeInfo
Decode a SNIP reply payload, tolerating short or truncated replies.
- to_bytes() bytes
Encode as a SNIP reply payload.