Types & storage
A point separates how the value is stored on the wire from what it means
logically. storage_type is the physical layout; value_type is the
interpretation.
Storage types
Modbus registers are 16-bit. ModDef storage types describe how one or more registers combine into a raw value:
- Integers:
U16S16U24U32S32U48S48U64S64 - IEEE-754 floats:
IEEE754_F32IEEE754_F64 - Text and bytes:
STRING_ASCIISTRING_UTF8BYTES_RAW - Packed decimal:
BCD - Multi-register composite:
COMPOSED(mantissa × base^exponent)
The register width follows from the storage type unless the mapping overrides
it with length_words.
Byte and word order
Multi-register values need two orderings, both defaulting to big-endian:
byte_order: byte order within a single 16-bit word (BIG_ENDIANorLITTLE_ENDIAN).word_order: order of the words themselves for values wider than one register (WORD_BIG_ENDIANorWORD_LITTLE_ENDIAN).
# 32-bit value, high word first, big-endian bytes (the common case)
mapping: { space: HOLDING_REGISTER, offset: 100, length_words: 2,
byte_order: BIG_ENDIAN, word_order: WORD_BIG_ENDIAN }
Value types
value_type is a tagged choice:
{ primitive: ... }:BOOL,INT32/64,UINT32/64,FLOAT32/64,DECIMAL,STRING,BYTES,DATETIME,FLAGS.{ enum_ref: { type_id } }: a named enum defined in the document.{ struct_ref: ... }or{ array: ... }: composite logical types.{ flags: { bits } }: an independent bit set (§13.2).
DECIMAL is the workhorse: an integer register scaled by a
transform into an engineering value. The decoded surface is
a double/number/float in every runtime, with an exact-integer escape
hatch (decode_raw) for billing counters that must not lose precision.
Sub-register fields
A single register can pack several values, such as a time slot with the hour in the high byte and the minute in the low byte. Register fields name each bit range so you get a struct instead of a raw number:
fields:
- { field_id: hour, bit_offset: 8, bit_length: 8 }
- { field_id: minute, bit_offset: 0, bit_length: 8 }
Unavailable values
Devices signal "no data" with sentinel raw values (e.g. 0xFFFF on a U16,
0x8000 on an S16). Declare them with na_values and the runtime returns an
explicit unavailable result instead of a bogus number:
na_values:
- { raw: 65535, meaning: not_implemented }