# ULS-DeCoNet Protocol Interface Control Document

> Electrical, mechanical and communication interfaces of ULS-DeCoNet — the ULS Devices Connection Network protocol for UART and CAN.

---

Site [llms.txt](/llms.txt)

---

> **ULSDC-PBICD011125** · version 1.0.5 · issued November 13, 2025  
> The numbered PDF is the controlled copy: [download it from the portal](https://downloads.uavlas.com).

## 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

```mermaid
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

1. **Layered Architecture**: Clear separation of concerns between protocol layers
2. **Transport Agnostic**: Core protocol independent of physical medium
3. **Efficient Framing**: Multiple framing modes optimized for different scenarios
4. **Scalable Addressing**: Support for hierarchical and flat addressing schemes
5. **Robust Error Handling**: CRC protection and timeout-based error recovery
6. **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:**
```mermaid
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`, insert `0x02` after it
- Delimiter `0x55` is 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:**
```mermaid
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:**
```mermaid
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:**

1. Packet is divided into blocks separated by zero bytes
2. Each block is preceded by a code byte:
   - Code byte = number of non-zero bytes following + 1
   - Maximum block size = 254 bytes
   - Code byte `0xFF` means 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:**
```mermaid
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:**
```mermaid
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:**

1. **Frame Sequence**: Frames numbered 0, 1, 2, ... N
2. **Last Frame Marker**: Frame N has bit 7 set (value = N | 0x80)
3. **Payload per Frame**: 9 bytes (DLC = 11, minus 3 header bytes)
4. **Frame Pool**: Receiver maintains a pool of 256 frame buffers
5. **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

```c
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

```mermaid
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**:
```mermaid
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**:
```mermaid
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**:
```c
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**:
```mermaid
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**:
```mermaid
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

```mermaid
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)

```mermaid
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)

```mermaid
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 commands
  - `0x10-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

```mermaid
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:

1. Master sends `CN_CMD_EXPLORER` with empty route
2. Each device:
   - Adds its CNRID to route
   - Forwards to all connections
   - Responds with `CN_ACK_EXPLORER` containing reverse route
3. 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**:
```mermaid
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**:
```mermaid
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**:
```mermaid
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)**:
```mermaid
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**:
1. Request routed to target device
2. Device looks up object by OBJ_ADDR
3. Check read permission
4. If OK: respond with object data
5. If error: no response or error code

##### CN_CMD_SETOBJ (0x16) - Write Object

**Purpose**: Write data to device object

**Request Structure**:
```mermaid
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)**:
```mermaid
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**:
1. Request routed to target device
2. Device looks up object by OBJ_ADDR
3. Check write permission
4. If OK: write data, respond with ACK
5. If error: no response or error code

#### System Commands

##### CN_CMD_SYS (0x12) - System Operations

**Purpose**: Device configuration and firmware update

**Structure**:
```mermaid
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**:
```mermaid
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**:
```mermaid
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**:
```mermaid
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**:
```mermaid
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**:
```mermaid
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**:
```mermaid
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**:
```c
#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**:
```cpp
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**:
```cpp
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

```cpp
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)

```mermaid
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**:
```cpp
// 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**:
```cpp
// 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

```cpp
// 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_KEY` for 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

1. **Use static IDs** for critical devices
2. **Implement authentication** for system commands
3. **Validate all inputs** at object level
4. **Use CRC checking** on all transports
5. **Implement timeouts** for all operations
6. **Log security events** for audit trails
7. **Encrypt sensitive data** if required by application
8. **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)

---
