ULCP: Framing and Common Semantics
This chapter defines the ULCP wire format and the semantics every device implements whatever else it supports: the frame layout, the command grammar, the property model, the classes of state a device holds, how a host attaches and synchronizes, and the numeric registries for status codes, reset codes, and capabilities. The subsystem chapters that follow build on it.
ULCP is inspired by the Spinel protocol from OpenThread, but it is not Spinel and does not aim for wire compatibility with it. The protocol assumes reliable, in-order delivery of frames, as well as a way to assert flow control. The framing mechanism depends on the underlying transport:
- Asynchronous serial links (UART, USB-CDC) use HDLC-Lite, exactly as used by Spinel.
- BLE uses the GATT frame transport defined in ULCP over BLE.
- A reliable, in-order byte stream standing in for a serial link—a TCP connection to a bridged port, say—uses the same HDLC-Lite framing.
In this chapter, the device is the side that owns the transceiver and the host is the side that attaches to it over the local link (see Local Control Protocol).
The protocol version is 6.0. Which subsystems a device implements is
discovered through PROP_CAPS, never through the version number; see
Minimum Requirements for what a device is required
to implement in order to be a ULCP device at all.
Data Representation
Spinel, being a low-level protocol between two devices which are likely to have a little-endian architecture, uses little-endian representations exclusively for all integers smaller than four bytes. For implementation convenience, values larger than four bytes (EUI64, IPv6 addresses, etc.) are stored as they are traditionally represented (typically, but not always, big-endian).
Packed Unsigned Integers
Certain types of integers, such as command or property identifiers, usually have a value on the wire that is less than 127. However, in order to not preclude the use of values larger than 255, we would need to add an extra byte. Doing this would add an extra byte to all packets, which can add up in terms of bandwidth. To address this, Spinel uses Packed Unsigned Integers, or PUIs.
The PUI format used in Spinel is based on the unsigned integer format in EXI, except that we limit the maximum value to the largest value that can be encoded in three bytes. The maximum value that can be encoded is 2,097,151.
For all values less than 127, the packed form of the number is simply a single byte which directly represents the number. For values larger than 127, the following process is used to encode the value:
- The unsigned integer is broken up into n 7-bit chunks and placed into n bytes, leaving the most significant bit of each byte unused.
- Order the bytes from least-significant to most-significant. (Little-endian)
- Clear the most significant bit of the most significant byte. Set the most significant bit on all other bytes.
Where n is the smallest number of 7-bit chunks you can use to represent the given value.
Take the value 1337, for example:
1337 => 0x0539
=> [39 0A]
=> [B9 0A]
To decode the value, you collect the 7-bit chunks until you find a byte with the most significant bit clear.
Frame Format
A ULCP frame is the concatenation of the following elements:
- A header comprising a single byte.
- A command identifier.
- A command-defined payload, which may be empty.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| HEADER | COMMAND ID | PAYLOAD ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure: Structure of a typical ULCP frame
Since the size of the frame is part of the framing mechanism, it is omitted from the frame.
Frame Header
Each frame has the following format:
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| FLG | RESERVED | TID |
+---+---+---+---+---+---+---+---+
Figure: Header Format
FLG: Flag
The Flag (FLG) field in the two most significant bits of the header byte is
always set to the value two (or 10 in binary). Any frame received with these
bits set to any other value SHALL NOT be considered a ULCP frame.
RESERVED: Reserved
These three bits must always be set to zero and the entire frame ignored if set to any other value. They may be assigned a meaning (such as an interface identifier) in a future version of this protocol.
TID: Transaction Identifier
The Transaction Identifier (TID) field in the three least significant bits of the header is used for correlating responses to the commands which generated them. This allows for up to seven host-issued commands to be in flight at once.
When a command is sent from the host, any reply to that command sent by the device will use the same value for the TID. When the host receives a frame that matches the TID of the command it sent, it can easily recognize that frame as the actual response to that command.
The zero value of TID is used for commands to which a correlated response is not expected or needed, such as for unsolicited update commands sent to the host from the device.
Note that while the frame format is symmetric between the frames being sent to the device versus frames being sent from the device, the behaviors are not. The device MUST NOT send a frame with a non-zero TID that is not a response to a frame it had recently received with that same TID. All unsolicited or asynchronous commands originating from the device MUST use TID zero (0).
Command ID
The command identifier is a 7-bit unsigned integer encoded from 0 to 127. The most significant bit is not set and the frame must be ignored if it is set.
Payload
The command payload follows the command identifier in a ULCP frame, containing the serialization of any arguments that the indicated command may require. The exact composition of a command payload is determined by the specific command identifier being used and MUST be empty if the command has no arguments.
Commands
This chapter defines the commands that operate on the protocol itself—
resets, liveness, and the property grammar. The remaining commands are
defined with the subsystem they act on: CMD_STR_SEND and CMD_STR_RECV
in Frame Transport, CMD_QUEUE_DRAIN in
Tethered Host Services, CMD_ANNOUNCE in
Device Identity, and the four state-management commands
in Saved State. The complete numeric allocation is
in the Command and Property Index.
| Id | Mnemonic | Dir | Description |
|---|---|---|---|
| 0 | CMD_NOP | Host->Device | No-Operation |
| 1 | CMD_RST | Host->Device | Reset the device |
| 2 | CMD_PROP_GET | Host->Device | Get property value |
| 3 | CMD_PROP_SET | Host->Device | Set property value |
| 4 | CMD_PROP_INSERT | Host->Device | Insert an item into a multi-value property |
| 5 | CMD_PROP_REMOVE | Host->Device | Remove an item from a multi-value property |
| 6 | CMD_PROP_IS | Device->Host | Property value notification |
| 7 | CMD_PROP_INSERTED | Device->Host | Item-inserted notification |
| 8 | CMD_PROP_REMOVED | Device->Host | Item-removed notification |
| 16 | CMD_REBOOT | Host->Device | Restart the device’s hardware |
| 19 | CMD_ANNOUNCE | Host->Device | Announce the device now |
| 21 | CMD_PROP_MULTI_GET | Host->Device | Get several property values |
| 22 | CMD_PROP_MULTI_SET | Host->Device | Set several property values in order |
| 23 | CMD_PROP_ARE | Device->Host | Multiple property value notification |
| 24 | CMD_SESSION_RESET | Device->Host | Session state was discarded |
The multi-property commands (21–23) are gated by CAP_CMD_MULTI,
CMD_REBOOT by CAP_REBOOT, and CMD_ANNOUNCE by CAP_ADVERT (see
Capabilities); everything else is unconditional.
CMD 0: (Host -> Device) CMD_NOP
0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 0| RES | TID | CMD_NOP |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
^ HEADER ^ COMMAND ^
Figure: Structure of CMD_NOP
No-Operation. Commands the device to reply with a STATUS_OK code. This is
primarily used for liveness checks.
The command payload for this command SHOULD be empty. The receiver MUST ignore any non-empty command payload.
There is no error condition for this command.
CMD 1: (Host -> Device) CMD_RST
0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 0| RES | TID | CMD_RST |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure: Structure of CMD_RST
Reset device. Commands the device to perform a software reset. Due to the nature of
this command, the TID is ignored. The host should instead wait for a
CMD_PROP_IS command from the device indicating PROP_LAST_STATUS has been set
to STATUS_RESET_SOFTWARE (see Status Codes).
The command payload SHOULD be empty, and it SHOULD NOT be processed.
If an error occurs, the value of the emitted PROP_LAST_STATUS will be set
accordingly to the status code for the error.
CMD 2: (Host -> Device) CMD_PROP_GET
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 0| RES | TID | CMD | PROP_KEY (PUI, 1-3 bytes) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure: Structure of CMD_PROP_GET
Get property value. Commands the device to emit a CMD_PROP_IS command for the
given property identifier.
The payload for this command is the property identifier encoded in the packed unsigned integer format described in Packed Unsigned Integers.
If an error occurs, the value of the emitted PROP_LAST_STATUS will be set
accordingly to the status code for the error.
CMD 3: (Host -> Device) CMD_PROP_SET
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 0| RES | TID | CMD | PROP_KEY (PUI, 1-3 bytes) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NEW PROPERTY VALUE ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure: Structure of CMD_PROP_SET
Set property value. Commands the device to set the given property to the specific
given value, replacing any previous value, and to emit a CMD_PROP_IS command
for that property indicating the new authoritative value if successful.
The payload for this command is the property identifier encoded in the packed unsigned integer format described in Packed Unsigned Integers, followed by the property value. The exact format of the property value is defined by the property.
If an error occurs, the value of the emitted PROP_LAST_STATUS will be set
accordingly to the status code for the error.
The value reported by that CMD_PROP_IS need not be the value written: a
device that adjusts a write to what it can honor reports the result, and
that result is the property’s value. A write fails only by way of
PROP_LAST_STATUS—a differing value is a successful write, not a
rejected one.
CMD 4: (Host -> Device) CMD_PROP_INSERT
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 0| RES | TID | CMD | PROP_KEY (PUI, 1-3 bytes) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ITEM VALUE ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure: Structure of CMD_PROP_INSERT
Insert item into property. Commands the device to add the given item to the
given multi-value property, and to emit a CMD_PROP_INSERTED command for
that property if successful.
The payload for this command is the property identifier encoded in the packed unsigned integer format, followed by exactly one item encoded in the property’s item form (see Multi-Value Properties). The item is not preceded by a length prefix, regardless of whether the property uses item length prefixes in its multi-item value form; the framing layer bounds the item.
If the item is already present the command fails with STATUS_ALREADY,
except where a property defines replacement semantics for matching items
(see, e.g., PROP_HOST_PEER_KEYS). If the property exists but is not a
multi-value property, the command fails with STATUS_INVALID_ARGUMENT.
If an error occurs, the value of the emitted PROP_LAST_STATUS will be set
accordingly to the status code for the error.
CMD 5: (Host -> Device) CMD_PROP_REMOVE
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 0| RES | TID | CMD | PROP_KEY (PUI, 1-3 bytes) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ITEM SELECTOR ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure: Structure of CMD_PROP_REMOVE
Remove item from property. Commands the device to remove the item matching the
given selector from the given multi-value property, and to emit a
CMD_PROP_REMOVED command for that property if successful.
The payload for this command is the property identifier encoded in the packed unsigned integer format, followed by an item selector. Each multi-value property documents its selector form; unless stated otherwise it is the full item value.
If no matching item is present, the command fails with
STATUS_ITEM_NOT_FOUND. If the property exists but is not a multi-value
property, the command fails with STATUS_INVALID_ARGUMENT.
If an error occurs, the value of the emitted PROP_LAST_STATUS will be set
accordingly to the status code for the error.
CMD 6: (Device -> Host) CMD_PROP_IS
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 0| RES | TID | CMD | PROP_KEY (PUI, 1-3 bytes) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| CURRENT PROPERTY VALUE ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure: Structure of CMD_PROP_IS
Property value notification. This command can be sent by the device in response to a previous command from the host, or it can be sent by the device in an unsolicited fashion to notify the host of various state changes asynchronously.
The payload for this command is the property identifier encoded in the packed unsigned integer format described in Packed Unsigned Integers, followed by the current value of the given property.
CMD 7: (Device -> Host) CMD_PROP_INSERTED
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 0| RES | TID | CMD | PROP_KEY (PUI, 1-3 bytes) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| REPORTED ITEM ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure: Structure of CMD_PROP_INSERTED
Item-inserted notification. Sent by the device in response to a successful
CMD_PROP_INSERT (with the TID of that command), or unsolicited with a TID
of zero when the device adds an item to a multi-value property for its own
reasons.
The payload is the property identifier followed by the inserted item as the device reports it (see Multi-Value Properties)—never in a form containing key material.
CMD 8: (Device -> Host) CMD_PROP_REMOVED
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 0| RES | TID | CMD | PROP_KEY (PUI, 1-3 bytes) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| REPORTED ITEM ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure: Structure of CMD_PROP_REMOVED
Item-removed notification. Sent by the device in response to a successful
CMD_PROP_REMOVE (with the TID of that command), or unsolicited with a TID
of zero when the device removes an item from a multi-value property for its
own reasons.
The payload is the property identifier followed by the removed item as the device reports it.
CMD 16: (Host -> Device) CMD_REBOOT
0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 0| RES | TID | CMD_REBOOT |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure: Structure of CMD_REBOOT
Restart the device. Commands the device to power-cycle its hardware, keeping every piece of state it has persisted: the saved snapshot, the device identity, the pairing PIN, and all bonds survive, and the device comes back configured as it was.
This differs from CMD_RST, which returns protocol state to
its post-reset values with the device still running, and from
CMD_FACTORY_RESET, which erases
that state before restarting. Between the three, this is the one that
changes nothing—it is how a host clears a condition the protocol cannot
name.
The command payload SHOULD be empty and MUST be ignored. A device that
restarts sends no response: the reboot drops the transport link, and
the TID is therefore irrelevant. A host treats the ensuing disconnect (and
the device’s subsequent reappearance announcing STATUS_RESET_POWER_ON)
as completion, and MUST NOT wait for a PROP_LAST_STATUS.
This command is only available on devices advertising CAP_REBOOT.
A device without it answers STATUS_UNIMPLEMENTED—which is the only
response this command ever produces, and the only thing that distinguishes
a device that declined from one that is already restarting.
CMD 21: (Host -> Device) CMD_PROP_MULTI_GET
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 0| RES | TID | CMD | PROP_KEY (PUI) | PROP_KEY ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure: Structure of CMD_PROP_MULTI_GET
Get several property values at once. Commands the device to reply with a
single CMD_PROP_ARE carrying one entry for each
requested property, in request order.
The payload is one or more property identifiers, each encoded in the packed unsigned integer format, one after another with no delimiters.
Fetching continues past failures: a property that cannot be fetched
occupies its position in the reply as a PROP_LAST_STATUS entry whose
value is the status code a CMD_PROP_GET of that property would have
produced. Position, not the entry’s key, identifies which request an
entry answers.
This command is available only on devices advertising CAP_CMD_MULTI.
On any other device it is an unrecognized command,
STATUS_INVALID_COMMAND.
CMD 22: (Host -> Device) CMD_PROP_MULTI_SET
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 0| RES | TID | CMD | ENTRY | ENTRY | ENTRY ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure: Structure of CMD_PROP_MULTI_SET
Set several property values in order. The payload is a sequence of entries, each the combined length of its key and value encoded as a packed unsigned integer, followed by that many octets—the property identifier as a packed unsigned integer, then the value:
+--------------+---------------------------+--------------------+
| LENGTH (PUI) | PROP_KEY (PUI, 1-3 bytes) | VALUE (remainder) |
+--------------+---------------------------+--------------------+
Figure: CMD_PROP_MULTI_SET Entry Format
The device applies each entry exactly as a CMD_PROP_SET of that
property would, strictly in payload order, stopping at the first entry
that fails. Mutation Atomicity applies to each
entry alone: the sequence is not a transaction, and a failure partway
leaves the earlier entries applied.
The reply is a single CMD_PROP_ARE containing, for
each applied entry in order, the property and its reported value—
exactly what the CMD_PROP_IS answering a lone CMD_PROP_SET would
carry—and, for the failing entry, a PROP_LAST_STATUS entry carrying
the error, after which the reply ends. Entries past the failure are not
executed and contribute nothing; a reply whose every entry is a success
covers the entire request.
This command is available only on devices advertising CAP_CMD_MULTI.
On any other device it is an unrecognized command,
STATUS_INVALID_COMMAND.
CMD 23: (Device -> Host) CMD_PROP_ARE
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 0| RES | TID | CMD | ENTRY | ENTRY | ENTRY ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure: Structure of CMD_PROP_ARE
Multiple property value notification. The payload is a sequence of
entries in the same encoding as CMD_PROP_MULTI_SET: a combined
key-and-value length as a packed unsigned integer, the property
identifier, and the value as the device reports it—under the same
reporting rules as CMD_PROP_IS, so key material never appears (see
Multi-Value Properties).
The device emits this command only in response to CMD_PROP_MULTI_GET
or CMD_PROP_MULTI_SET, with the TID of that command. It MUST NOT
be emitted unsolicited: asynchronous updates use CMD_PROP_IS and its
companions, one property at a time.
CMD 24: (Device -> Host) CMD_SESSION_RESET
0 1 2
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 0| RES | TID | CMD | REASON
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure: Structure of CMD_SESSION_RESET
The device has discarded session state, so every session-scoped property is back at its documented default under a host that did not ask for it. The TID MUST be zero: the frame is always unsolicited.
REASON is a packed unsigned integer. It is diagnostic—a host’s obligation is the same for every value:
| Value | Meaning |
|---|---|
| 0 | A host attached |
| 1 | CMD_RST |
| 2 | CMD_RESTORE in its reset form |
Unassigned values are reserved. A host MUST treat an unrecognized reason as a session reset it does not have a name for, never as a parse failure.
A device MUST emit this command whenever it discards session state while a host is attached, and MUST NOT emit it when no host is attached: a detach discards session state with nobody to tell.
The frame MUST be emitted before any frame belonging to the new
session, so a host can tell which session anything it receives came
from. The completion of the command that caused the discard belongs to
the exchange that requested it and MAY precede the notice; a
CMD_RST is answered by its STATUS_RESET_SOFTWARE and then the
notice. Where a session is instead created by the host’s own first
frame, nothing has been answered yet and the notice comes first.
The command MUST NOT be emitted over the administrative binding. It concerns the local tethered session; an administrator over the mesh is not party to it, and the binding carries only what was asked for.
A host MUST tolerate the frame at any time while attached. On receiving it, a host MUST re-establish anything it holds in session state and SHOULD otherwise resynchronize as it would on a fresh attach (see Attach, Detach, and Synchronization).
This is deliberately not a reset code, and MUST NOT
disturb PROP_LAST_STATUS. The two report different losses:
STATUS_RESET_POWER_ON means the host domain went with the session and
must be reprovisioned in full, whereas a session reset means only session
state went. A reboot implies a session reset, so recording the narrower
fact over the broader one would lose the distinction that governs
recovery.
Properties and Streams
A property is a piece of device state with a value the host can read and, where the property allows it, write. A stream is a packet-like flow that is not modeled as state; streams share the property identifier space and are carried by their own commands (see Frame Transport).
Note
The properties marked as supporting
Ismeans that the property may be emitted asynchronously. All properties that supportGetorSetwill emit anIsto respond with the current/new value of that property.A multi-value property marked as supporting
InsertedorRemovedmay likewise emit those asynchronously, reporting one item the device added or dropped for its own reasons rather than the whole value. A host that tolerates an unsolicitedIsmust tolerate these as well.
Multi-Value Properties
A multi-value property holds an unordered set of items rather than a
single value. PROP_CAPS is one, and is constant; the key, peer, and
filter tables of the device and host domains are mutable ones.
The host writes items (CMD_PROP_SET, CMD_PROP_INSERT) in the
property’s item form. When the device reports items (CMD_PROP_IS,
CMD_PROP_INSERTED, CMD_PROP_REMOVED), it reports them exactly as
written—except where the item form contains symmetric key material. Such
a property documents its reported form instead: the entry with its
key material omitted, or a value derived from it (a channel key is
reported as its derived channel
identifier), so that
secrets can never be read back (see Provisioning
Security).
The commands valid on a mutable multi-value property are:
CMD_PROP_GET—the device replies withCMD_PROP_ISwhose value is the concatenation of all items as reported. If the property is documented as having an item length prefix, each item is preceded by its length in octets encoded as a packed unsigned integer; properties whose reported items are fixed-size omit the prefix.CMD_PROP_SET—replaces the entire contents with the items encoded in the value, each in item form (with the same length-prefix rule). Setting an empty value clears the property. Success is reported with aCMD_PROP_IScarrying the new complete value as reported.CMD_PROP_INSERT/CMD_PROP_REMOVE—add or remove one item, as defined above.
Hosts manipulating large tables SHOULD prefer Insert/Remove over
whole-table Set, since a full table may not fit comfortably in one frame
on all transports.
Mutation Atomicity
State-changing operations in this protocol are transactional and fail closed:
- The device MUST validate a complete request before changing any state.
A whole-table
CMD_PROP_SETwhose value contains any invalid item fails without applying any of it. - Whole-table replacement is atomic: no observer of device behavior (frame filtering, acknowledgement decisions) sees a mixture of the old and new contents.
- Operations that include durable writes—
CMD_SAVE,CMD_CLEAR, installing or generating the device identity, and settingPROP_BLE_PAIRING_PIN—MUST NOT report success before the durable write has completed. - On any failure, the prior live and durable state remains unchanged, and
the device MUST NOT emit
CMD_PROP_IS,CMD_PROP_INSERTED, orCMD_PROP_REMOVEDnotifications describing a partially applied change. - Host replacement is atomic in the same sense: at no point may the device operate with a mixture of the old and new hosts’ keys, filters, or policy. It involves no durable write, so it cannot fail partway.
Atomicity is per operation, not per sequence. Establishing a host domain is several property writes, and an interruption between them leaves a mixture of old and new—bounded by the fact that a host-key change resets the domain first and a reboot empties it. A host repairs this the same way it provisions in the first place: by writing everything again.
Core Properties
These properties exist on every device and are not gated by any capability.
| Id | Mnemonic | Commands | Description |
|---|---|---|---|
| 0 | PROP_LAST_STATUS | Get, Is | Last status |
| 1 | PROP_PROTOCOL_VERSION | Get | Protocol version |
| 2 | PROP_DEV_VERSION | Get | Device version string |
| 3 | PROP_INTERFACE_TYPE | Get | Interface type |
| 5 | PROP_CAPS | Get | Capabilities |
PROP 0: PROP_LAST_STATUS
- Type: Single-Value, Read-Only
- Asynchronous Updates: Yes
- Required: REQUIRED
- Value Type: PUI + STRING(opt.)
- Units: Enumeration
- Post-Reset Value: Reset Reason Code
This property describes the status code of the last device operation. For many
commands, failure is indicated by emitting CMD_PROP_IS for this property with
a TID matching the failing command. It is generally not necessary to ever fetch
the value of this property explicitly, as it is often emitted directly as an
error response. It is also occasionally emitted as a success response with a
value of STATUS_OK.
Upon device reset, this property MUST be emitted with a status code indicating the reset reason.
Upon receiving an asynchronous update to PROP_LAST_STATUS with a status code
that indicates a reset, the host SHALL assume that the device has been reset and
that all properties have reverted to their defined after-reset values.
See Status Codes for the complete list of status codes.
PROP 1: PROP_PROTOCOL_VERSION
- Type: Single-Value, Constant
- Asynchronous Updates: No
- Required: REQUIRED
- Scope: Device
- Value Type: UINT8, UINT8
- Post-Reset Value: 6, 0
Describes the ULCP version information. This property contains two fields:
0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| MAJOR_VERSION | MINOR_VERSION |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure: PROP_PROTOCOL_VERSION Value Format
MAJOR_VERSION- The major version number is used to identify backward incompatible differences between protocol versions.
MINOR_VERSION- The minor version number is used to identify backward-compatible differences between protocol versions. A mismatch between the advertised minor version number and the minor version that is supported by the host SHOULD NOT be fatal to the operation of the host.
This document describes major version 6, minor version 0 of this protocol.
PROP 2: PROP_DEV_VERSION
- Type: Single-Value, Constant
- Asynchronous Updates: No
- Required: REQUIRED
- Scope: Device
- Value Type: STRING
- Post-Reset Value: Implementation-Specific
Contains a zero-terminated ASCII string which describes the firmware currently running on the device.
The value of this string MUST be different for every firmware release.
The format of the string is not strictly defined, but it is intended to present similarly to the “User-Agent” string from HTTP. The following format is RECOMMENDED:
STACK-NAME/STACK-VERSION[BUILD-INFO][; OTHER-INFO][; BUILD-DATE]
The hardware the firmware is running on belongs in
PROP_DEV_MODEL, not here.
PROP 3: PROP_INTERFACE_TYPE
- Type: Single-Value, Constant
- Asynchronous Updates: No
- Required: REQUIRED
- Scope: NLI
- Value Type: PUI
- Units: Enumeration
- Post-Reset Value: Implementation-Specific
This unsigned packed integer identifies the network protocol implemented by this device. It must return the value 8.
PROP 4: PROP_DEV_MODEL
- Type: Single-Value, Constant
- Asynchronous Updates: No
- Required: OPTIONAL
- Scope: Device
- Value Type: STRING
- Post-Reset Value: Implementation-Specific
Contains a zero-terminated ASCII string naming the hardware model the device
is, such as Seeed SenseCAP T1000-E. Where
PROP_DEV_VERSION describes the firmware a device runs,
this describes the thing it runs on, and the two change independently: the
same firmware release covers several models, and a model outlives every
release built for it.
Firmware built for one specific board SHOULD implement this. A device whose hardware has no fixed identity—a simulator, or an implementation that runs on whatever it is compiled for—SHOULD omit the property rather than return an empty or invented string. A host MUST treat a refused get as “this device does not name its hardware” and continue.
The value SHOULD name the product as its vendor does, so that a host can
match it against an external hardware description. It is intended for display
and for lookup, and is deliberately not an identifier: a host that needs to
make decisions based on what a device can do has
PROP_CAPS for that.
PROP 5: PROP_CAPS
- Type: Multiple-Value, Constant
- Has Item Length Prefix: No
- Asynchronous Updates: No
- Required: REQUIRED
- Scope: NLI
- Item Type: PUI
- Units: Enumeration
- Post-Reset Value: Implementation-Specific
Describes the supported capabilities of this device. Encoded as a list of packed unsigned integers. See Capabilities for a list of values.
PROP 6: PROP_UPTIME
- Type: Single-Value, Read-Only
- Asynchronous Updates: No
- Required: OPTIONAL
- Scope: Device
- Value Type: UINT32
- Units: Seconds
- Post-Reset Value: 0
Seconds elapsed since the device last booted, truncated toward zero. A device that runs long enough to exhaust the range saturates rather than wrapping, so the value never falsely reports a recent restart.
This dates what PROP_LAST_STATUS describes: the
reset code says why the device last started, and this says how long ago.
Read together they distinguish a node that came up cleanly weeks back
from one that is restarting under a fault and reporting the same code
each time.
Only a power cycle or a genuine restart resets it. CMD_RST returns
protocol state to its post-reset values without rebooting the device, and
MUST NOT reset this property; neither does a host attaching or
detaching.
A device with no monotonic clock to answer from SHOULD omit the property rather than report a fabricated value. A host MUST treat a refused get as “this device does not report its uptime” and continue.
State Classes
Every piece of device state belongs to exactly one of three classes. The classes determine what survives a host attach, a change of host, and a power cycle.
Session State
State that exists only while a host is attached: transaction (TID)
correlation, transport reassembly buffers, and the session-scoped
properties PROP_MAC_PROMISCUOUS and PROP_MAC_BACKHAUL. Session state
is reset to defaults on every attach. Resetting it never affects radio
operation.
Device Domain
State that belongs to the device itself, independent of which host is attached:
- the device identity keypair (independently persisted; never part of the saved snapshot—see Saved State)
- the device identity’s channel keys (
PROP_DEV_CHANNEL_KEYS) and peer list (PROP_DEV_PEERS) - the RF configuration (
PROP_PHY_*), includingPROP_PHY_ENABLED, and the duty-cycle limit - the human-readable device name (
PROP_DEV_NAME) - live battery telemetry (
PROP_BATTERY), whenCAP_BATTERYis present - device behavior settings (property identifiers 70–95): the repeater
forwarding switch (
PROP_MAC_REPEATER_ENABLED), with the rest of the range reserved for future definition (further repeater policy, positioning, periodic advertisement of the device identity, and similar) - the administrator list (
PROP_DEV_ADMINS) authorizing node management over the mesh - transport configuration such as
PROP_BLE_PAIRING_PIN
The RF configuration is deliberately device-domain: a site repeater keeps its frequency and regulatory limits no matter which phone pairs with it. An attached host may still reconfigure it at any time.
Host Domain
State that belongs to the currently configured tethered host identity:
PROP_HOST_KEYitself- the host’s channel keys and peer keys
- the receive filter table and acknowledgement-delegation policy
- the inbound queue: its configuration and its contents
The host domain is volatile across a power cycle, and only across a power cycle. It MUST NOT be persisted: it is not part of the saved snapshot, and at power-on every host-domain property takes its documented default.
It emphatically does survive a disconnect. A detached radio keeps filtering, queueing and acknowledging on behalf of its host for as long as it stays powered—that is the entire value of the host domain, and nothing about the host going out of range changes what the host wants done.
The two together give the host a simple rule with no detection in it: a host MUST establish its complete host domain on every tethered attach, writing every part of it rather than reasoning about what the device already holds. Key material cannot be compared anyway—the key tables never read it back (see Provisioning Security), so a peer’s pairwise keys can be replaced without changing anything the host can observe. Where the device is already provisioned as asked, the rewrite is redundant; that is preferable to depending on a signal that would also have to cover partial provisioning, another administrator’s intervention, and future device behavior. A boot generation or reset indication MAY be used to skip the rewrite as an optimization, never to decide whether it is needed.
Property Allocation
Property and stream identifiers are allocated by state class and subsystem:
| Range | Class |
|---|---|
| 0–31 | Core protocol state |
| 32–47 | Radio control (PROP_PHY_*) |
| 48–63 | Session-scoped and global protocol state |
| 64–95 | Device domain |
| 96–111 | Host domain (PROP_HOST_*) |
| 112–127 | Streams (STR_*) |
| 4608–4863 | Extended radio control |
| 4864–5119 | Extended device and transport configuration |
Unassigned identifiers in these ranges are reserved. The identifiers in use are listed in the Command and Property Index.
Attach, Detach, and Synchronization
How attach and detach are detected is defined by the transport binding:
- BLE—enabling/disabling notifications on Frame Out, as specified in ULCP over BLE.
- USB-CDC—assertion and deassertion of DTR on the ULCP interface.
- TCP—establishment and closure of the connection.
- Bare UART—implementation-defined. A device with no way to detect host presence MAY treat the host as permanently attached, in which case it never enters detached operation and offline assistance (Inbound Queueing, Acknowledgement Delegation) is unavailable on that transport.
On attach, the device MUST reset session state (see State Classes) and
MUST NOT modify the device or host domains in any way. In particular,
the PHY is not disabled and no property outside session state changes
value. The device MUST NOT emit any frame before attach; the first
frame of the session is the CMD_SESSION_RESET
announcing the session state the attach discarded, with reason 0, and
the attach itself produces no other unsolicited notification.
Because attach no longer implies any known default state, the host synchronizes by fetching, not by assuming. The following post-attach procedure is RECOMMENDED:
CMD_PROP_GETforPROP_LAST_STATUS. If it returns a reset code (see Reset Codes), the device has reset since the last host command, so any state that is not restored from saved state (notably queue contents) has been lost.CMD_PROP_GETforPROP_HOST_KEY. An empty value is the ordinary case after a power cycle—the host domain does not survive one—and the host simply provisions. A value matching the host’s own identity means its provisioning is still live from before the disconnect. Any other value means another host has taken the radio over since this host last attached; the queue and provisioning belong to that identity, and this host must decide whether to take the radio over (see Host Replacement) before doing anything else.CMD_PROP_GETfor the device-domain properties the host depends on (PROP_SAVED, thePROP_PHY_*configuration), and forPROP_HOST_RX_QUEUE_COUNT.- Establish the complete host domain (see Host Domain): write
PROP_HOST_KEY, the key tables, the filter table and the delegation policy in full. The key tables are read back only to find entries the host no longer wants, which it removes; entries it does want are written whether or not the device reports them, since key material is not readable and so cannot be compared. - Issue
CMD_QUEUE_DRAINwhen actually ready to process backlogged traffic.
More generally, a host MUST tolerate unsolicited CMD_PROP_IS,
CMD_PROP_INSERTED, and CMD_PROP_REMOVED notifications at any time
while attached, updating its view of the affected property accordingly:
device state can change for reasons the host did not initiate, and
publication of the new authoritative value is how the protocol reports
that.
The same applies to CMD_SESSION_RESET, which
reports the one change no property notification can: the session itself
starting over. A host that receives one runs this procedure again.
On detach, the device discards session state, keeps operating with the current device- and host-domain state, and begins detached operation: accepted frames are queued rather than delivered, and acknowledgement delegation (if enabled) becomes active.
Provisioning Security
Provisioning moves real key material onto the device, within the limits of the security boundary: channel keys and per-peer symmetric keys—and the device identity’s own private key— but never the host’s private key. The rules:
- All symmetric key material, and the device identity private key, is
write-only.
CMD_PROP_GETand all device-emitted notifications report key-bearing properties without their secrets (see Multi-Value Properties): peer public keys withoutK_ENC/K_MIC, derived channel identifiers instead of channel keys, and never the device private key. This holds for both identities’ key tables. These read-backs let the host verify what is provisioned after a reconnect without any secret ever crossing the link a second time— which matters because more than one host may be able to attach over the radio’s lifetime (transport bonds are possession credentials, not identity credentials), and a later host must not be able to extract an earlier host’s keys. - Commands that carry key material—
CMD_PROP_SETandCMD_PROP_INSERTfor the key tables, and any set ofPROP_DEV_PRIVATE_KEY—MUST NOT be carried over a transport that does not meet the requirements of the transport’s security binding: physical possession for serial transports, or an encrypted bonded LESC link as specified in ULCP over BLE. - A compromised or stolen device exposes the provisioned channels, the provisioned pairwise conversations, and its own device identity, but cannot impersonate the host to any new peer, cannot sign as the host, and cannot decrypt traffic for peers or channels that were never provisioned.
- Hosts SHOULD provision the minimum useful set of peers and channels, SHOULD remove entries that are no longer needed, and SHOULD prefer on-device generation of the device identity over installing one.
- A device advertising
CAP_SAVEMUST store persisted key material in the most protected storage available to it.
Status Codes
Status codes are used for PROP_LAST_STATUS. When a command generates a status
code, it is returned via a CMD_PROP_IS with a property of PROP_LAST_STATUS
and the TID of command it is referring to.
| Id | Name |
|---|---|
| 0 | STATUS_OK |
| 1 | STATUS_FAILURE |
| 2 | STATUS_UNIMPLEMENTED |
| 3 | STATUS_INVALID_ARGUMENT |
| 4 | STATUS_INVALID_STATE |
| 5 | STATUS_INVALID_COMMAND |
| 7 | STATUS_INTERNAL_ERROR |
| 9 | STATUS_PARSE_ERROR |
| 10 | STATUS_IN_PROGRESS |
| 11 | STATUS_NOMEM |
| 12 | STATUS_BUSY |
| 13 | STATUS_PROP_NOT_FOUND |
| 18 | STATUS_CCA_FAILURE |
| 19 | STATUS_ALREADY |
| 20 | STATUS_ITEM_NOT_FOUND |
| 21 | STATUS_CURSOR_INVALID |
| 22 | STATUS_NOT_PERMITTED |
| 23 | STATUS_CHANNEL_NOT_FOUND |
| 32 | STATUS_DUTY_LIMIT |
STATUS_OK- Indicates that the operation has completed successfully.
STATUS_FAILURE- Indicates that the operation has failed for an unspecified reason. The use of this status code SHOULD be avoided. If a more specific status code exists that better explains the failure, then that status code MUST be used instead.
STATUS_UNIMPLEMENTED- Indicates that the given operation has not been implemented.
STATUS_INVALID_ARGUMENT- Indicates that an argument to the given operation is invalid. The value may be out of range or improperly formatted. This status code is also returned when setting an invalid value to a property.
STATUS_INVALID_STATE- Indicates that the given operation is invalid for the current state of the device.
STATUS_INVALID_COMMAND- The given command id is not recognized.
STATUS_INTERNAL_ERROR- An internal runtime error has occurred.
STATUS_PARSE_ERROR- An error has occurred while parsing the command.
STATUS_IN_PROGRESS- Indicates that the operation was started but has not completed, and completion will be reported asynchronously.
STATUS_NOMEM- The operation has been prevented due to memory pressure.
STATUS_BUSY- The device is currently performing a mutually exclusive operation. This status
differs from
STATUS_INVALID_STATEin that it will resolve spontaneously. STATUS_PROP_NOT_FOUND- The given property key is not recognized.
STATUS_ALREADY- The requested state is already in effect; in particular, the item passed
to
CMD_PROP_INSERTis already present in the property. STATUS_ITEM_NOT_FOUND- The item or selector passed to
CMD_PROP_REMOVEdoes not match any item in the property; or the value written by aCMD_PROP_SETnames an item of another property that does not exist, as a write ofPROP_WIFI_NETWORKnames an entry of the known-network table. It is distinct fromSTATUS_INVALID_ARGUMENTbecause a host acts on it differently: the value is well-formed and the item it names has merely to be created first. STATUS_CURSOR_INVALID- The cursor presented in a Node Management continuation is not one the device can honor—it does not parse, it was issued for a different request, or the underlying data has changed so that the position is meaningless. The administrator restarts the read from an initial, cursor-less request.
STATUS_NOT_PERMITTED- The property or command exists, but the binding the request arrived
over is not allowed to perform it—in particular, a Node
Management write to a property
reserved to the tethered host. Distinct from
STATUS_PROP_NOT_FOUNDandSTATUS_INVALID_COMMAND: the operation would be accepted from a binding with the standing to ask. STATUS_CHANNEL_NOT_FOUND- The request names a channel by its channel
identifier and the
device holds no channel key that derives it. Distinct from
STATUS_ITEM_NOT_FOUND, which concerns an item of the property being written, and fromSTATUS_INVALID_ARGUMENT: the value is well formed, and the channel has only to be provisioned first (PROP_DEV_CHANNEL_KEYS). STATUS_CCA_FAILURE- The packet was not sent due to a CCA failure. This status code is only emitted when sending data to a packet stream with a TID other than zero.
STATUS_DUTY_LIMIT- The packet cannot be sent because it would exceed the currently set duty-cycle limit.
Reset Codes
All status codes which fall into the inclusive range of 112-127 are considered
reset codes. These codes are emitted asynchronously after a device reset and
provide a way to differentiate different causes of resets. If the first command
the host sends to the device after a reset is to fetch PROP_LAST_STATUS, then
the reset code MUST be returned.
Note
On a device holding a saved snapshot, the post-reset value of every saved property is its saved value rather than the documented default. A host MUST NOT assume that a reset implies documented factory defaults; it should fetch or explicitly set the properties it depends on. Without a snapshot the documented post-reset values apply unconditionally.
| Id | Name |
|---|---|
| 112 | STATUS_RESET_POWER_ON |
| 113 | STATUS_RESET_EXTERNAL |
| 114 | STATUS_RESET_SOFTWARE |
| 115 | STATUS_RESET_RESTORED |
| 116 | STATUS_RESET_CRASH |
| 117 | STATUS_RESET_ASSERT |
| 118 | STATUS_RESET_OTHER |
| 119 | STATUS_RESET_UNKNOWN |
| 120 | STATUS_RESET_WATCHDOG |
Of these defined reset codes, only STATUS_RESET_POWER_ON,
STATUS_RESET_EXTERNAL, STATUS_RESET_SOFTWARE, and
STATUS_RESET_RESTORED are emitted during normal operation. All other
reset codes generally indicate some sort of software bug or hardware
failure.
Unexpected or unrequested resets are always an indication of a problem, no matter what the code value is.
A session reset is not one of these. Discarding session state costs the
host what it established there and nothing more, so it is announced by
CMD_SESSION_RESET and leaves PROP_LAST_STATUS
alone. Every reset code above implies a session reset; none of them is
implied by one.
STATUS_RESET_POWER_ON- Cold power-on start.
STATUS_RESET_EXTERNAL- External device reset. This is generally caused by RESET pin on the device being asserted.
STATUS_RESET_SOFTWARE- Software-requested orderly reset. This is generally caused by the host
sending the device
CMD_RST. STATUS_RESET_RESTORED- Protocol reset into the saved snapshot, emitted when a device completes
CMD_RESTOREin its reset form (seeCMD_RESTORE). Unlike the other reset codes, this one does not indicate a hardware or firmware restart: the transport link and attach state survive it. STATUS_RESET_CRASH- Unrecoverable software execution failure, like a segmentation fault or a stack overflow.
STATUS_RESET_ASSERT- Software invariant property not respected.
STATUS_RESET_OTHER- Unspecified cause.
STATUS_RESET_UNKNOWN- Failure while recovering cause of reset.
STATUS_RESET_WATCHDOG- Watchdog timer expired, forcing a reset.
Capabilities
Capabilities are how a device can advertise support for specific behaviors and
functionalities. They can be fetched via the PROP_CAPS property.
Each capability is defined by the chapter that specifies the behavior it grants:
| Code | Name | Requires | Defined in |
|---|---|---|---|
| 8 | CAP_WRITABLE_RAW_STREAM | — | Frame Transport |
| 16 | CAP_PHY_DUTY_LIMIT | — | Radio Control |
| 32 | CAP_HOST_FILTER | — | Tethered Host Services |
| 33 | CAP_HOST_RX_QUEUE | CAP_HOST_FILTER | Tethered Host Services |
| 34 | CAP_HOST_KEYS | CAP_HOST_FILTER | Tethered Host Services |
| 35 | CAP_HOST_AUTO_ACK | CAP_HOST_KEYS, CAP_HOST_RX_QUEUE | Tethered Host Services |
| 36 | CAP_SAVE | — | Saved State |
| 37 | CAP_DEV_IDENTITY | — | Device Domain |
| 38 | CAP_DEV_NAME | — | Device Domain |
| 39 | CAP_BATTERY | — | Device Domain |
| 40 | CAP_REPEATER | CAP_DEV_IDENTITY | Device Domain |
| 41 | CAP_IDENT | CAP_DEV_IDENTITY | Device Domain |
| 42 | CAP_ALERT | — | Device Domain |
| 43 | CAP_ADMIN | CAP_DEV_IDENTITY, CAP_CMD_MULTI | Node Management |
| 44 | CAP_TIME | — | Device Domain |
| 45 | CAP_GNSS | CAP_TIME | Device Domain |
| 46 | CAP_ADVERT | CAP_DEV_IDENTITY | Device Domain |
| 47 | CAP_ILLUMINANCE | — | Device Domain |
| 48 | CAP_MAC_BACKHAUL | CAP_REPEATER | Tethered Host Services |
| 49 | CAP_CMD_MULTI | — | Framing and Common Semantics |
| 50 | CAP_BLE | — | BLE Binding |
| 51 | CAP_REBOOT | — | Framing and Common Semantics |
| 52 | CAP_STATS | — | Radio Control |
| 53 | CAP_WIFI_SCAN | — | Wi-Fi |
| 54 | CAP_WIFI | CAP_WIFI_SCAN | Wi-Fi |
| 55 | CAP_IPV4 | — | IP Connectivity |
| 56 | CAP_IPV6 | — | IP Connectivity |
| 57 | CAP_WIFI_AP | CAP_WIFI_SCAN | Wi-Fi |
| 515 | CAP_PHY_LORA | — | Radio Control |
A device MUST NOT advertise a capability without also advertising the
capabilities it requires. Apart from the multi-property commands, which
CAP_CMD_MULTI gates, CMD_REBOOT, which CAP_REBOOT gates, and
CMD_ANNOUNCE, which CAP_ADVERT gates, the
commands and status codes defined in this chapter are unconditional and
need no capability; a device that defines no
mutable multi-value properties simply has nothing to apply
CMD_PROP_INSERT/CMD_PROP_REMOVE to.