ULS-DeCoNet CAN Transport Specification
ULSDC-PBDS021125 · version 1.0.5 · issued November 13, 2025
The numbered PDF is the controlled copy: download it from the portal.
Introduction
Purpose
This document specifies how ULS-DeCoNet protocol messages are transmitted over CAN bus, including frame structure, multi-frame messaging, and error handling specific to the CAN transport.
CAN Bus Advantages
Why CAN for ULS-DeCoNet:
- Multi-master: Any device can initiate communication
- Robust: Built-in error detection and retry
- Priority-based: Critical messages transmitted first
- Collision-free: Hardware arbitration prevents collisions
- Long-distance: Up to 40m @ 1Mbps, longer at lower speeds
- Industrial proven: Widely used in automotive and industrial applications
Scope
This specification covers:
- CAN physical layer configuration
- Application-level frame structure
- Multi-frame message segmentation and reassembly
- Frame pool management
- Priority schemes
- Error recovery mechanisms
Physical Layer
CAN Standards Support
Classical CAN:
- Standard identifiers (11-bit)
- Data payload: 0-8 bytes
- Bit rates: Up to 1 Mbps
- Fully supported
CAN-FD (Flexible Data-rate):
- Standard identifiers (11-bit)
- Extended data payload: Up to 64 bytes
- Arbitration phase: Up to 1 Mbps
- Data phase: Up to 5 Mbps
- Supported via FDCAN peripheral
ULS-DeCoNet Implementation:
- Uses standard 11-bit identifiers
- Classical CAN: 8-byte payload maximum
- CAN-FD: Can utilize extended payload for efficiency
- Current implementation optimized for 8-byte frames
Physical Specifications
Bus Configuration:
Device 1 -----+
|
Device 2 -----+---- CAN_H -------- 120Ω
| CAN_L
Device 3 -----+
|
Device N -----+
|
120Ω
Electrical Specifications:
- Differential voltage: 2V typical
- Termination: 120Ω at both ends
- Max stub length: 30 cm recommended
- Common mode range: -2V to +7V
- Max nodes: Typically 30-64 (driver dependent)
Recommended Bit Rates:
| Distance | Bit Rate | Sample Point |
|---|---|---|
| Up to 40m | 1 Mbps | 75% |
| Up to 100m | 500 kbps | 75% |
| Up to 200m | 250 kbps | 75% |
| Up to 500m | 125 kbps | 75% |
| Up to 1000m | 50 kbps | 75% |
CAN Identifier Structure
Standard 11-bit Identifier:
packet-beta title "CAN 11-bit Identifier" 0-10: "Message ID (11 bits)"
ULS-DeCoNet Usage:
- Identifiers determined by implementation
- Lower identifiers = higher priority
- Can use identifier for addressing or priority
Example Identifier Scheme:
Bits [10:8] - Message priority (0=highest)
Bits [7:0] - Source device address
CAN Frame Structure
Hardware CAN Frame
Standard CAN Frame:
packet-beta title "Standard CAN Frame" 0-0: "SOF" 1-11: "ID (11b)" 12-12: "RTR" 13-13: "IDE" 14-17: "DLC (4b)" 18-81: "DATA (0-8 bytes)" 82-97: "CRC (16b)" 98-99: "ACK (2b)"
| Field | Size | Description |
|---|---|---|
| SOF | 1 bit | Start of Frame |
| ID | 11 bits | Identifier (11-bit) |
| RTR | 1 bit | Remote Transmission Request |
| IDE | 1 bit | Identifier Extension |
| DLC | 4 bits | Data Length Code (0-8) |
| DATA | 0-8 bytes | Payload |
| CRC | 16 bits | Cyclic Redundancy Check |
| ACK | 2 bits | Acknowledgment |
| Notes: |
- Hardware handles SOF, CRC, ACK automatically
- Application specifies ID, DLC, DATA
- RTR and IDE typically 0 for ULS-DeCoNet
ULS-DeCoNet Application Frame
Single-Frame Structure
For messages that fit in one CAN frame (≤10 bytes payload):
packet-beta title "Single-Frame CAN Data Field (8 bytes)" 0-7: "CMD (Byte 0)" 8-15: "DID (Byte 1)" 16-63: "PAYLOAD (Bytes 2-7)"
Fields:
- Byte 0 (CMD): Command code from IF or CN layer
- Byte 1 (DID): Source Device ID
- Bits 5-0: Device ID (0-63)
- Bits 7-6: Connection ID (0-3)
- Bytes 2-7: Command-specific payload (up to 6 bytes)
Characteristics:
- Total overhead: 2 bytes
- Usable payload: 6 bytes per frame
- Transmitted as single atomic CAN frame
Multi-Frame Structure
For messages >10 bytes:
packet-beta title "Multi-Frame CAN Data Field (8 bytes)" 0-7: "CMD (Byte 0)" 8-15: "DID (Byte 1)" 16-23: "FRMCTL (Byte 2)" 24-63: "PAYLOAD 5 bytes (Bytes 3-7)"
packet-beta title "FRMCTL Byte" 0-0: "END" 1-7: "FRAME NUMBER 0-127 (bits 6-0)"
| Field | Description |
|---|---|
| END | Last frame flag: 1 = last frame |
| FRAME NUMBER | Sequence number 0-127 |
| Fields: |
- CMD: Command code (same across all frames)
- DID: Source Device ID (same across all frames)
- FRMCTL: Frame control byte
- Bit 7: End-of-message flag
- Bits 6-0: Frame sequence number (0-127)
- PAYLOAD: Data segment (5 bytes per frame)
Frame Numbering:
Frame 0: FRMCTL = 0x00, payload bytes 0-4
Frame 1: FRMCTL = 0x01, payload bytes 5-9
Frame 2: FRMCTL = 0x02, payload bytes 10-14
...
Frame N: FRMCTL = 0x80 | N, last payload bytes
Single-Frame Messages
Network Management Messages
Heartbeat (HB)
packet-beta title "Heartbeat (CMD=0x01)" 0-7: "CMD 0x01" 8-15: "DID" 16-47: "UID0 (4 bytes)"
Usage: Periodic presence announcement
Payload: Device unique ID (32 bits)
Frequency: Every 1000ms
Request ID
packet-beta title "Request ID (CMD=0x03)" 0-7: "CMD 0x03" 8-15: "DID 0x3F" 16-47: "KEY (4 bytes)"
Usage: Request ID assignment
Payload: Random key for identification
Sent by: Uninitialized devices (DID=63)
Set ID
packet-beta title "Set ID (CMD=0x04)" 0-7: "CMD 0x04" 8-15: "DID 0x00 (Master)" 16-23: "NEWID (1 byte)" 24-55: "KEY (4 bytes)"
Usage: Master assigns ID to device
Sent by: Master device (DID=0)
Payload: New ID + matching key
Blitz Messages
packet-beta title "Blitz Message (CMD=0x06)" 0-7: "CMD 0x06" 8-15: "DID" 16-31: "MSG_ID (2 bytes)" 32-63: "DATA (4 bytes)"
Usage: High-frequency sensor data
Payload:
- MSG_ID (2 bytes): Blitz message type
- DATA (4 bytes): Message-specific data
Note: Blitz messages use DLC=7 or 8 depending on data size
Multi-Frame Protocol
Overview
When Multi-Frame is Used:
- Messages >10 bytes total length
- CN protocol commands (routing, object access)
- System commands with large payloads
- Firmware update data
Key Concept:
- Large message split into multiple CAN frames
- Each frame carries 5 bytes of payload (with 3-byte header)
- Frames can arrive out of order
- Receiver assembles from frame pool
Transmission Algorithm
_io_op_result sendPacket() {
uint8_t framecntr = 0;
uint8_t *pxPld = ifTxPacket->pld;
// Check if single-frame message
if (ifTxPacket->cmd < 16) {
if (ifTxLen > 12) return IO_ERROR;
// Single-frame transmission
_can_mail mail;
mail.packet.raw.data[0] = ifTxPacket->cmd;
mail.packet.raw.data[1] = ifTxPacket->src_lid;
memcpy(&mail.packet.raw.data[2], ifTxPacket->pld, ifTxLen - 2);
mail.len = (ifTxLen < 4) ? 0 : ifTxLen - 4;
send_can_frame(&mail, CAN_PRIORITY_HIGH);
return IO_OK;
}
// Multi-frame transmission
ifTxLen -= 2; // Subtract CMD and DID
while (ifTxLen > 0) {
_can_mail mail;
mail.packet.raw.data[0] = ifTxPacket->cmd;
mail.packet.raw.data[1] = ifTxPacket->src_lid;
mail.packet.raw.data[2] = framecntr++;
// Copy up to 5 bytes payload
uint32_t len = (ifTxLen > 5) ? 5 : ifTxLen;
for (uint32_t i = 0; i < len; i++) {
mail.packet.raw.data[3 + i] = *pxPld++;
ifTxLen--;
}
// Mark last frame
if (ifTxLen == 0) {
mail.packet.raw.data[2] |= 0x80;
}
mail.len = len + 2; // Data length code
if (!send_can_frame(&mail, CAN_PRIORITY_NORMAL)) {
return IO_BUFFER_FULL;
}
}
return IO_OK;
}
Reception Algorithm
_io_op_result receivePacket() {
_can_mail mail;
while (read_can_frame(&mail)) {
uint8_t did = mail.packet.raw.data[1] & 0x3F;
uint8_t cmd = mail.packet.raw.data[0];
// Update device timeout
_devs[did].timeout = CN_CAN_DEV_TIMEOUT;
// Single-frame message
if (cmd < 16) {
ifRxPacket->cmd = cmd;
ifRxPacket->src_lid = did;
memcpy(ifRxPacket->pld, &mail.packet.raw.data[2], mail.len + 2);
ifRxLen = 4 + mail.len;
return IO_OK;
}
// Multi-frame message
uint8_t frame_num = mail.packet.raw.data[2] & 0x7F;
bool is_last = (mail.packet.raw.data[2] & 0x80) != 0;
// Store frame in pool
store_frame_in_pool(did, frame_num, &mail);
if (is_last) {
// Attempt to assemble message
return assemble_message(did, frame_num);
}
}
return IO_NO_DATA;
}
Message Assembly
_io_op_result assemble_message(uint8_t did, uint8_t last_frame) {
ifRxPacket->cmd = get_cmd_from_pool(did);
ifRxPacket->src_lid = did;
uint32_t expected_frames = last_frame + 1;
uint32_t expected_len = last_frame * 5 + get_last_frame_len(did);
ifRxLen = 2; // CMD + DID
// Verify all frames present
for (uint32_t frame = 0; frame <= last_frame; frame++) {
if (!frame_exists_in_pool(did, frame)) {
// Missing frame
log_missing_frames(did, expected_frames);
clean_pool(did);
return IO_ERROR;
}
// Copy frame payload
copy_frame_payload(did, frame, &ifRxPacket->pld[frame * 5]);
ifRxLen += get_frame_payload_len(did, frame);
}
// Verify length
if (ifRxLen != expected_len + 2) {
clean_pool(did);
return IO_ERROR;
}
// Success - clean up pool
clean_pool(did);
return IO_OK;
}
Multi-Frame Example
Scenario: Send 22-byte message from device ID=5
Calculation:
Payload: 22 bytes
Frames needed: ceil(22 / 5) = 5 frames
Frame 0: bytes 0-4 (5 bytes)
Frame 1: bytes 5-9 (5 bytes)
Frame 2: bytes 10-14 (5 bytes)
Frame 3: bytes 15-19 (5 bytes)
Frame 4: bytes 20-21 (2 bytes, last frame)
CAN Frames Transmitted:
Frame 0:
[CMD][0x05][0x00][data[0]][data[1]][data[2]][data[3]][data[4]]
Frame 1:
[CMD][0x05][0x01][data[5]][data[6]][data[7]][data[8]][data[9]]
Frame 2:
[CMD][0x05][0x02][data[10]][data[11]][data[12]][data[13]][data[14]]
Frame 3:
[CMD][0x05][0x03][data[15]][data[16]][data[17]][data[18]][data[19]]
Frame 4:
[CMD][0x05][0x84][data[20]][data[21]][PAD][PAD][PAD]
^^^^
0x80 | 0x04 = Last frame, number 4
Frame Pool Management
Pool Architecture
Purpose: Store received frames until complete message assembled
Pool Structure:
#define CN_CAN_POOL_SIZE 256 // Frame storage slots
#define CN_CAN_DEV_SIZE 64 // Device tracking entries
typedef struct {
uint32_t timeout;
uint32_t start;
uint32_t size;
uint32_t len;
} _cn_can_dev;
_can_mail _pool[CN_CAN_POOL_SIZE];
_cn_can_dev _devs[CN_CAN_DEV_SIZE];
Pool Operations
Frame Storage
bool store_frame_in_pool(uint8_t did, uint8_t frame_num, _can_mail *mail) {
// Find free slot
uint32_t slot = allocate_pool_slot();
if (slot == INVALID_SLOT) {
// Pool full - trigger cleanup
clean_expired_frames();
slot = allocate_pool_slot();
if (slot == INVALID_SLOT) {
return false; // Still full
}
}
// Store frame
memcpy(&_pool[slot], mail, sizeof(_can_mail));
// Mark slot as used
_pool[slot].packet.raw.data[0] = mail->packet.raw.data[0];
return true;
}
Slot Allocation
uint32_t allocate_pool_slot() {
for (uint32_t i = 0; i < CN_CAN_POOL_SIZE; i++) {
_iempty++;
if (_iempty >= CN_CAN_POOL_SIZE) {
_iempty = 0;
}
// Check if slot is empty (marked with 0xFF)
if (_pool[_iempty].packet.raw.data[0] == 0xFF) {
return _iempty;
}
}
return INVALID_SLOT;
}
Timeout Management
Device Timeout:
#define CN_CAN_DEV_TIMEOUT (CN_CAN_POOL_SIZE / 2) // 128 frame times
Timeout Process:
void task(uint32_t dtms) {
// Decrement all device timeouts
for (uint32_t i = 0; i < CN_CAN_DEV_SIZE; i++) {
if (_devs[i].timeout > 0) {
_devs[i].timeout--;
}
}
// On device timeout, clean its frames
for (uint32_t i = 0; i < CN_CAN_DEV_SIZE; i++) {
if (_devs[i].timeout == 0 && _devs[i].size > 0) {
clean_device_frames(i);
}
}
}
Pool Cleanup
Clean Expired Frames
void clean_expired_frames() {
for (uint32_t i = 0; i < CN_CAN_POOL_SIZE; i++) {
if (_pool[i].packet.raw.data[0] == 0xFF) {
continue; // Already free
}
uint8_t did = _pool[i].packet.raw.data[1] & 0x3F;
if (_devs[did].timeout == 0) {
// Device timed out - free frame
_pool[i].packet.raw.data[0] = 0xFF;
}
}
}
Clean Device Frames
uint32_t clean_device_frames(uint8_t did) {
uint32_t count = 0;
for (uint32_t i = 0; i < CN_CAN_POOL_SIZE; i++) {
if (_pool[i].packet.raw.data[0] == 0xFF) {
continue;
}
uint8_t frame_did = _pool[i].packet.raw.data[1] & 0x3F;
if (frame_did == did) {
_pool[i].packet.raw.data[0] = 0xFF;
count++;
}
}
return count;
}
Pool Monitoring
uint32_t get_pool_free_count() {
uint32_t count = 0;
for (uint32_t i = 0; i < CN_CAN_POOL_SIZE; i++) {
if (_pool[i].packet.raw.data[0] == 0xFF) {
count++;
}
}
return count;
}
void check_pool_health() {
uint32_t free = get_pool_free_count();
if (free < CN_CAN_POOL_SIZE / 4) {
// Less than 25% free - warning
log_warning("CAN pool low: %d free", free);
}
if (free == 0) {
// Pool exhausted - critical
log_error("CAN pool exhausted!");
emergency_cleanup();
}
}
Priority and Arbitration
CAN Arbitration
Hardware Arbitration:
- Lower CAN ID wins arbitration
- Non-destructive (losing node automatically retries)
- Deterministic priority
Message Priority Levels:
typedef enum {
_CAN_MAIL_PRIORITY_HI = 0, // Critical messages
_CAN_MAIL_PRIORITY_NORMAL = 1, // Regular data
_CAN_MAIL_PRIORITY_LOW = 2 // Background tasks
} _can_mail_priority;
Priority Assignment
High Priority:
- Network management messages (HB, REQUEST_ID, SET_ID)
- Safety-critical commands
- Single-frame short messages
Normal Priority:
- Multi-frame data transfers
- Object access commands
- System commands
Low Priority:
- Diagnostic data
- Non-critical telemetry
- Bulk data transfers
Identifier Allocation Strategy
Option 1: Source Address Based:
CAN ID = Source Device ID
- Simple
- Natural priority (lower DID = higher priority)
- Master (DID=0) always highest priority
Option 2: Priority + Source:
CAN ID[10:8] = Priority (0=high, 7=low)
CAN ID[7:0] = Source Device ID
Example:
0x000-0x0FF: Highest priority messages
0x100-0x1FF: Normal priority
0x200-0x7FF: Lower priorities
Performance Characteristics
Throughput Analysis
Single-Frame Messages:
CAN @ 1 Mbps:
Frame overhead: ~44 bits
Data: 8 bytes = 64 bits
Total: 108 bits
Time per frame: 108 µs
Max throughput: ~9260 frames/sec
Multi-Frame Messages:
Payload per frame: 5 bytes
Effective data rate: 5/8 = 62.5% efficiency
Net throughput @ 1 Mbps: ~625 kbps for data
Example Transfer Rates:
| Message Size | Frames | Time @ 1Mbps | Throughput |
|---|---|---|---|
| 10 bytes | 1 | 108 µs | 92.6 KB/s |
| 50 bytes | 10 | 1.08 ms | 46.3 KB/s |
| 256 bytes | 52 | 5.62 ms | 45.6 KB/s |
| 1024 bytes | 205 | 22.1 ms | 46.3 KB/s |
Latency Analysis
Best Case (single frame, no contention):
Latency = CAN_frame_time
= 108 µs @ 1 Mbps
Typical Case (multi-frame, some contention):
Latency = (N_frames × CAN_frame_time) + queuing_delay
≈ (N_frames × 108 µs) + (0-500 µs)
Worst Case (high bus load):
Latency = (N_frames × CAN_frame_time) + max_retry_delay
Can be significantly higher during bus saturation
Bus Utilization
Recommended Maximum Load: 70-80%
Critical Threshold: 90%
Load Calculation:
Load = (Messages_per_second × Bits_per_message) / Bus_bitrate
Example:
100 msgs/sec × 108 bits/msg = 10,800 bps
Load @ 1 Mbps = 1.08%
Error Handling
CAN Hardware Errors
CAN Controller Error States:
stateDiagram-v2 [*] --> ErrorActive ErrorActive: Error Active\n(Normal operation) ErrorPassive: Error Passive\n(Reduced priority) BusOff: Bus Off\n(Disconnected) ErrorActive --> ErrorPassive: TEC/REC > 127 ErrorPassive --> BusOff: TEC > 255 BusOff --> ErrorActive: Recovery (128 × 11 recessive bits)
| Counter | Meaning |
|---|---|
| TEC | Transmit Error Counter |
| REC | Receive Error Counter |
| Hardware Error Handling: |
- Automatic retransmission
- Error frames generation
- Automatic recovery from Bus Off (implementation-dependent)
Application-Level Errors
Missing Frames
Detection:
// Check for missing frames in sequence
for (uint32_t i = 0; i <= last_frame; i++) {
if (!frame_exists(did, i)) {
log_error("Missing frame %d from device %d", i, did);
_missedFrames[i] = 1;
}
}
Recovery:
- Discard incomplete message
- Clean pool entries
- Higher layer handles timeout/retransmission
Pool Overflow
Detection:
if (allocate_pool_slot() == INVALID_SLOT) {
log_error("CAN pool exhausted!");
return IO_BUFFER_FULL;
}
Recovery:
1. Trigger emergency cleanup
2. Remove oldest/timed-out frames
3. If still full, reject new frames
4. Report error to higher layer
Timeout Errors
Device Timeout:
void handle_device_timeout(uint8_t did) {
log_warning("Device %d timeout", did);
// Clean all frames from device
uint32_t cleaned = clean_device_frames(did);
log_info("Cleaned %d frames from device %d", cleaned, did);
// Notify higher layer
notify_device_disconnected(did);
}
Error Statistics
typedef struct {
uint32_t tx_ok;
uint32_t tx_errors;
uint32_t rx_ok;
uint32_t rx_errors;
uint32_t missing_frames;
uint32_t pool_overflows;
uint32_t device_timeouts;
} can_stats_t;
Implementation Details
ULSBusConnectionCAN Class
class ULSBusConnectionCAN : public ULSBusConnection, DrvCAN {
public:
ULSBusConnectionCAN(_drvcan_handle_td* handler,
ULSDBase* dev,
ULSBusConnectionsList* connections,
const char* name,
uint8_t id,
uint8_t cid);
// Configuration
bool open() override;
void setSpeed(uint32_t speed);
// Task processing
void task(uint32_t dtms) override;
// Frame I/O
_io_op_result sendPacket() override;
_io_op_result receivePacket() override;
// Statistics
uint32_t poolSize();
private:
_can_mail _pool[CN_CAN_POOL_SIZE];
_cn_can_dev _devs[CN_CAN_DEV_SIZE];
uint32_t _iempty;
uint32_t _missedFrames[128];
bool allocate();
void clean();
uint32_t clean(uint8_t id);
void setTimeouts();
};
CAN Mail Structure
typedef struct {
union {
struct {
uint32_t id; // CAN identifier
uint8_t data[8]; // Payload
uint8_t len; // DLC (0-8)
} raw;
// Alternative access methods
} packet;
} _can_mail;
Driver Integration
class DrvCAN {
protected:
_drvcan_handle_td* _handler;
public:
bool open();
void setSpeed(uint32_t speed);
bool send(_can_mail* mail, _can_mail_priority priority);
bool read(_can_mail* mail);
void txTask(); // Process TX queue
};
Configuration Example
// Initialize CAN peripheral
FDCAN_HandleTypeDef hfdcan1;
hfdcan1.Instance = FDCAN1;
hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
hfdcan1.Init.AutoRetransmission = ENABLE;
hfdcan1.Init.TransmitPause = DISABLE;
hfdcan1.Init.ProtocolException = ENABLE;
// Bit timing (1 Mbps @ 80 MHz APB clock)
hfdcan1.Init.NominalPrescaler = 4;
hfdcan1.Init.NominalSyncJumpWidth = 1;
hfdcan1.Init.NominalTimeSeg1 = 15;
hfdcan1.Init.NominalTimeSeg2 = 4;
// Create ULS connection
ULSBusConnectionCAN canConnection(
&hfdcan1, // CAN handle
&device, // Device object
&connections, // Connection list
"CAN1", // Name
static_did, // Device ID
0 // Connection ID
);
// Configure and open
canConnection.setSpeed(1000000); // 1 Mbps
canConnection.open();
Usage Pattern
// Main loop
void main_loop() {
while (1) {
// Process CAN I/O
canConnection.task(dt_ms);
// Send data
if (data_ready) {
canConnection.ifSendBLITZ(msg_id, data, size);
}
// Check pool health
if (canConnection.poolSize() < 64) {
log_warning("CAN pool low");
}
delay(1); // 1ms tick
}
}
Best Practices
Design Guidelines
- Keep Messages Small: Use single-frame when possible
- Set Appropriate Timeouts: Balance responsiveness vs. robustness
- Monitor Pool Usage: Implement pool health checks
- Use Priority Wisely: Don’t overuse high priority
- Handle Bus-Off: Implement recovery mechanism
- Test Under Load: Verify behavior at high utilization
Performance Optimization
For High Throughput:
- Use CAN-FD if available
- Batch small messages
- Optimize frame packing
- Use DMA for CAN peripheral
For Low Latency:
- Minimize multi-frame messages
- Use high priority for time-critical data
- Reduce bus load
- Implement fast-path processing
For Reliability:
- Implement message acknowledgment at application level
- Use sequence numbers
- Add timeout and retry logic
- Monitor error statistics
Troubleshooting
| Symptom | Possible Cause | Solution |
|---|---|---|
| No communication | Wrong bit rate | Verify bit rate settings match |
| Intermittent errors | No termination | Check 120Ω resistors at bus ends |
| Bus-Off state | Wiring issue | Check CAN_H/CAN_L connections |
| Missing frames | Pool overflow | Increase pool size or cleanup rate |
| High latency | Bus saturation | Reduce message rate or increase bitrate |
| Device timeouts | Lost frames | Check for collisions or interference |
Appendices
Appendix A: Frame Examples
Heartbeat Frame:
CAN ID: 0x001
Data: [0x01][0x05][0x12][0x34][0x56][0x78][00][00]
CMD DID UID0 (little-endian)
Multi-Frame Example (15-byte message):
Frame 0: [0x14][0x05][0x00][d0][d1][d2][d3][d4]
Frame 1: [0x14][0x05][0x01][d5][d6][d7][d8][d9]
Frame 2: [0x14][0x05][0x82][d10][d11][d12][d13][d14]
^^^^
Last frame (0x80 | 0x02)
Appendix B: Performance Calculations
See section 8 for detailed performance analysis.
Copyright © 2020-2026 UAVLAS <www.uavlas.com>
License: GNU Lesser General Public License v3.0+
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve this page !
Sorry to hear that. Please tell us how we can improve it !