|
|
@@ -303,7 +303,7 @@ Bytes 7+: Binary payload bytes (variable length)
|
|
|
- Values other than `0xFF` are reserved for official protocol extensions.
|
|
|
|
|
|
**Limits**:
|
|
|
-- Maximum payload length is `163` bytes (`MAX_GROUP_DATA_LENGTH`).
|
|
|
+- Maximum payload length is `160` bytes.
|
|
|
- Larger payloads are rejected with `PACKET_ERROR` / `ERR_CODE_ILLEGAL_ARG`.
|
|
|
|
|
|
**Response**: `PACKET_OK` (0x00) on success
|
|
|
@@ -326,7 +326,7 @@ Byte 0: 0x0A
|
|
|
|
|
|
**Response**:
|
|
|
- `PACKET_CHANNEL_MSG_RECV` (0x08) or `PACKET_CHANNEL_MSG_RECV_V3` (0x11) for channel messages
|
|
|
-- `PACKET_CHANNEL_DATA_RECV` (0x1B) or `PACKET_CHANNEL_DATA_RECV_V3` (0x1C) for channel data
|
|
|
+- `PACKET_CHANNEL_DATA_RECV` (0x1B) for channel data
|
|
|
- `PACKET_CONTACT_MSG_RECV` (0x07) or `PACKET_CONTACT_MSG_RECV_V3` (0x10) for contact messages
|
|
|
- `PACKET_NO_MORE_MSGS` (0x0A) if no messages available
|
|
|
|
|
|
@@ -397,8 +397,7 @@ Messages are received via the TX characteristic (notifications). The device send
|
|
|
- `PACKET_CHANNEL_MSG_RECV_V3` (0x11) - Version 3 with SNR
|
|
|
|
|
|
2. **Channel Data**:
|
|
|
- - `PACKET_CHANNEL_DATA_RECV` (0x1B) - Standard format
|
|
|
- - `PACKET_CHANNEL_DATA_RECV_V3` (0x1C) - Version 3 with SNR
|
|
|
+ - `PACKET_CHANNEL_DATA_RECV` (0x1B) - Includes SNR and reserved bytes
|
|
|
|
|
|
3. **Contact Messages**:
|
|
|
- `PACKET_CONTACT_MSG_RECV` (0x07) - Standard format
|
|
|
@@ -502,26 +501,17 @@ Bytes 11+: Payload bytes
|
|
|
|
|
|
### Channel Data Format
|
|
|
|
|
|
-**Standard Format** (`PACKET_CHANNEL_DATA_RECV`, 0x1B):
|
|
|
+**Format** (`PACKET_CHANNEL_DATA_RECV`, 0x1B):
|
|
|
```
|
|
|
Byte 0: 0x1B (packet type)
|
|
|
-Byte 1: Channel Index (0-7)
|
|
|
-Byte 2: Path Length
|
|
|
-Byte 3: Data Type
|
|
|
-Bytes 4-7: Timestamp (32-bit little-endian)
|
|
|
-Bytes 8+: Payload bytes
|
|
|
-```
|
|
|
-
|
|
|
-**V3 Format** (`PACKET_CHANNEL_DATA_RECV_V3`, 0x1C):
|
|
|
-```
|
|
|
-Byte 0: 0x1C (packet type)
|
|
|
Byte 1: SNR (signed byte, multiplied by 4)
|
|
|
Bytes 2-3: Reserved
|
|
|
Byte 4: Channel Index (0-7)
|
|
|
Byte 5: Path Length
|
|
|
Byte 6: Data Type
|
|
|
-Bytes 7-10: Timestamp (32-bit little-endian)
|
|
|
-Bytes 11+: Payload bytes
|
|
|
+Byte 7: Data Length
|
|
|
+Bytes 8-11: Timestamp (32-bit little-endian)
|
|
|
+Bytes 12+: Payload bytes
|
|
|
```
|
|
|
|
|
|
**Parsing Pseudocode**:
|
|
|
@@ -529,9 +519,10 @@ Bytes 11+: Payload bytes
|
|
|
def parse_channel_frame(data):
|
|
|
packet_type = data[0]
|
|
|
offset = 1
|
|
|
+ snr = None
|
|
|
|
|
|
- # Check for V3 format
|
|
|
- if packet_type in (0x11, 0x1C): # V3
|
|
|
+ # Formats with explicit SNR/reserved bytes
|
|
|
+ if packet_type in (0x11, 0x1B):
|
|
|
snr_byte = data[offset]
|
|
|
snr = ((snr_byte if snr_byte < 128 else snr_byte - 256) / 4.0)
|
|
|
offset += 3 # Skip SNR + reserved
|
|
|
@@ -539,8 +530,10 @@ def parse_channel_frame(data):
|
|
|
channel_idx = data[offset]
|
|
|
path_len = data[offset + 1]
|
|
|
item_type = data[offset + 2]
|
|
|
- timestamp = int.from_bytes(data[offset+3:offset+7], 'little')
|
|
|
- payload = data[offset+7:]
|
|
|
+ data_len = data[offset + 3] if packet_type == 0x1B else None
|
|
|
+ timestamp = int.from_bytes(data[offset+4:offset+8], 'little') if packet_type == 0x1B else int.from_bytes(data[offset+3:offset+7], 'little')
|
|
|
+ payload_offset = offset + 8 if packet_type == 0x1B else offset + 7
|
|
|
+ payload = data[payload_offset:payload_offset + data_len] if packet_type == 0x1B else data[payload_offset:]
|
|
|
is_text = packet_type in (0x08, 0x11)
|
|
|
if is_text and item_type == 0:
|
|
|
message = payload.decode('utf-8')
|
|
|
@@ -553,7 +546,7 @@ def parse_channel_frame(data):
|
|
|
'timestamp': timestamp,
|
|
|
'payload': payload,
|
|
|
'message': message,
|
|
|
- 'snr': snr if packet_type in (0x11, 0x1C) else None
|
|
|
+ 'snr': snr
|
|
|
}
|
|
|
```
|
|
|
|
|
|
@@ -590,8 +583,7 @@ Use `CMD_SEND_CHANNEL_TXT_MSG` for plain text, and `CMD_SEND_CHANNEL_DATA` for b
|
|
|
| 0x10 | PACKET_CONTACT_MSG_RECV_V3 | Contact message (V3 with SNR) |
|
|
|
| 0x11 | PACKET_CHANNEL_MSG_RECV_V3 | Channel message (V3 with SNR) |
|
|
|
| 0x12 | PACKET_CHANNEL_INFO | Channel information |
|
|
|
-| 0x1B | PACKET_CHANNEL_DATA_RECV | Channel data (standard) |
|
|
|
-| 0x1C | PACKET_CHANNEL_DATA_RECV_V3| Channel data (V3 with SNR) |
|
|
|
+| 0x1B | PACKET_CHANNEL_DATA_RECV | Channel data (includes SNR) |
|
|
|
| 0x80 | PACKET_ADVERTISEMENT | Advertisement packet |
|
|
|
| 0x82 | PACKET_ACK | Acknowledgment |
|
|
|
| 0x83 | PACKET_MESSAGES_WAITING | Messages waiting notification |
|
|
|
@@ -892,7 +884,7 @@ def on_notification_received(data):
|
|
|
packet_type = data[0]
|
|
|
|
|
|
if packet_type in (PACKET_CHANNEL_MSG_RECV, PACKET_CHANNEL_MSG_RECV_V3,
|
|
|
- PACKET_CHANNEL_DATA_RECV, PACKET_CHANNEL_DATA_RECV_V3):
|
|
|
+ PACKET_CHANNEL_DATA_RECV):
|
|
|
message = parse_channel_frame(data)
|
|
|
handle_channel_message(message)
|
|
|
elif packet_type == PACKET_MESSAGES_WAITING:
|