🏠 Home → Software → RTLV → Frame Structure
🤖 Auto-generated from firmware (SSOT). Do not hand-edit — change the descriptor and regenerate. RTLV v3 ·
source_hash eb6b51128c1b
| Byte | 0 | 1 | 2 | 3 | 4 … 3+len | … |
|---|---|---|---|---|---|---|
| Field | prefix |
seq |
tag |
len |
value |
tag… |
An uplink frame = [prefix][seq] + one or more TLVs [tag][len][value]. The prefix hi-nibble is the event category, the lo-nibble the interface.
| Frame kind | First bytes | TLV offset | Notes |
|---|---|---|---|
| data/alarm/button | [prefix][seq] |
2 | the event family |
STARTUP 0xBE |
[0xBE][protoVer] |
2 | byte[1]=protoVer, not seq |
0xF0 response |
[F0][LEN][hdr×5] |
7 | structured envelope |
0xF5 fragment |
[F5][03][idx][total][id] |
5 | frame-level lead header |
| nRF/BLE transport | [prefix][seq] |
0 | no LoRaWAN FPort byte offset |
| Hi nibble | Category | Members |
|---|---|---|
A_ |
Alarm | 0xA0=ALARM_SYSTEM, 0xA1=ALARM_MODBUS_1, 0xA2=ALARM_MODBUS_2, 0xA3=ALARM_MODBUS_3, 0xA4=ALARM_MODBUS_4, 0xA5=ALARM_MODBUS_5, 0xA6=ALARM_MODBUS_6, 0xA7=ALARM_MODBUS_7, 0xA8=ALARM_MODBUS_8, 0xA9=ALARM_ONEWIRE, 0xAA=ALARM_ANALOG, 0xAB=ALARM_BUS, 0xAD=ALARM_DISCRETE |
B_ |
Button | 0xB0=BUTTON_SYSTEM, 0xB1=BUTTON_MODBUS_1, 0xB2=BUTTON_MODBUS_2, 0xB3=BUTTON_MODBUS_3, 0xB4=BUTTON_MODBUS_4, 0xB5=BUTTON_MODBUS_5, 0xB6=BUTTON_MODBUS_6, 0xB7=BUTTON_MODBUS_7, 0xB8=BUTTON_MODBUS_8, 0xB9=BUTTON_ONEWIRE, 0xBA=BUTTON_ANALOG, 0xBB=BUTTON_BUS, 0xBD=BUTTON_DISCRETE, 0xBE=STARTUP |
C_ |
Control/Ext | 0xCA=PAGING, 0xCD=CONTROL_OUTPUT, 0xCE=BLE_STATE, 0xCF=CONFIG_UART |
D_ |
Data | 0xD0=DATA_SYSTEM, 0xD1=DATA_MODBUS_1, 0xD2=DATA_MODBUS_2, 0xD3=DATA_MODBUS_3, 0xD4=DATA_MODBUS_4, 0xD5=DATA_MODBUS_5, 0xD6=DATA_MODBUS_6, 0xD7=DATA_MODBUS_7, 0xD8=DATA_MODBUS_8, 0xD9=DATA_ONEWIRE, 0xDA=DATA_ANALOG, 0xDB=DATA_BUS, 0xDD=DATA_DISCRETE, 0xDE=DAILY_ROLLOVER |
E_ |
Ext/Event | 0xE0=ESP32_RESPONSE, 0xEA=SYSTEM_EVENT, 0xED=DUTY_CYCLE_WARN |
F_ |
Framework | 0xF0=RESPONSE, 0xF1=JOIN_SUCCESS, 0xF2=TIME_SYNC_SUCCESS, 0xF3=TIME_SYNC_TIMEOUT, 0xF5=FRAGMENT |
The lo-nibble is the interface/slot (e.g. 0xD1..0xD8 = Modbus slot 1..8). 0xBE STARTUP and 0xDE DAILY_ROLLOVER are special members.
Big-endian by default. A decoder MUST read each tag's endian field, never memorize. There are exactly two documented LE exceptions:
| Tag | Name | Layout | Why LE |
|---|---|---|---|
0x07 |
device_time | [unix u32 LE][tz_min i16 LE] |
matches the on-device SysTime_t/RTC byte order (tlv_protocol.h:100) |
0xCB |
daily_gpio_events | 6× uint32 LE | FRAM daily counters stored LE (FPort 100) |
⚠️ A third LE entry in the descriptor — FPort-6
0xCB slot10_loop_current— is a bug (must be BE); see the HART tags page.
0xF0 response envelopeResponse — 0xF0 COMMAND_RESPONSE 7-byte envelope, then echo-TLVs @ offset 7 (decoded in the response FPort's namespace):
| Offset | Byte | Field | Meaning |
|---|---|---|---|
| 0 | F0 |
prefix | COMMAND_RESPONSE |
| 1 | LEN |
length | bytes after [F0][LEN]; 0x05 for the bare 7-byte header |
| 2 | — | cmd_id | echoed command id |
| 3 | — | status | 0=OK |
| 4 | — | error_code | command error |
| 5 | — | flags | response flags |
| 6 | — | protocol_version | =0x03 (TLV_PROTOCOL_VERSION) |
| 7… | — | echo-TLVs | port-scoped [tag][len][value] |
The
[0xF0][3]…forms in firmware docstrings are stale shorthand — never mirror them.
0xF5 fragmentation| Offset | Byte | Meaning |
|---|---|---|
| 0 | F5 |
FRAGMENT prefix (frame-level) |
| 1 | 03 |
header length (3 bytes follow) |
| 2 | idx |
fragment index — 1-based on the wire (lorawan_commands.c:594) |
| 3 | total |
total fragments |
| 4 | id |
message/seq id (same across the message) |
Reassembly: group by id, order by idx, strip each 5-byte 0xF5 header, concatenate in index order, parse as one ordinary frame. The first fragment carries the wrapped frame's own header. A single packet has no 0xF5 header. The tlv_protocol.h “0-based” comment is stale; tlv_add_fragment_info() is dead code.
| FPort | Name | Framing | Direction behavior |
|---|---|---|---|
| 220 | PAGING_USER | raw | raw passthrough both directions; no charset transform (app-layer CP1251 convention) |
Full byte-by-byte decodes are on the Parsing Walkthroughs page.