1 - ULS-DeCoNet Protocol Interface Control Document
ULSDC-PBICD011125 · version 1.0.5 · issued November 13, 2025
The numbered PDF is the controlled copy: download it from the portal.
Introduction
Purpose
The ULS-DeCoNet (ULS Devices Connection Network) protocol is a comprehensive communication protocol designed for Ultra-precise Location Systems (ULS). It provides a robust, hierarchical network architecture for connecting ULS devices across multiple transport mediums including UART and CAN bus.
Scope
This protocol defines:
- Device discovery and network management
- Object-oriented data exchange
- System control and configuration
- Firmware update mechanisms
- Multi-hop routing capabilities
- Blitz sensor data transmission
Key Features
- Multi-transport Support: UART (with various framing modes) and CAN bus
- Automatic Device Discovery: Dynamic network topology with automatic ID allocation
- Hierarchical Addressing: Support for up to 63 local devices per interface
- Multi-hop Routing: Packet forwarding through intermediate nodes
- Object-based Data Model: Structured access to device parameters and data
- Permission System: Read/write/protected access control for objects
- Firmware Update: Secure bootloader mode with signature verification
- Low Overhead: Optimized for embedded systems with limited resources
Terminology
| Term | Description |
|---|---|
| DID | Device ID - Logical identifier for devices on a network segment (0-63) |
| LID | Local ID - Synonym for DID |
| CID | Connection ID - Identifies which connection interface (0-3) |
| HB | Heartbeat - Periodic keep-alive message |
| NM | Network Management - Protocol layer for device discovery |
| CN | Connection - Higher-level protocol for data exchange |
| Blitz | Fast sensor data messaging subsystem |
| MRX | Multi-Receiver eXtension - Secondary receiver support |
| GIMU | Ground IMU - Inertial Measurement Unit on transmitter |
| TXC | Transmitter Control - Ground unit control interface |
Protocol Architecture
Protocol Stack
block-beta columns 1 A["Application Layer\n(Device Objects, Blitz Messages, Config)"] B["Connection Layer (CN)\n(Object Access, System Commands, Routing)"] C["Interface Layer (IF)\n(Network Management, Device Discovery)"] D["Framing Layer\n(UART: ESC/COBS, CAN: Multi-frame)"] E["Physical Layer\n(UART, CAN/FDCAN)"]
Design Principles
- Layered Architecture: Clear separation of concerns between protocol layers
- Transport Agnostic: Core protocol independent of physical medium
- Efficient Framing: Multiple framing modes optimized for different scenarios
- Scalable Addressing: Support for hierarchical and flat addressing schemes
- Robust Error Handling: CRC protection and timeout-based error recovery
- Plug-and-Play: Automatic device discovery and ID allocation
OSI Layer Model Mapping
The ULS-DeCoNet protocol maps to the OSI reference model as follows:
| OSI Layer | ULS-DeCoNet Component | Responsibility |
|---|---|---|
| 7. Application | ULSObject, ULSDBase, Blitz Messages | Device-specific data, sensor measurements, configuration |
| 6. Presentation | Data Structures (packed structs) | Data formatting, byte ordering (little-endian) |
| 5. Session | ULSBusConnection | Connection establishment, session management |
| 4. Transport | CN Protocol Layer | Reliable message delivery, routing, flow control |
| 3. Network | IF Protocol Layer | Addressing, device discovery, network management |
| 2. Data Link | Framing (ESC/COBS/CAN) | Frame delimiting, error detection (CRC) |
| 1. Physical | UART/CAN Hardware | Physical signaling, bit transmission |
Layer Interactions
Application Data (Objects/Blitz)
↓
[CN Layer]
- Add routing information
- Add command type
↓
[IF Layer]
- Add source LID
- Add command flags
- Network management
↓
[Framing Layer]
- Add frame delimiters
- Add CRC
- Escape special characters (UART)
- Multi-frame splitting (CAN)
↓
[Physical Layer]
- Transmit bytes/frames
Physical Layer
UART Physical Layer
Specifications:
- Data Format: 8-N-1 (8 data bits, no parity, 1 stop bit)
- Baud Rates: Configurable (typically 115200, 230400, 460800, 921600 bps)
- Voltage Levels: Device-dependent (typically 3.3V or 5V TTL/RS232)
- Flow Control: Optional hardware (RTS/CTS) or software (XON/XOFF)
Advantages:
- Simple two-wire interface
- Widely supported
- Point-to-point or multi-drop with appropriate hardware
Limitations:
- Distance limitations without level shifters
- No built-in arbitration for multi-device scenarios
CAN Physical Layer
Specifications:
- CAN Version: Classical CAN and CAN-FD (FDCAN) supported
- Bit Rates:
- Classical CAN: Up to 1 Mbps
- CAN-FD: Up to 5 Mbps (data phase)
- Bus Topology: Multi-drop differential bus
- Termination: 120Ω termination resistors required at both ends
- Max Devices: Theoretically unlimited (practical limit ~32-64)
- Max Distance: Up to 40m @ 1Mbps, longer at lower speeds
Advantages:
- Multi-master capability with arbitration
- Built-in error detection and signaling
- Robust in electrically noisy environments
- Supports broadcast and multicast
CAN Identifiers:
- Standard 11-bit identifiers used
- Identifier structure defined by implementation
Data Link Layer
The Data Link Layer provides reliable frame transmission with error detection. Different framing modes are supported for UART, while CAN has its own native framing.
UART Framing Modes
The protocol supports four UART framing modes:
RAW Mode (SERIAL_MODE_RAW)
Description: No framing - direct byte transmission
Use Case: Binary data transfer when frame boundaries are managed at higher layers
Structure:
[DATA BYTES...]
Characteristics:
- No overhead
- No frame delimiting
- No error detection at this layer
- Highest throughput
- Requires higher layer to manage message boundaries
ESC Mode (SERIAL_MODE_ESC)
Description: Frame delimiting with byte stuffing and CRC-16
Frame Structure:
packet-beta title "ESC Mode Frame Structure" 0-7: "SOF 0x55 (1 byte)" 8-15: "START_TYPE 0x01 (1 byte)" 16-23: "PAYLOAD (variable, ~1 byte)" 24-31: "CRC_LOW (1 byte)" 32-39: "CRC_HIGH (1 byte)" 40-47: "EOF 0x55 (1 byte)" 48-55: "END_TYPE 0x03 (1 byte)"
Byte Stuffing:
- If data byte ==
0x55, insert0x02after it - Delimiter
0x55is escaped when it appears in payload or CRC
CRC Calculation:
- Algorithm: CRC-16 (polynomial 0x8005, init 0xFFFF)
- Applied to payload only
- 2 bytes transmitted (low byte, high byte)
Example:
Original payload: [0x12, 0x55, 0x34]
CRC: 0xABCD
Transmitted frame:
0x55 0x01 0x12 0x55 0x02 0x34 0xCD 0xAB 0x55 0x03
Characteristics:
- Frame boundaries clearly defined
- Error detection with CRC-16
- Variable overhead (depends on data content)
- Average overhead: ~15-25%
ESC Simple CRC Mode (SERIAL_MODE_ESC_SIMPLE_CRC)
Description: Similar to ESC mode but with simpler 8-bit checksum
Frame Structure:
packet-beta title "ESC Simple Mode Frame Structure (8-bit Checksum)" 0-7: "SOF 0x55 (1 byte)" 8-15: "START_TYPE 0x01 (1 byte)" 16-23: "PAYLOAD (variable, ~1 byte)" 24-31: "CHECKSUM (1 byte)" 32-39: "EOF 0x55 (1 byte)" 40-47: "END_TYPE 0x03 (1 byte)"
Checksum:
- Simple byte summation:
checksum = Σ(data_bytes) & 0xFF - 1 byte transmitted
Characteristics:
- Faster than CRC-16
- Lower error detection capability
- Less overhead than full ESC mode
- Suitable for low-error-rate environments
COBS Mode (SERIAL_MODE_COBS)
Description: Consistent Overhead Byte Stuffing with CRC-16
Advantages:
- Predictable framing overhead
- Zero byte (
0x00) used as frame delimiter - No data expansion for most byte values
- Very efficient for binary data
Frame Structure:
packet-beta title "COBS Mode Frame Structure" 0-7: "SOF 0x00 (1 byte)" 8-15: "COBS CODE (1 byte)" 16-79: "ENCODED DATA (variable, ~8 bytes)" 80-87: "CRC_LOW (1 byte)" 88-95: "CRC_HIGH (1 byte)" 96-103: "EOF 0x00 (1 byte)"
COBS Encoding Algorithm:
- Packet is divided into blocks separated by zero bytes
- Each block is preceded by a code byte:
- Code byte = number of non-zero bytes following + 1
- Maximum block size = 254 bytes
- Code byte
0xFFmeans 254 non-zero bytes follow
Example:
Original data: [0x45, 0x00, 0x00, 0x2C, 0x4C]
COBS encoded: [0x02, 0x45, 0x01, 0x03, 0x2C, 0x4C]
^^^^^ ^^^^ ^^^^ ^^^^^ ^^^^^^^^^^
code data code code data data
With frame delimiters:
0x00 0x02 0x45 0x01 0x03 0x2C 0x4C [CRC_L] [CRC_H] 0x00
COBS Characteristics:
- Overhead: +1 byte per 254 bytes + frame delimiters
- Maximum overhead: ~0.4% + fixed overhead
- Excellent for binary protocols
- No byte escaping needed
- Efficient zero-crossing detection
CRC Calculation in COBS:
- CRC-16 calculated on original unencoded data
- CRC bytes are COBS encoded with the data
CAN Framing
CAN bus has built-in framing at the hardware level, but ULS-DeCoNet adds an additional application-level framing layer for large messages.
Single-Frame CAN Messages
Structure:
packet-beta title "Single-Frame CAN Message (8-byte data field)" 0-7: "CMD (1 byte)" 8-15: "SRC (1 byte)" 16-23: "(varies) (1 byte)" 24-87: "PAYLOAD (variable, ~8 bytes)"
Field Description:
- Byte 0 (CMD): Command type (IF layer command)
- Byte 1 (SRC): Source device ID (bits 0-5), connection ID (bits 6-7)
- Bytes 2+: Command-specific payload
Used for:
- Network management messages (HB, REQUEST_ID, SET_ID)
- Blitz messages (up to 10 bytes payload)
- Short system commands
Multi-Frame CAN Messages
For messages larger than can fit in a single CAN frame, multi-frame protocol is used.
Frame Structure:
packet-beta title "Multi-Frame CAN Message" 0-7: "CMD (1 byte)" 8-15: "DID (1 byte)" 16-23: "FRMCTL (1 byte)" 24-95: "PAYLOAD (variable, ~9 bytes)"
FRMCTL byte: Bit 7 = End-of-message flag (1 = last frame); Bits 6-0 = Frame sequence number (0–127)
Multi-Frame Protocol:
- Frame Sequence: Frames numbered 0, 1, 2, … N
- Last Frame Marker: Frame N has bit 7 set (value = N | 0x80)
- Payload per Frame: 9 bytes (DLC = 11, minus 3 header bytes)
- Frame Pool: Receiver maintains a pool of 256 frame buffers
- Timeout: Device timeout of 128 frames worth of time
Transmission Algorithm:
total_frames = ceil(message_len / 9)
for frame_num in 0..total_frames-1:
can_frame.data[0] = CMD
can_frame.data[1] = SRC_DID
can_frame.data[2] = frame_num
if frame_num == total_frames-1:
can_frame.data[2] |= 0x80 // Mark last frame
copy up to 9 bytes to can_frame.data[3..11]
send_can_frame()
Reception Algorithm:
On receiving CAN frame:
1. Store frame in pool indexed by (DID, frame_num)
2. Set device timeout
3. If last_frame_flag:
a. Verify all frames 0..N received
b. Reconstruct message from frames
c. If complete: process message
d. If incomplete: log missing frames, discard
e. Free pool entries for this DID
Frame Pool Management:
- Pool Size: 256 frame slots
- Device Table: 64 device entries with timeouts
- Timeout Value:
CN_CAN_DEV_TIMEOUT= 128 frames - Cleanup: On timeout, all frames from device are freed
Example Multi-Frame Message:
Message length: 25 bytes
Frames needed: 3 (9+9+7)
Frame 0: [CMD][DID][0x00][data 0-8]
Frame 1: [CMD][DID][0x01][data 9-17]
Frame 2: [CMD][DID][0x82][data 18-24][pad]
^^^^
0x80 | 0x02 = last frame, number 2
Error Handling:
- Missing frame detection by sequence number gaps
- Device timeout triggers cleanup
- Duplicate frames overwrite previous (allows retransmission)
- Pool full triggers emergency cleanup of timed-out devices
CRC-16 Algorithm
Polynomial: 0x8005 (CRC-16-IBM/ANSI)
Initial Value: 0xFFFF
Table-based implementation for efficiency
uint16_t crc = 0xFFFF;
for each byte in data:
crc = (crc >> 8) ^ crc16_table[(crc ^ byte) & 0xFF]
Validation:
- Receiver calculates CRC over received data
- Valid frame: calculated CRC == 0x0000 (after including received CRC bytes)
Network Layer
The Network Layer (IF Layer) manages device addressing, discovery, and basic packet routing.
Addressing Scheme
Device ID (DID/LID)
Range: 0-63 (6 bits)
| ID Range | Usage |
|---|---|
| 0 | Master device (network controller) |
| 1-62 | Regular network nodes |
| 63 | Broadcast address / Uninitialized device |
Special IDs:
- ID 0: Reserved for the master device (typically the main controller or coordinator)
- ID 63: Used by devices before ID assignment and for broadcast messages
Connection ID (CID)
Range: 0-3 (2 bits)
Identifies which physical connection a device uses when a node has multiple network interfaces.
Combined Routing ID (CNRID):
CNRID = (CID << 6) | DID
= [CID(2)][DID(6)]
Bits: 7 6 5 4 3 2 1 0
└─┘ └─────────┘
CID DID
Network Management (NM) Protocol
The NM protocol handles device discovery and ID allocation.
Device States
stateDiagram-v2 [*] --> UNINITIALIZED: Power On (DID=63) UNINITIALIZED --> WaitingSetID: Send REQUEST_ID WaitingSetID --> OK: Receive SET_ID (DID assigned) OK --> OK: Send HB / Timeout
NM Messages
IF_CMD_NM_HB (0x01) - Heartbeat
Purpose: Keep-alive message to announce presence
Structure:
packet-beta title "IF_CMD_NM_HB (0x01) Heartbeat" 0-7: "CMD 0x01 (1 byte)" 8-15: "SRC (DID) (1 byte)" 16-47: "UID0 (4 bytes)"
Fields:
- CMD: 0x01
- SRC: Source device ID
- UID0: Device unique ID (first 32 bits)
Timing:
- Send Interval: Every 1000ms (
IF_NM_PING_HB_TIMEOUT) - Receive Timeout: 3000ms (
IF_NM_DVICE_HB_TIMEOUT) - Device considered disconnected if no HB received within timeout
Behavior:
- All devices with assigned ID send periodic HB
- Master and slaves both participate
- Timeout detection triggers disconnection callback
IF_CMD_NM_REQUEST_ID (0x03) - Request ID Allocation
Purpose: Device requests ID assignment from master
Structure:
packet-beta title "IF_CMD_NM_REQUEST_ID (0x03)" 0-7: "CMD 0x03 (1 byte)" 8-15: "SRC 63 (1 byte)" 16-47: "KEY (4 bytes)"
Fields:
- CMD: 0x03
- SRC: 63 (uninitialized)
- KEY: Random 32-bit key derived from device UID
Key Generation:
key = DEVICE_KEY ^ key_counter
where DEVICE_KEY = UID0 ^ UID1 ^ UID2 ^ UID3
Timing:
- Sent every 100ms + random offset
- Up to 5 attempts
- If no master responds, device self-assigns random free ID
IF_CMD_NM_SET_ID (0x04) - ID Assignment
Purpose: Master assigns ID to requesting device
Structure:
packet-beta title "IF_CMD_NM_SET_ID (0x04)" 0-7: "CMD 0x04 (1 byte)" 8-15: "SRC 0 (1 byte)" 16-23: "NEW_ID (1 byte)" 24-55: "KEY (4 bytes)"
Fields:
- CMD: 0x04
- SRC: 0 (master device)
- NEW_ID: Assigned device ID (1-62)
- KEY: The key from REQUEST_ID message
ID Allocation Algorithm (Master):
1. Maintain table of active devices (timeout-based)
2. On REQUEST_ID received:
a. Scan table for first free ID (timeout == 0)
b. Assign that ID
c. Send SET_ID with matching KEY
d. Set timeout for new device
Reception (Requesting Device):
1. Receive SET_ID
2. Verify KEY matches own key
3. If match:
a. Set DID = NEW_ID
b. Change state to OK
c. Send immediate HB
4. If no match:
Ignore (not for us)
IF_CMD_NM_RESET_ID (0x05) - Reset Device ID
Purpose: Force device to return to uninitialized state
Structure:
packet-beta title "IF_CMD_NM_RESET_ID (0x05)" 0-7: "CMD 0x05 (1 byte)" 8-15: "SRC 0 (1 byte)" 16-23: "DST_DID (1 byte)"
Note: Defined but not fully implemented in current version
Static ID Assignment
Method: ifSetStaticDID(uint8_t static_did)
Devices can be configured with static IDs (1-62) that bypass the dynamic allocation process.
Usage:
- Configuration storage in device
- Fixed topology networks
- Deterministic addressing requirements
Behavior:
- Device uses static ID immediately
- Still sends HB for presence indication
- Bypasses REQUEST_ID mechanism
Network Topology
The IF layer supports various network topologies:
Star Topology
flowchart TB Master["Master (ID=0)"] --> N1["Node (1)"] Master --> N2["Node (2)"] Master --> N3["Node (3)"]
Characteristics:
- Single master (ID=0)
- All slaves connect directly to master
- Master performs ID allocation
- Common for UART bus configurations
Multi-Master (CAN)
flowchart LR N0["(0)"] --- N1["(1)"] --- N2["(2)"] --- N3["(3)"] N0 --- N4["(4)"] N3 --- N5["(5)"] N4~~~N5
CAN BUS (shared medium)
Characteristics:
- Any device can be master (first ID=0 or all peer)
- Peer-to-peer communication possible
- ID allocation can be distributed
- Typical for CAN bus configurations
Packet Structure (IF Layer)
packet-beta title "IF Layer Packet Structure" 0-7: "CMD (1 byte)" 8-15: "SRC_LID (1 byte)" 16-79: "PAYLOAD (variable, ~8 bytes)"
CMD Field (1 byte):
- Bit 4: Frame type flag
0x00-0x0F: Network management / System commands0x10-0x1F: Higher layer protocols (CN layer)
- Bits 3-0: Command code
IF Layer Commands:
| Code | Name | Description |
|---|---|---|
| 0x00 | IF_CMD_SYS | System command |
| 0x01 | IF_CMD_NM_HB | Network heartbeat |
| 0x02 | IF_CMD_NM_GET_STATUS | Get device status |
| 0x03 | IF_CMD_NM_REQUEST_ID | Request ID allocation |
| 0x04 | IF_CMD_NM_SET_ID | Assign device ID |
| 0x05 | IF_CMD_NM_RESET_ID | Reset device ID |
| 0x06 | IF_CMD_BLITZ | Blitz sensor data |
Transport Layer
The Transport Layer (CN - Connection Layer) provides routing, object access, and system management.
CN Protocol Overview
The Connection layer adds:
- Multi-hop routing
- Object-oriented data access
- System configuration and firmware update
- Reliable request-response patterns
Routing Mechanism
Route Table
Routes are stored as arrays of routing IDs (CNRID):
Route = [hop0, hop1, hop2, ..., hopN]
Each hop contains:
- Bits 7-6: CID (Connection ID)
- Bits 5-0: DID (Device ID)
Route Direction:
- Forward Route (command): hop0 = source, hopN = destination
- Reverse Route (response): route is reversed
CN Packet Structure
packet-beta title "CN Packet Structure" 0-7: "CMD (1 byte)" 8-15: "SRC_DID (1 byte)" 16-23: "HOP (1 byte)" 24-79: "ROUTE (variable, ~8 bytes)" 80-143: "PAYLOAD (variable, ~8 bytes)"
HOP byte: Bits 7-4 = current hop index; Bits 3-0 = route size
Packet Fields:
- CMD: CN command type
- SRC_DID: Original source device ID
- HOP: Hop counter (high nibble) and route size (low nibble)
- ROUTE: Array of CNRID values defining path
- PAYLOAD: Command-specific data
Routing Example
Scenario: Device A (DID=1, CID=0) sends message to Device C (DID=3, CID=2) through Device B (DID=2, CID=1)
Forward Packet (A→B→C):
At A:
CMD = CN_CMD_GETOBJ
SRC_DID = 1
HOP = 0x03 (hop=0, route_size=3)
ROUTE = [0x01, 0x42, 0x83]
^^^^ ^^^^ ^^^^
A B C
CID=0 CID=1 CID=2
DID=1 DID=2 DID=3
At B (forwarding):
- Increment hop: HOP = 0x13 (hop=1, route_size=3)
- Next destination = ROUTE[1] = 0x42 (DID=2)
- Forward to CID=1
At C (final destination):
- hop == route_size-1, packet is for us
- Process CN_CMD_GETOBJ
Response Packet (C→B→A):
At C:
CMD = CN_ACK_GETOBJ
SRC_DID = 3
HOP = 0x03 (hop=0, route_size=3)
ROUTE = [0x83, 0x42, 0x01] // Reversed!
^^^^ ^^^^ ^^^^
C B A
Routing process same as forward
Route Discovery
Routes are built dynamically through Explorer messages:
- Master sends
CN_CMD_EXPLORERwith empty route - Each device:
- Adds its CNRID to route
- Forwards to all connections
- Responds with
CN_ACK_EXPLORERcontaining reverse route
- Master builds topology map from responses
CN Commands
Command Types
| Code | Name | Description |
|---|---|---|
| 0x10 | CN_CMD_EXPLORER | Network exploration |
| 0x11 | CN_ACK_EXPLORER | Explorer response with status |
| 0x12 | CN_CMD_SYS | System command |
| 0x13 | CN_ACK_SYS | System command acknowledgment |
| 0x14 | CN_CMD_GETOBJ | Get object data |
| 0x15 | CN_ACK_GETOBJ | Object data response |
| 0x16 | CN_CMD_SETOBJ | Set object data |
| 0x17 | CN_ACK_SETOBJ | Set object acknowledgment |
Explorer Protocol
CN_CMD_EXPLORER (0x10)
Purpose: Discover network topology
Structure:
packet-beta title "CN_CMD_EXPLORER (0x10)" 0-7: "0x10 (1 byte)" 8-15: "SRC_DID (1 byte)" 16-23: "HOP (1 byte)" 24-87: "ROUTE (variable, ~8 bytes)"
Transmission:
1. Master sends with HOP=0x00, empty route
2. Each device receives:
a. Append own CNRID to route
b. If HOP < 15:
- Increment HOP
- Forward to all other connections
c. Send CN_ACK_EXPLORER with reverse route
CN_ACK_EXPLORER (0x11)
Purpose: Respond to explorer with device info
Structure:
packet-beta title "CN_ACK_EXPLORER (0x11)" 0-7: "0x11 (1 byte)" 8-15: "SRC_DID (1 byte)" 16-23: "HOP (1 byte)" 24-79: "ROUTE (variable, ~8 bytes)" 80-111: "TYPE (4 bytes)" 112-239: "NAME (16 bytes)"
Fields:
- TYPE: Device type code (uint32_t)
- NAME: Device name (null-terminated string, max 16 chars)
Object Access
CN_CMD_GETOBJ (0x14) - Read Object
Purpose: Read data from device object
Request Structure:
packet-beta title "CN_CMD_GETOBJ (0x14) Request" 0-7: "0x14 (1 byte)" 8-15: "SRC_DID (1 byte)" 16-23: "HOP (1 byte)" 24-79: "ROUTE (variable, ~8 bytes)" 80-95: "OBJ_ADDR (2 bytes)"
Fields:
- OBJ_ADDR: Object address/ID (uint16_t)
Response (CN_ACK_GETOBJ):
packet-beta title "CN_ACK_GETOBJ (0x15) Response" 0-7: "0x15 (1 byte)" 8-15: "SRC_DID (1 byte)" 16-23: "HOP (1 byte)" 24-79: "ROUTE (variable, ~8 bytes)" 80-95: "OBJ_ADDR (2 bytes)" 96-159: "OBJ_DATA (variable, ~8 bytes)"
Process:
- Request routed to target device
- Device looks up object by OBJ_ADDR
- Check read permission
- If OK: respond with object data
- If error: no response or error code
CN_CMD_SETOBJ (0x16) - Write Object
Purpose: Write data to device object
Request Structure:
packet-beta title "CN_CMD_SETOBJ (0x16) Request" 0-7: "0x16 (1 byte)" 8-15: "SRC_DID (1 byte)" 16-23: "HOP (1 byte)" 24-79: "ROUTE (variable, ~8 bytes)" 80-95: "OBJ_ADDR (2 bytes)" 96-159: "OBJ_DATA (variable, ~8 bytes)"
Response (CN_ACK_SETOBJ):
packet-beta title "CN_ACK_SETOBJ (0x17) Response" 0-7: "0x17 (1 byte)" 8-15: "SRC_DID (1 byte)" 16-23: "HOP (1 byte)" 24-79: "ROUTE (variable, ~8 bytes)" 80-95: "OBJ_ADDR (2 bytes)"
Process:
- Request routed to target device
- Device looks up object by OBJ_ADDR
- Check write permission
- If OK: write data, respond with ACK
- If error: no response or error code
System Commands
CN_CMD_SYS (0x12) - System Operations
Purpose: Device configuration and firmware update
Structure:
packet-beta title "CN_CMD_SYS (0x12)" 0-7: "0x12 (1 byte)" 8-15: "SRC_DID (1 byte)" 16-23: "HOP (1 byte)" 24-79: "ROUTE (variable, ~8 bytes)" 80-87: "SYSCMD (1 byte)" 88-151: "SYS_PAYLOAD (variable, ~8 bytes)"
System Sub-Commands:
| Code | Name | Description |
|---|---|---|
| 0 | CN_SYS_CMD_PING | Ping device |
| 1 | CN_SYS_CMD_SETMODE | Set operational mode |
| 2 | CN_SYS_CMD_ERASE | Erase flash memory |
| 3 | CN_SYS_CMD_WRITE | Write flash memory |
| 4 | CN_SYS_CMD_SETSIGNATURE | Set firmware signature |
| 5 | CN_SYS_CMD_SAVECFG | Save configuration |
PING (0x00)
Request:
packet-beta title "SYS PING (0x00) Request" 0-7: "SYSCMD 0x00 (1 byte)" 8-23: "DEVTYPE (2 bytes)"
Response: Operation result (CN_ACK_SYS)
SETMODE (0x01)
Purpose: Switch between application and bootloader mode
Request:
┌─────────┬──────┐
│ SYSCMD │ MODE │
│ 0x01 │(1 b) │
└─────────┴──────┘
MODE values:
0 = CN_SYS_MODE_APP (application)
1 = CN_SYS_MODE_LOADER (bootloader)
Usage:
- Switch to loader mode for firmware update
- Requires device reset after mode change
ERASE (0x02)
Purpose: Erase flash memory region
Request:
packet-beta title "SYS ERASE (0x02)" 0-7: "SYSCMD 0x02 (1 byte)" 8-39: "KEY (4 bytes)" 40-71: "START (4 bytes)" 72-103: "LEN (4 bytes)"
Fields:
- KEY: Operation authorization key
- START: Start address in flash
- LEN: Length to erase (bytes)
Response: Operation result with status code
WRITE (0x03)
Purpose: Write data to flash memory
Request:
packet-beta title "SYS WRITE (0x03)" 0-7: "SYSCMD 0x03 (1 byte)" 8-39: "KEY (4 bytes)" 40-71: "START (4 bytes)" 72-103: "LEN (4 bytes)" 104-135: "DATA (up to 512 bytes)"
Fields:
- KEY: Operation authorization key
- START: Start address in flash
- LEN: Length to write (bytes)
- DATA: Data to write
Response: Operation result with status code
SETSIGNATURE (0x04)
Purpose: Set firmware signature information
Request:
packet-beta title "SYS SETSIGNATURE (0x04)" 0-7: "SYSCMD 0x04 (1 byte)" 8-39: "KEY (4 bytes)" 40-295: "FW version (32 bytes)" 296-551: "LDR version (32 bytes)" 552-583: "FWTIME (4 bytes)" 584-615: "PROGSIZE (4 bytes)" 616-647: "PROGCRC (4 bytes)"
Fields:
- KEY: Operation authorization key
- FW: Firmware version string (32 chars)
- LDR: Loader version string (32 chars)
- FWTIME: Firmware flashing timestamp
- PROGSIZE: Program size in bytes
- PROGCRC: Program CRC32 checksum
Purpose: Store metadata after firmware update completion
SAVECFG (0x05)
Purpose: Save current configuration to non-volatile memory
Request:
packet-beta title "SYS SAVECFG (0x05)" 0-7: "SYSCMD 0x05 (1 byte)" 8-39: "KEY (4 bytes)"
CN_ACK_SYS (0x13) - System Command Response
Structure:
packet-beta title "CN_ACK_SYS (0x13)" 0-7: "0x13 (1 byte)" 8-15: "SRC_DID (1 byte)" 16-23: "HOP (1 byte)" 24-79: "ROUTE (variable, ~8 bytes)" 80-87: "RESULT (1 byte)"
Result Codes:
| Code | Name | Description |
|---|---|---|
| 0 | CN_SYS_OPERATION_UNDEFINED | Operation not defined |
| 1 | CN_SYS_OPERATION_OK | Operation successful |
| 2 | CN_SYS_OPERATION_ERROR | Operation failed |
| 3 | CN_SYS_OPERATION_WRONGKEY | Invalid authorization key |
Operation Keys
Purpose: Prevent unauthorized firmware modifications
Key Generation:
#define _ULS_OPERATION_KEY 0x24041982
#define DEVICE_KEY (UID0 ^ UID1 ^ UID2 ^ UID3)
uint32_t operation_key = _ULS_OPERATION_KEY;
// Or device-specific key for some operations
Usage:
- ERASE, WRITE, SETSIGNATURE, SAVECFG require valid key
- Key validation prevents accidental or malicious operations
- Each device can have unique key derived from UID
Application Layer
The Application Layer defines device-specific data structures and high-level protocols.
Object Model
Object Architecture
Objects provide structured access to device parameters, configuration, and data.
Object Base Class:
class ULSObjectBase {
uint16_t id; // Object address
uint16_t size; // Size of single element
uint16_t len; // Array length (1 for scalar)
uint8_t *data; // Pointer to data
const char *name; // Object name
const char *description; // Object description
_ulsbus_obj_permissions permission; // Access permission
}
Object Permissions
| Permission | Value | Read | Write | Description |
|---|---|---|---|---|
| READONLY | 0 | ✓ | ✗ | Read-only data |
| WRITEONLY | 1 | ✗ | ✓ | Write-only (e.g., commands) |
| READWRITE | 2 | ✓ | ✓ | Full access |
| PROTECTED | 3 | ✓ | ✓* | Requires authorization |
| CONFIG | 4 | ✓ | ✓* | Configuration parameters |
| SYSCONFIG | 5 | ✓ | ✓* | System configuration |
| ADMIN | 6 | ✓ | ✓* | Administrator only |
*Note: Protected/Config/Admin levels require additional authorization mechanisms (implementation-specific)
Standard Objects
System Signature Object (0x0001)
Purpose: Device identification and firmware information
Structure:
struct ULSObjectSignature {
char fw[32]; // Firmware version
char ldr[32]; // Loader/bootloader version
uint32_t serial[4]; // Device serial number (UID)
uint32_t progflashingtime; // Firmware flash timestamp
uint32_t progsize; // Program size
uint32_t progcrc; // Program CRC32
uint32_t type; // Device type code
}; // Total: 128 bytes
Permission: READONLY
Usage:
- Device identification
- Firmware version tracking
- Update verification
Device Base Class
class ULSDBase {
const char *devname; // Device name
const char *typeName; // Type name string
uint16_t typeCode; // Numeric type code
ULSList<ULSObjectBase> objects; // List of objects
ULSObjectBase* getObject(uint16_t obj_id);
void setData(uint16_t obj_id, uint8_t *buf);
};
Purpose: Base class for all ULS devices providing:
- Object management
- Device identification
- Configuration storage
Blitz Protocol
The Blitz protocol provides high-frequency sensor data transmission with minimal overhead.
Blitz Packet Structure (IF Layer)
packet-beta title "Blitz Packet (IF Layer)" 0-7: "CMD 0x06 (1 byte)" 8-15: "SRC_LID (1 byte)" 16-31: "MSG_ID (2 bytes)" 32-95: "DATA (8 bytes)"
Fields:
- CMD: 0x06 (IF_CMD_BLITZ)
- SRC_LID: Source device ID
- MSG_ID: Blitz message type identifier
- DATA: Message-specific payload (max 8 bytes)
Blitz Message Types
See separate document: ULS-DeCoNet_Blitz_Messages.md for complete message definitions.
Summary of Message Types:
| Message ID | Name | Description |
|---|---|---|
| 0x0010 | XCG1_RX_RAW_MEASURMENT | Legacy raw measurement (limited angular range) |
| 0x0011 | RX_RAW_MEASURMENT | Raw measurement with full angular range |
| 0x0012 | RX_POS_IN_TX_FRAME | 3D position in transmitter frame |
| 0x0013 | RX_MRX | Multi-receiver information (yaw, distance) |
| 0x0014 | RX_DACS | DACS information with continuous yaw |
| 0x0020 | GIMU_MEASUREMENT | Ground IMU measurement (roll, pitch, yaw) |
| 0x0030 | XX_TXC_IMU_OVERRIDE | IMU override for ground unit |
| 0x0031 | XX_TXC_MAG_OVERRIDE | Magnetometer override for ground unit |
Blitz Data Flow
Sensor → Measurement → Blitz Packet → IF Layer → Framing → Physical Layer
↓
[Status Bits]
[Counter]
[Sensor Data]
Status Bits (common to most Blitz messages):
| Bit | Flag | Description |
|---|---|---|
| 0 | CARRIER_OK | IR signal detected |
| 1 | SQ_OK | Signal quality OK |
| 2 | POS_OK | Position estimated |
| 3 | VEL_OK | Velocity estimated |
| 4 | GU_IMU_OK | Ground Unit IMU OK |
| 5 | MRX_OK | MRX message received |
| 6 | MRXDATA_OK | MRX calculations OK |
Blitz Usage Pattern
Transmitter:
// Construct Blitz message
__uls_blitz_msg_rx_raw_measurmet msg;
msg.status = calculate_status();
msg.counter = counter++;
msg.aX = angle_x_scaled;
msg.aY = angle_y_scaled;
msg.distance = distance_cm;
// Send via IF layer
interface->ifSendBLITZ(
ULS_BLITZ_MSG_ID_RX_RAW_MEASURMENT,
(uint8_t*)&msg,
sizeof(msg)
);
Receiver:
// Set callback
interface->ifclbkBlitzReceived = &onBlitzReceived;
void onBlitzReceived(ULSBusInterface *iface) {
uint16_t msg_id = iface->ifRxPacket->blitz.msg_id;
uint8_t *data = iface->ifRxPacket->blitz.data;
switch(msg_id) {
case ULS_BLITZ_MSG_ID_RX_RAW_MEASURMENT:
process_raw_measurement(data);
break;
// ... handle other message types
}
}
Application Examples
Read Configuration Object
Scenario: Read object 0x0100 from device at DID=5
// Prepare route (direct connection)
uint8_t route[] = {0x05}; // DID=5, CID=0
// Send GET request
connection->cnSendGetObject(
route, // Route array
1, // Route size (hops)
0x0100 // Object address
);
// Response handled in callback
connection->cnclbkObjReceived = &onObjectReceived;
void onObjectReceived(ULSBusConnection *cn) {
uint16_t obj_addr = *((uint16_t*)&cn->cnRxPacket->pld[cn->cnRxPacket->hop & 0xF]);
uint8_t *obj_data = &cn->cnRxPacket->pld[(cn->cnRxPacket->hop & 0xF) + 2];
// Process object data
process_config(obj_addr, obj_data);
}
Firmware Update Procedure
1. Switch to Loader Mode:
cnSendSysSetMode(route, hops, CN_SYS_MODE_LOADER)
→ Device resets into bootloader
2. Erase Flash:
cnSendSysErase(route, hops, key, start_addr, length)
→ Wait for CN_ACK_SYS with OK result
3. Write Firmware (in blocks):
for each 512-byte block:
cnSendSysWrite(route, hops, key, addr, 512, data)
→ Wait for CN_ACK_SYS with OK result
addr += 512
4. Set Signature:
cnSendSysSetSignature(route, hops, key, fw_ver, ldr_ver,
timestamp, size, crc)
→ Device validates and stores metadata
5. Save Configuration:
cnSendSysSaveConfig(route, hops, key)
→ Device commits changes
6. Switch to Application Mode:
cnSendSysSetMode(route, hops, CN_SYS_MODE_APP)
→ Device resets into new firmware
Security Considerations
Authentication
Operation Keys:
- System operations require 32-bit keys
- Key validation prevents unauthorized firmware modification
- Keys can be device-specific (derived from UID)
Recommendations:
- Change default
_ULS_OPERATION_KEYfor production - Implement challenge-response for critical operations
- Consider encryption for sensitive data
Access Control
Object Permissions:
- Enforce read/write restrictions
- Protected objects require authorization
- Validate permissions before object access
Firmware Integrity
CRC Validation:
- Firmware CRC32 stored in signature
- Bootloader verifies before execution
- Prevents corrupted firmware execution
Signature Verification:
- Firmware version and timestamp tracking
- Size validation
- Metadata consistency checks
Network Security
ID Allocation:
- Master controls ID assignment
- Duplicate ID detection
- Timeout-based cleanup
Routing:
- Route validation
- Hop count limits prevent loops
- Source verification
Best Practices
- Use static IDs for critical devices
- Implement authentication for system commands
- Validate all inputs at object level
- Use CRC checking on all transports
- Implement timeouts for all operations
- Log security events for audit trails
- Encrypt sensitive data if required by application
- Protect operation keys in device storage
References
- ULS-DeCoNet Source Code:
ULSOpenLib/ - ULSDC-PBDS021125 - ULS-DeCoNet CAN Transport Specification
- ULSDC-PBDS031125 - ULS-DeCoNet UART Transport Specification
- ULSDC-PBDS041125 - ULS-DeCoNet Quick Reference Guide
- ULSDC-PBDS051125 - ULS-DeCoNet Blitz Messages Specification
Copyright © 2020-2026 UAVLAS <www.uavlas.com>
License: GNU Lesser General Public License v3.0+
Project: ULS Devices Connection Network (ULS-DeCoNet)
2 - ULS-DeCoNet Quick Reference Guide
ULSDC-PBDS041125 · version 1.0.0 · issued November 13, 2025
The numbered PDF is the controlled copy: download it from the portal.
Protocol Stack
Application Layer │ Objects, Blitz Messages, Device Data
Connection Layer │ Routing, Object Access, System Commands
Interface Layer │ Network Management, Device Discovery
Framing Layer │ UART: ESC/COBS | CAN: Multi-frame
Physical Layer │ UART 115200+ | CAN 1Mbps
Addressing
| Component | Size | Range | Description |
|---|---|---|---|
| Device ID (DID) | 6 bits | 0-63 | Local device address |
| Connection ID (CID) | 2 bits | 0-3 | Interface identifier |
| CNRID | 8 bits | 0-255 | Combined routing ID: (CID<<6)|DID |
Special Addresses:
- 0: Master device
- 63: Broadcast / Uninitialized
- 1-62: Regular devices
UART Framing Modes
| Mode | Delimiter | CRC | Overhead | Best For |
|---|---|---|---|---|
| RAW | None | None | 0% | Custom protocols |
| ESC | 0x55 0x01/0x03 | CRC-16 | ~15-25% | General purpose |
| ESC_SIMPLE | 0x55 0x01/0x03 | 8-bit sum | ~12-20% | Low-power |
| COBS | 0x00 | CRC-16 | ~0.4-2% | Binary data |
Frame Examples
ESC Mode:
[0x55][0x01][DATA...][CRC_L][CRC_H][0x55][0x03]
COBS Mode:
[0x00][CODE][DATA...][CRC_L][CRC_H][0x00]
CAN Frame Structure
Single-Frame (≤10 bytes payload)
[CMD][DID][PAYLOAD(6 bytes)]
Multi-Frame (>10 bytes)
Frame N: [CMD][DID][FRMCTL][PAYLOAD(5 bytes)]
Last Frame: FRMCTL = 0x80 | frame_number
Frame Control (FRMCTL):
- Bit 7: End flag (1 = last frame)
- Bits 6-0: Frame number (0-127)
IF Layer Commands
| Code | Name | Description |
|---|---|---|
| 0x00 | SYS | System command |
| 0x01 | NM_HB | Heartbeat (1000ms interval) |
| 0x02 | NM_GET_STATUS | Get device status |
| 0x03 | NM_REQUEST_ID | Request ID allocation |
| 0x04 | NM_SET_ID | Assign device ID |
| 0x05 | NM_RESET_ID | Reset device ID |
| 0x06 | BLITZ | Sensor data message |
Packet Structure:
[CMD][SRC_LID][PAYLOAD]
CN Layer Commands
| Code | Name | Description |
|---|---|---|
| 0x10 | EXPLORER | Network discovery |
| 0x11 | ACK_EXPLORER | Discovery response |
| 0x12 | SYS | System operation |
| 0x13 | ACK_SYS | System response |
| 0x14 | GETOBJ | Read object |
| 0x15 | ACK_GETOBJ | Object data response |
| 0x16 | SETOBJ | Write object |
| 0x17 | ACK_SETOBJ | Write acknowledgment |
Packet Structure:
[CMD][SRC_DID][HOP][ROUTE...][PAYLOAD]
HOP byte:
Bits 7-4: Current hop index
Bits 3-0: Route size
System Sub-Commands
| Code | Name | Description |
|---|---|---|
| 0 | PING | Device ping |
| 1 | SETMODE | Set APP/LOADER mode |
| 2 | ERASE | Erase flash memory |
| 3 | WRITE | Write flash memory |
| 4 | SETSIGNATURE | Set firmware signature |
| 5 | SAVECFG | Save configuration |
Result Codes:
- 0: UNDEFINED
- 1: OK
- 2: ERROR
- 3: WRONGKEY
Blitz Messages
Message Types
| ID | Name | Size | Description |
|---|---|---|---|
| 0x0010 | XCG1_RAW | 8B | Legacy ±30° measurement |
| 0x0011 | RAW_MEASURMENT | 8B | ±180° measurement |
| 0x0012 | POS_TX_FRAME | 8B | 3D position (cm) |
| 0x0013 | MRX | 6B | Multi-receiver data |
| 0x0014 | DACS | 8B | Continuous yaw |
| 0x0020 | GIMU | 8B | Ground IMU data |
| 0x0030 | IMU_OVERRIDE | 8B | Override IMU |
| 0x0031 | MAG_OVERRIDE | 8B | Override magnetometer |
Status Bits
| Bit | Flag | Description |
|---|---|---|
| 0 | CARRIER_OK | IR signal present |
| 1 | SQ_OK | Signal quality OK |
| 2 | POS_OK | Position valid |
| 3 | VEL_OK | Velocity valid |
| 4 | GU_IMU_OK | Ground IMU OK |
| 5 | MRX_OK | MRX received |
| 6 | MRXDATA_OK | MRX data valid |
Data Encoding
Angles (±180°):
int16_t = (degrees / 180.0) * 32767.0
degrees = (int16_t / 32767.0) * 180.0
Position/Distance (cm):
value_cm = int16_t or uint16_t
value_m = value_cm * 0.01
Object Permissions
| Value | Name | Read | Write |
|---|---|---|---|
| 0 | READONLY | ✓ | ✗ |
| 1 | WRITEONLY | ✗ | ✓ |
| 2 | READWRITE | ✓ | ✓ |
| 3 | PROTECTED | ✓ | ✓* |
| 4 | CONFIG | ✓ | ✓* |
| 5 | SYSCONFIG | ✓ | ✓* |
| 6 | ADMIN | ✓ | ✓* |
*Requires authorization
Network States
Device States
UNINITIALIZED (DID=63)
↓ Send REQUEST_ID
↓ Receive SET_ID
OK (DID assigned)
↓ Send HB every 1000ms
↓ Timeout 3000ms
ERROR
Common Operations
Device Discovery
1. Master sends CN_CMD_EXPLORER
2. Devices forward and respond with ACK_EXPLORER
3. Master builds topology map
Read Object
1. Send CN_CMD_GETOBJ with object ID
2. Receive CN_ACK_GETOBJ with data
Write Object
1. Send CN_CMD_SETOBJ with object ID and data
2. Receive CN_ACK_SETOBJ confirmation
Firmware Update
1. SETMODE → LOADER
2. ERASE flash region
3. WRITE firmware blocks (512 bytes each)
4. SETSIGNATURE with metadata
5. SAVECFG
6. SETMODE → APP
Timing Parameters
| Parameter | Value | Description |
|---|---|---|
| HB_INTERVAL | 1000 ms | Heartbeat send interval |
| DEVICE_TIMEOUT | 3000 ms | Device disconnection timeout |
| REQUEST_ID_INTERVAL | 100 ms | ID request interval |
| REQUEST_ID_RETRIES | 5 | Max ID request attempts |
| CAN_DEV_TIMEOUT | 128 frames | CAN multi-frame timeout |
| CAN_POOL_SIZE | 256 slots | CAN frame buffer pool |
Performance Metrics
UART @ 115200 bps
| Mode | Throughput | Latency |
|---|---|---|
| RAW | 11.5 KB/s | ~0 ms |
| ESC | 9.6 KB/s | ~0.17 ms |
| COBS | 11.3 KB/s | ~0.09 ms |
CAN @ 1 Mbps
| Message | Frames | Time | Throughput |
|---|---|---|---|
| 10 bytes | 1 | 108 µs | 92.6 KB/s |
| 256 bytes | 52 | 5.6 ms | 45.6 KB/s |
Error Handling
UART
- CRC errors → discard frame, increment counter
- Framing errors → resync to next delimiter
- Buffer overflow → flush and restart
CAN
- Missing frames → timeout and cleanup
- Pool overflow → emergency cleanup
- Bus-Off → automatic recovery
Code Examples
Initialize Connection (UART)
ULSSerial serial(&rxFifo, &txFifo);
serial.mode(SERIAL_MODE_COBS);
ULSBusInterface interface("UART1", static_did);
interface.open();
Initialize Connection (CAN)
ULSBusConnectionCAN can(&hfdcan1, &device,
&connections, "CAN1",
static_did, cid);
can.setSpeed(1000000);
can.open();
Send Blitz Message
__uls_blitz_msg_rx_raw_measurmet msg;
msg.status = calc_status();
msg.counter = counter++;
msg.aX = (angle_x / 180.0) * 32767;
msg.aY = (angle_y / 180.0) * 32767;
msg.distance = distance_m * 100;
interface->ifSendBLITZ(
ULS_BLITZ_MSG_ID_RX_RAW_MEASURMENT,
(uint8_t*)&msg, sizeof(msg)
);
Receive Blitz Message
interface->ifclbkBlitzReceived = &onBlitz;
void onBlitz(ULSBusInterface *iface) {
uint16_t msg_id = iface->ifRxPacket->blitz.msg_id;
uint8_t *data = iface->ifRxPacket->blitz.data;
switch(msg_id) {
case ULS_BLITZ_MSG_ID_RX_RAW_MEASURMENT:
process_measurement(data);
break;
}
}
Read Object
uint8_t route[] = {0x05}; // DID=5
connection->cnSendGetObject(route, 1, 0x0100);
// In callback
connection->cnclbkObjReceived = &onObjReceived;
System Command
uint8_t route[] = {0x05};
uint32_t key = _ULS_OPERATION_KEY;
connection->cnSendSysSetMode(route, 1,
CN_SYS_MODE_LOADER);
Troubleshooting
| Issue | Check | Solution |
|---|---|---|
| No communication | Baud rate, wiring | Match settings, check connections |
| CRC errors | Noise, cable quality | Add shielding, lower baud rate |
| Device timeout | HB interval | Check network connectivity |
| Pool overflow | Traffic load | Increase pool size, reduce rate |
| Missing frames | Bus load | Reduce message rate |
Key Definitions
// Operation Key
#define _ULS_OPERATION_KEY 0x24041982
// Buffer Sizes
#define IF_PACKET_SIZE 1324
#define CN_CAN_POOL_SIZE 256
#define CN_CAN_DEV_SIZE 64
// Timeouts
#define IF_NM_DVICE_HB_TIMEOUT 3000
#define IF_NM_PING_HB_TIMEOUT 1000
#define IF_NM_REQUESTID_TIMEOUT 100
Document References
- Overview:
ULS-DeCoNet_Protocol_Overview.md - UART:
ULS-DeCoNet_UART_Protocol.md - CAN:
ULS-DeCoNet_CAN_Protocol.md - Blitz:
ULS-DeCoNet_Blitz_Messages.md
Copyright © 2020-2026 UAVLAS
License: LGPL-3.0+
Version: 1.0
Copyright © 2020-2026 UAVLAS <www.uavlas.com>
License: GNU Lesser General Public License v3.0+