meshcore-open/documentation/ble-protocol.md
zjs81 cb63b48b78 Add comprehensive documentation for various app features
- Introduced "Contacts" documentation detailing the contact management system, types, list, search, and tap actions.
- Added "Map & Location" documentation covering map features, interactions, path tracing, and line-of-sight analysis.
- Created "Navigation" documentation outlining app flow, QuickSwitchBar, and device screen interactions.
- Developed "Notifications" documentation explaining notification types, in-app badges, settings, and rate limiting.
- Established "Repeater Management" documentation for managing repeaters and room servers, including CLI access and telemetry.
- Compiled "Scanner & Connection" documentation detailing BLE, USB, and TCP connection processes.
- Formulated "Settings" documentation outlining access, layout, device info, app settings, node settings, actions, debug options, export features, and about section.
2026-03-20 02:24:02 -07:00

249 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# BLE Protocol & Data Layer
This is a technical reference for the communication protocol and data architecture.
## Transport Layer
The app supports three transports, all sharing the same command/response protocol:
| Transport | Method | Implementation |
|---|---|---|
| Bluetooth LE | Nordic UART Service (NUS) GATT | `flutter_blue_plus` |
| USB Serial | Packet-framed serial | `MeshCoreUsbManager` |
| TCP | Packet-framed socket | `MeshCoreTcpConnector` |
### BLE (Nordic UART Service)
- **Service UUID**: `6e400001-b5a3-f393-e0a9-e50e24dcca9e`
- **RX Characteristic** (write to device): `6e400002-b5a3-f393-e0a9-e50e24dcca9e`
- **TX Characteristic** (notify from device): `6e400003-b5a3-f393-e0a9-e50e24dcca9e`
Raw `Uint8List` payloads are written directly to the RX characteristic. Writes use "write without response" if supported, falling back to "write with response".
### USB and TCP Framing
Both use a lightweight packet framing codec:
```
TX (host → device): [0x3C][len_lo][len_hi][payload...]
RX (device → host): [0x3E][len_lo][len_hi][payload...]
```
- Frame start: `0x3C` (`<`) for outgoing, `0x3E` (`>`) for incoming
- Length: 2-byte little-endian, payload only
- Max payload: 172 bytes
- TCP: `tcpNoDelay: true` (Nagle disabled), writes serialized to prevent interleaving
- USB: 10ms post-write delay between frames
## Connection State Machine
```
enum MeshCoreConnectionState {
disconnected,
scanning,
connecting,
connected,
disconnecting,
}
```
## BLE Connection Lifecycle
1. **Scan** with keyword filters `["MeshCore-", "Whisper-"]`
2. **Connect** with 15-second timeout
3. **Request MTU** 185 bytes (non-web only)
4. **Discover services** and locate NUS
5. **Enable TX notifications** (up to 3 attempts on native)
6. **Subscribe** to TX characteristic for incoming frames
7. **Initial sync**: device info query, time sync, channel sync
## Auto-Reconnect (BLE Only)
On unexpected disconnection, auto-reconnect with exponential backoff:
- Delays: 1s, 2s, 4s, 8s, 16s, 30s, 30s...
- Resets on successful connection
- Disabled for manual disconnects
- Not available for USB or TCP
## Protocol Constants
| Constant | Value | Description |
|---|---|---|
| Max frame size | 172 bytes | BLE/USB/TCP payload limit |
| Public key size | 32 bytes | Ed25519 public key |
| Max path size | 64 bytes | Maximum path data |
| Max name size | 32 bytes | Maximum node name |
| Max text payload | 160 bytes | Firmware `MAX_TEXT_LEN` |
| App protocol version | 3 | Sent in device query |
| Contact frame size | 148 bytes | Fixed-size contact record |
## Command Codes (App → Device)
| Code | Name | Description |
|------|------|-------------|
| 1 | CMD_APP_START | Announce app connection |
| 2 | CMD_SEND_TXT_MSG | Send direct text message |
| 3 | CMD_SEND_CHANNEL_TXT_MSG | Send channel text message |
| 4 | CMD_GET_CONTACTS | Request contact list |
| 5 | CMD_GET_DEVICE_TIME | Query device clock |
| 6 | CMD_SET_DEVICE_TIME | Set device clock |
| 7 | CMD_SEND_SELF_ADVERT | Broadcast own advertisement |
| 8 | CMD_SET_ADVERT_NAME | Set node name |
| 9 | CMD_ADD_UPDATE_CONTACT | Add or update a contact |
| 10 | CMD_SYNC_NEXT_MESSAGE | Request next queued message |
| 11 | CMD_SET_RADIO_PARAMS | Set radio parameters |
| 12 | CMD_SET_RADIO_TX_POWER | Set TX power |
| 13 | CMD_RESET_PATH | Reset contact path |
| 14 | CMD_SET_ADVERT_LATLON | Set advertised location |
| 15 | CMD_REMOVE_CONTACT | Remove a contact |
| 16 | CMD_SHARE_CONTACT | Share contact to mesh |
| 17 | CMD_EXPORT_CONTACT | Export contact as bytes |
| 18 | CMD_IMPORT_CONTACT | Import contact from bytes |
| 19 | CMD_REBOOT | Reboot device |
| 20 | CMD_GET_BATT_AND_STORAGE | Query battery and storage |
| 22 | CMD_DEVICE_QUERY | Query device info |
| 26 | CMD_SEND_LOGIN | Login to repeater/room |
| 27 | CMD_SEND_STATUS_REQ | Request repeater status |
| 30 | CMD_GET_CONTACT_BY_KEY | Get contact by public key |
| 31 | CMD_GET_CHANNEL | Get channel definition |
| 32 | CMD_SET_CHANNEL | Set channel name and PSK |
| 36 | CMD_SEND_TRACE_PATH | Request path trace |
| 38 | CMD_SET_OTHER_PARAMS | Set misc parameters |
| 39 | CMD_GET_TELEMETRY_REQ | Request sensor telemetry |
| 40 | CMD_GET_CUSTOM_VAR | Get custom variables |
| 41 | CMD_SET_CUSTOM_VAR | Set a custom variable |
| 50 | CMD_SEND_BINARY_REQ | Send binary request |
| 57 | CMD_SEND_ANON_REQ | Send anonymous request |
| 58 | CMD_SET_AUTO_ADD_CONFIG | Set auto-add configuration |
| 59 | CMD_GET_AUTO_ADD_CONFIG | Get auto-add configuration |
## Response / Push Codes (Device → App)
| Code | Name | Description |
|------|------|-------------|
| 0 | RESP_CODE_OK | Generic success |
| 1 | RESP_CODE_ERR | Generic error |
| 2 | RESP_CODE_CONTACTS_START | Contact list begins |
| 3 | RESP_CODE_CONTACT | Single contact data |
| 4 | RESP_CODE_END_OF_CONTACTS | Contact list complete |
| 5 | RESP_CODE_SELF_INFO | Device self-info response |
| 6 | RESP_CODE_SENT | Message transmitted; carries `[1]=is_flood, [25]=ack_hash, [69]=estimated_timeout_ms` |
| 7 | RESP_CODE_CONTACT_MSG_RECV | Incoming direct message (v2) |
| 8 | RESP_CODE_CHANNEL_MSG_RECV | Incoming channel message (v2) |
| 10 | RESP_CODE_NO_MORE_MESSAGES | No more queued messages |
| 11 | RESP_CODE_EXPORT_CONTACT | Exported contact data |
| 9 | RESP_CODE_CURR_TIME | Current device time |
| 12 | RESP_CODE_BATT_AND_STORAGE | Battery mV (uint16 LE) + storage used/total (uint32 LE each) |
| 13 | RESP_CODE_DEVICE_INFO | Firmware info |
| 16 | RESP_CODE_CONTACT_MSG_RECV_V3 | Incoming direct message (v3) |
| 17 | RESP_CODE_CHANNEL_MSG_RECV_V3 | Incoming channel message (v3) |
| 18 | RESP_CODE_CHANNEL_INFO | Channel definition |
| 21 | RESP_CODE_CUSTOM_VARS | Custom variables |
| 25 | RESP_CODE_AUTO_ADD_CONFIG | Auto-add flags |
| 0x80 | PUSH_CODE_ADVERT | Known contact re-seen |
| 0x81 | PUSH_CODE_PATH_UPDATED | Better path found; carries the 32-byte public key of the updated contact |
| 0x82 | PUSH_CODE_SEND_CONFIRMED | Delivery ACK from remote; carries ACK hash (4 bytes) + trip time (4 bytes) |
| 0x83 | PUSH_CODE_MSG_WAITING | Offline messages queued |
| 0x85 | PUSH_CODE_LOGIN_SUCCESS | Repeater/room login succeeded |
| 0x86 | PUSH_CODE_LOGIN_FAIL | Repeater/room login failed |
| 0x87 | PUSH_CODE_STATUS_RESPONSE | Repeater status response |
| 0x88 | PUSH_CODE_LOG_RX_DATA | Radio RX data with SNR (int8, units 1/4 dB), RSSI, and raw radio packet |
| 0x89 | PUSH_CODE_TRACE_DATA | Path trace result |
| 0x8A | PUSH_CODE_NEW_ADVERT | New node discovered |
| 0x8B | PUSH_CODE_TELEMETRY_RESPONSE | Sensor telemetry data |
| 0x8C | PUSH_CODE_BINARY_RESPONSE | Binary data response |
## Data Models
### Contact
32-byte public key (primary identity), name, type (chat/repeater/room/sensor), flags, path data, GPS coordinates, last-seen timestamp. Parsed from 148-byte firmware frames with this layout:
```
[0] = resp_code
[132] = public key (32 bytes)
[33] = type (1=chat, 2=repeater, 3=room, 4=sensor)
[34] = flags (bit 0 = favorite)
[35] = path_length
[3699] = path (64 bytes)
[100131] = name (32 bytes, null-padded)
[132135] = timestamp (uint32 LE)
[136139] = latitude (int32 LE, × 1e-6 degrees)
[140143] = longitude (int32 LE, × 1e-6 degrees)
[144147] = last_modified (uint32 LE)
```
### Message (Direct)
Sender key, text, timestamp, outgoing flag, status (pending/sent/delivered/failed), message ID (UUID), retry count, ACK hash, trip time, path data, reactions.
### Channel Message
Sender name, text, timestamp, status (pending/sent/failed), repeater hops, path variants, channel index, reactions, reply threading fields.
### Channel
Index (07), name, 16-byte PSK, unread count. PSK derivation methods for hashtag (SHA-256) and community (HMAC-SHA256) channels.
### Community
UUID, name, 32-byte secret, hashtag channel list. Shared via QR code.
## Persistence
All data is stored via `SharedPreferences` (JSON-serialized). No SQLite or other database.
| Data | Storage Key Pattern | Scope |
|---|---|---|
| Contacts | `contacts<pubKey10>` | Per device identity |
| Messages | `messages_<pubKey10><contactKey>` | Per device + contact |
| Channel Messages | `channel_messages_<pubKey10><index>` | Per device + channel |
| Channels | `channels<pubKey10>` | Per device identity |
| Channel Order | `channel_order_<pubKey10>` | Per device identity |
| Contact Groups | `contact_groups<pubKey10>` | Per device identity |
| Communities | `communities_v1<pubKey10>` | Per device identity |
| Unread Counts | `contact_unread_count<pubKey10>` | Per device identity |
| Discovered Contacts | `discovered_contacts` | Global |
| App Settings | `app_settings` | Global |
| Path History | `path_history_<contactKey>` | Per contact |
## Auto-Add Configuration Bitmask
Used by `CMD_SET_AUTO_ADD_CONFIG` (58) and `RESP_CODE_AUTO_ADD_CONFIG` (25):
| Bit | Flag | Description |
|-----|------|-------------|
| 0 | 0x01 | Overwrite oldest contact when list is full |
| 1 | 0x02 | Auto-add chat users |
| 2 | 0x04 | Auto-add repeaters |
| 3 | 0x08 | Auto-add room servers |
| 4 | 0x10 | Auto-add sensors |
## Radio Packet Payload Types
Seen inside `PUSH_CODE_LOG_RX_DATA` raw packets:
| Code | Type |
|------|------|
| 0x00 | REQ (request) |
| 0x01 | RESPONSE |
| 0x02 | TXTMSG (text message) |
| 0x03 | ACK |
| 0x04 | ADVERT |
| 0x05 | GRPTXT (group/channel text) |
| 0x06 | GRPDATA (group data) |
| 0x07 | ANONREQ (anonymous request) |
| 0x08 | PATH |
| 0x09 | TRACE |
| 0x0A | MULTIPART |
| 0x0B | CONTROL |
| 0x0F | RAW_CUSTOM |
## State Management
Uses Flutter `Provider` with `ChangeNotifier`. The central state holder is `MeshCoreConnector`, which owns all in-memory collections and fires debounced (50ms) `notifyListeners()` to update the UI. In-memory conversations are windowed to 200 messages per contact; older messages remain on disk and are loaded on demand.
### Data Flow
1. Raw frames arrive over BLE/USB/TCP
2. First byte is parsed as response/push code
3. Appropriate model factory (`fromFrame()`) parses the data
4. In-memory collections are updated
5. Storage stores are persisted (async)
6. `notifyListeners()` triggers UI rebuilds
7. Screens read current state via getters