Chapter 15 — SNIP (Simple Node Information Protocol)
The Simple Node Information Protocol provides a lightweight way to identify a node without reading its full CDI. A SNIP reply packs manufacturer identification and user-configurable name/description into a single addressed message (up to 256 bytes).
src/openlcb/protocol_snip.c,
src/openlcb/protocol_snip.h
15.1 Request / Reply Exchange
The handler ProtocolSnip_handle_simple_node_info_request() builds the
reply and marks it valid. The incoming reply handler
ProtocolSnip_handle_simple_node_info_reply() is a no-op (no automatic
response is generated).
15.2 Reply Payload Format (8 Fields)
The SNIP reply contains exactly 8 fields assembled sequentially. Each string field
is null-terminated. The total maximum payload is LEN_MESSAGE_BYTES_SNIP
(256 bytes).
| # | Field | Type | Max Size | Source |
|---|---|---|---|---|
| 1 | Manufacturer Version | 1 byte | 1 | snip.mfg_version (node params) |
| 2 | Manufacturer Name | string + null | 41 | snip.name (node params) |
| 3 | Model | string + null | 41 | snip.model (node params) |
| 4 | Hardware Version | string + null | 21 | snip.hardware_version (node params) |
| 5 | Software Version | string + null | 21 | snip.software_version (node params) |
| 6 | User Version | 1 byte | 1 | snip.user_version (node params) |
| 7 | User Name | string + null | 63 | Configuration memory (ACDI User space) |
| 8 | User Description | string + null | 64 | Configuration memory (ACDI User space) |
LEN_SNIP_STRUCTURE = 264 bytes (includes all max lengths). The wire
payload is variable-length depending on actual string lengths.
15.3 Manufacturer vs. User Fields
Fields 1-5 (manufacturer section) come from the node's parameters->snip
structure, which is typically stored in flash/ROM. These are read-only and set at
compile time:
typedef struct {
uint8_t mfg_version; // Always 1
char name[LEN_SNIP_NAME_BUFFER]; // 41 bytes
char model[LEN_SNIP_MODEL_BUFFER]; // 41 bytes
char hardware_version[LEN_SNIP_HARDWARE_VERSION_BUFFER]; // 21 bytes
char software_version[LEN_SNIP_SOFTWARE_VERSION_BUFFER]; // 21 bytes
uint8_t user_version; // Always 1
} user_snip_struct_t;
Fields 7-8 (user section) are read at runtime from configuration memory via the
config_memory_read callback. The addresses are defined by the
application:
- User Name: starts at
USER_DEFINED_CONFIG_MEM_USER_NAME_ADDRESS - User Description: starts at
USER_DEFINED_CONFIG_MEM_USER_DESCRIPTION_ADDRESS
If the node's address_space_config_memory.low_address_valid flag is set,
the low address offset is added to the base address, allowing per-node offsets in a
shared configuration space.
15.4 Field Loader Functions
Each of the 8 fields has a dedicated public loader function. All share the same signature pattern:
uint16_t ProtocolSnip_load_<field>(
openlcb_node_t *openlcb_node,
openlcb_msg_t *outgoing_msg,
uint16_t offset, // current payload offset
uint16_t requested_bytes // max bytes to write
);
// Returns: updated offset after writing
| Loader Function | Field |
|---|---|
ProtocolSnip_load_manufacturer_version_id() | Mfg version byte |
ProtocolSnip_load_name() | Manufacturer name |
ProtocolSnip_load_model() | Model name |
ProtocolSnip_load_hardware_version() | Hardware version |
ProtocolSnip_load_software_version() | Software version |
ProtocolSnip_load_user_version_id() | User version byte |
ProtocolSnip_load_user_name() | User name (from config memory) |
ProtocolSnip_load_user_description() | User description (from config memory) |
The internal helper _process_snip_string() handles string copying with
truncation. It clamps the string length to the buffer maximum, copies the characters,
and always appends a null terminator.
15.5 Reply Assembly Flow
Each loader function advances the payload_offset and increments
outgoing_msg->payload_count. The loaders are called sequentially so
the payload is built in wire order.
15.6 Validation: Exactly 6 Null Terminators
ProtocolSnip_validate_snip_reply() verifies an incoming SNIP reply is
well-formed. The three checks are:
- Length check:
payload_countmust not exceedLEN_MESSAGE_BYTES_SNIP(256). - MTI check: must be
MTI_SIMPLE_NODE_INFO_REPLY(0x0A08). - Null count: the payload must contain exactly 6 null bytes (0x00).
The 6 null bytes correspond to the 6 null terminators expected from the string fields
(fields 2-5 and 7-8). The two version bytes (fields 1 and 6) are not null-terminated.
The null count is computed by OpenLcbUtilities_count_nulls_in_openlcb_payload().
15.7 Callback Interface
The SNIP handler requires a single callback:
typedef struct {
uint16_t (*config_memory_read)(
openlcb_node_t *openlcb_node,
uint32_t address,
uint16_t count,
configuration_memory_buffer_t *buffer
); // REQUIRED
} interface_openlcb_protocol_snip_t;
The config_memory_read callback is used to fetch user name and user
description from configuration memory. If this callback is NULL, the user fields
are written as empty strings (single null byte each).