diff --git a/README.md b/README.md index 5a0941753..9cf043e3b 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ MeshCore provides the ability to create wireless mesh networks, similar to Mesht * Multi-Hop Packet Routing * Devices can forward messages across multiple nodes, extending range beyond a single radio's reach. * Supports up to a configurable number of hops to balance network efficiency and prevent excessive traffic. - * Nodes use fixed roles where "Companion" nodes are not repeating messages at all to prevent adverse routing paths from being used. + * Nodes use fixed roles where Companion nodes do not repeat by default. Companion firmware can optionally enable client repeat mode on specific frequencies. * Supports LoRa Radios – Works with Heltec, RAK Wireless, and other LoRa-based hardware. * Decentralized & Resilient – No central server or internet required; the network is self-healing. * Low Power Consumption – Ideal for battery-powered or solar-powered devices. diff --git a/docs/cli_commands.md b/docs/cli_commands.md index 7ade97066..3dd72147f 100644 --- a/docs/cli_commands.md +++ b/docs/cli_commands.md @@ -53,7 +53,7 @@ This document provides an overview of CLI commands that can be sent to MeshCore - `time ` **Parameters:** -- `epoc_seconds`: Unix epoc time +- `epoch_seconds`: Unix epoch time --- @@ -91,6 +91,14 @@ This document provides an overview of CLI commands that can be sent to MeshCore --- +### Trigger active neighbor discovery +**Usage:** +- `discover.neighbors` + +**Note:** Sends a node discovery request and refreshes the repeater's neighbor list from matching repeater discovery responses. + +--- + ### Remove a neighbor **Usage:** - `neighbor.remove ` @@ -136,7 +144,7 @@ This document provides an overview of CLI commands that can be sent to MeshCore --- -### End capture of rx log to node sotrage +### End capture of rx log to node storage **Usage:** `log stop` --- @@ -165,6 +173,13 @@ This document provides an overview of CLI commands that can be sent to MeshCore --- +### Show the bootloader version +**Usage:** `get bootloader.ver` + +**Note:** Supported on nRF52 builds. Returns `ERROR: unsupported` on other platforms and `> unknown` if unavailable. + +--- + ## Configuration ### Radio @@ -200,7 +215,7 @@ This document provides an overview of CLI commands that can be sent to MeshCore **Default:** Varies by board -**Notes:** This setting only controls the power level of the LoRa chip. Some nodes have an additional power amplifier stage which increases the total output. Referr to the node's manual for the correct setting to use. **Setting a value too high may violate the laws in your country.** +**Notes:** This setting only controls the power level of the LoRa chip. Some nodes have an additional power amplifier stage which increases the total output. Refer to the node's manual for the correct setting to use. **Setting a value too high may violate the laws in your country.** --- @@ -402,7 +417,7 @@ This document provides an overview of CLI commands that can be sent to MeshCore **Parameters:** - `value`: Direct transmit delay factor (0-2) -**Default:** `0.2` +**Default:** `0.3` (Simple Repeater), `0.2` (Simple Room Server / Simple Sensor) --- diff --git a/docs/companion_protocol.md b/docs/companion_protocol.md index 9d45b59ef..aa2b1347e 100644 --- a/docs/companion_protocol.md +++ b/docs/companion_protocol.md @@ -1,7 +1,7 @@ # Companion Protocol - **Last Updated**: 2026-01-03 -- **Protocol Version**: Companion Firmware v1.12.0+ +- **Protocol Version**: Companion Firmware v1.13.0+ (frame protocol code 9) > NOTE: This document is still in development. Some information may be inaccurate. @@ -100,7 +100,7 @@ When writing commands to the RX characteristic, specify the write type: ### MTU (Maximum Transmission Unit) -The default BLE MTU is 23 bytes (20 bytes payload). For larger commands like `SET_CHANNEL` (66 bytes), you may need to: +The default BLE MTU is 23 bytes (20 bytes payload). For larger commands like `SET_CHANNEL` (50 bytes), you may need to: 1. **Request Larger MTU**: Request MTU of 512 bytes if supported - Android: `gatt.requestMtu(512)` @@ -187,7 +187,7 @@ Bytes 2-10: "mccli" (ASCII, null-padded to 9 bytes) **Command Format**: ``` Byte 0: 0x16 -Byte 1: 0x03 +Byte 1: App target protocol version (for example, 0x03) ``` **Example** (hex): @@ -229,10 +229,10 @@ Byte 1: Channel Index (0-7) Byte 0: 0x20 Byte 1: Channel Index (0-7) Bytes 2-33: Channel Name (32 bytes, UTF-8, null-padded) -Bytes 34-65: Secret (32 bytes) +Bytes 34-49: Secret (16 bytes) ``` -**Total Length**: 66 bytes +**Total Length**: 50 bytes **Channel Index**: - Index 0: Reserved for public channels (no secret) @@ -243,14 +243,16 @@ Bytes 34-65: Secret (32 bytes) - Maximum 32 bytes - Padded with null bytes (0x00) if shorter -**Secret Field** (32 bytes): -- For **private channels**: 32-byte secret -- For **public channels**: All zeros (0x00) +**Secret Field**: +- Firmware stores and uses a 16-byte (128-bit) channel secret. +- Current firmware expects a 16-byte secret payload (`len >= 2 + 32 + 16`). +- 32-byte secret payload variants are currently rejected as unsupported. +- For **public channels**: all zeros (0x00). **Example** (create channel "YourChannelName" at index 1 with secret): ``` 20 01 53 4D 53 00 00 ... (name padded to 32 bytes) - [32 bytes of secret] + [16 bytes of secret] ``` **Response**: `PACKET_OK` (0x00) on success, `PACKET_ERROR` (0x01) on failure @@ -306,7 +308,7 @@ Byte 0: 0x0A ### 7. Get Battery -**Purpose**: Query device battery level. +**Purpose**: Query battery millivolts and storage usage. **Command Format**: ``` @@ -318,7 +320,7 @@ Byte 0: 0x14 14 ``` -**Response**: `PACKET_BATTERY` (0x0C) with battery percentage +**Response**: `PACKET_BATTERY` (0x0C) with battery millivolts and storage totals --- @@ -354,13 +356,28 @@ Byte 0: 0x14 - Send `CMD_SET_CHANNEL` with empty name and all-zero secret - Or overwrite with a new channel +### Client Repeat Mode (v9+) + +Client repeat is controlled through `CMD_SET_RADIO_PARAMS`: +- Command byte: `0x0B` +- Payload includes radio params and an optional trailing `repeat` byte (firmware protocol code 9+). +- `repeat = 0`: client repeat disabled +- `repeat != 0`: client repeat enabled (subject to frequency validation) + +Current allowed frequencies for enabling repeat are: +- `433000` kHz +- `869000` kHz +- `918000` kHz + +If repeat is enabled at a different frequency, firmware returns `PACKET_ERROR` with illegal argument. + --- ## Message Handling ### Receiving Messages -Messages are received via the RX characteristic (notifications). The device sends: +Messages are received via the TX characteristic (notifications). The device sends: 1. **Channel Messages**: - `PACKET_CHANNEL_MSG_RECV` (0x08) - Standard format @@ -492,7 +509,8 @@ def parse_channel_message(data): Use the `SEND_CHANNEL_MESSAGE` command (see [Commands](#commands)). **Important**: -- Messages are limited to 133 characters per MeshCore specification +- Message payloads are limited by `MAX_TEXT_LEN` in firmware (currently `10 * 16 = 160` bytes). +- For channel messages, this same limit includes the firmware-added `": "` prefix. - Long messages should be split into chunks - Include a chunk indicator (e.g., "[1/3] message text") @@ -515,13 +533,13 @@ Use the `SEND_CHANNEL_MESSAGE` command (see [Commands](#commands)). | 0x08 | PACKET_CHANNEL_MSG_RECV | Channel message (standard) | | 0x09 | PACKET_CURRENT_TIME | Current time response | | 0x0A | PACKET_NO_MORE_MSGS | No more messages available | -| 0x0C | PACKET_BATTERY | Battery level | +| 0x0C | PACKET_BATTERY | Battery mV + storage usage | | 0x0D | PACKET_DEVICE_INFO | Device information | | 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 | | 0x80 | PACKET_ADVERTISEMENT | Advertisement packet | -| 0x82 | PACKET_ACK | Acknowledgment | +| 0x82 | PACKET_SEND_CONFIRMED | Send confirmation (ack + RTT) | | 0x83 | PACKET_MESSAGES_WAITING | Messages waiting notification | | 0x88 | PACKET_LOG_DATA | RF log data (can be ignored) | @@ -544,11 +562,9 @@ Byte 1: Error code (optional) Byte 0: 0x12 Byte 1: Channel Index Bytes 2-33: Channel Name (32 bytes, null-terminated) -Bytes 34-65: Secret (32 bytes, but device typically only returns 20 bytes total) +Bytes 34-49: Secret (16 bytes) ``` -**Note**: The device may not return the full 66-byte packet. Parse what is available. The secret field is typically not returned for security reasons. - **PACKET_DEVICE_INFO** (0x0D): ``` Byte 0: 0x0D @@ -562,6 +578,7 @@ Bytes 4-7: BLE PIN (32-bit little-endian) Bytes 8-19: Firmware Build (12 bytes, UTF-8, null-padded) Bytes 20-59: Model (40 bytes, UTF-8, null-padded) Bytes 60-79: Version (20 bytes, UTF-8, null-padded) +Byte 80: Client repeat flag (`0`/`1`) for protocol code 9+ ``` **Parsing Pseudocode**: @@ -580,6 +597,8 @@ def parse_device_info(data): info['fw_build'] = data[8:20].decode('utf-8').rstrip('\x00').strip() info['model'] = data[20:60].decode('utf-8').rstrip('\x00').strip() info['ver'] = data[60:80].decode('utf-8').rstrip('\x00').strip() + if len(data) >= 81: + info['client_repeat'] = data[80] return info ``` @@ -587,29 +606,25 @@ def parse_device_info(data): **PACKET_BATTERY** (0x0C): ``` Byte 0: 0x0C -Bytes 1-2: Battery Level (16-bit little-endian, percentage 0-100) - -Optional (if data size > 3): -Bytes 3-6: Used Storage (32-bit little-endian, KB) -Bytes 7-10: Total Storage (32-bit little-endian, KB) +Bytes 1-2: Battery millivolts (16-bit little-endian) +Bytes 3-6: Used storage (32-bit little-endian, KB) +Bytes 7-10: Total storage (32-bit little-endian, KB) ``` **Parsing Pseudocode**: ```python def parse_battery(data): - if len(data) < 3: + if len(data) < 11: return None - - level = int.from_bytes(data[1:3], 'little') - info = {'level': level} - - if len(data) > 3: - used_kb = int.from_bytes(data[3:7], 'little') - total_kb = int.from_bytes(data[7:11], 'little') - info['used_kb'] = used_kb - info['total_kb'] = total_kb - - return info + + battery_mv = int.from_bytes(data[1:3], 'little') + used_kb = int.from_bytes(data[3:7], 'little') + total_kb = int.from_bytes(data[7:11], 'little') + return { + 'battery_mv': battery_mv, + 'used_kb': used_kb, + 'total_kb': total_kb, + } ``` **PACKET_SELF_INFO** (0x05): @@ -680,15 +695,16 @@ def parse_self_info(data): **PACKET_MSG_SENT** (0x06): ``` Byte 0: 0x06 -Byte 1: Message Type -Bytes 2-5: Expected ACK (4 bytes, hex) -Bytes 6-9: Suggested Timeout (32-bit little-endian, seconds) +Byte 1: Route mode (0 = direct, 1 = flood) +Bytes 2-5: Request/Send Tag (4 bytes) +Bytes 6-9: Suggested timeout (32-bit little-endian, milliseconds) ``` -**PACKET_ACK** (0x82): +**PACKET_SEND_CONFIRMED** (0x82): ``` Byte 0: 0x82 -Bytes 1-6: ACK Code (6 bytes, hex) +Bytes 1-4: ACK hash (4 bytes) +Bytes 5-8: Trip time (32-bit little-endian, milliseconds) ``` ### Error Codes @@ -825,12 +841,12 @@ device = scan_for_device("MeshCore") gatt = connect_to_device(device) # 3. Discover services and characteristics -service = discover_service(gatt, "0000ff00-0000-1000-8000-00805f9b34fb") -rx_char = discover_characteristic(service, "0000ff01-0000-1000-8000-00805f9b34fb") -tx_char = discover_characteristic(service, "0000ff02-0000-1000-8000-00805f9b34fb") +service = discover_service(gatt, "6E400001-B5A3-F393-E0A9-E50E24DCCA9E") +rx_char = discover_characteristic(service, "6E400002-B5A3-F393-E0A9-E50E24DCCA9E") +tx_char = discover_characteristic(service, "6E400003-B5A3-F393-E0A9-E50E24DCCA9E") -# 4. Enable notifications on RX characteristic -enable_notifications(rx_char, on_notification_received) +# 4. Enable notifications on TX characteristic +enable_notifications(tx_char, on_notification_received) # 5. Send AppStart command send_command(tx_char, build_app_start()) diff --git a/docs/faq.md b/docs/faq.md index 220b8971c..492dd64e9 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -44,7 +44,7 @@ A list of frequently-asked questions and answers for MeshCore - [5.1. Q: What are BW, SF, and CR?](#51-q-what-are-bw-sf-and-cr) - [5.2. Q: Do MeshCore clients repeat?](#52-q-do-meshcore-clients-repeat) - [5.3. Q: What happens when a node learns a route via a mobile repeater, and that repeater is gone?](#53-q-what-happens-when-a-node-learns-a-route-via-a-mobile-repeater-and-that-repeater-is-gone) - - [5.4. Q: How does a node discovery a path to its destination and then use it to send messages in the future, instead of flooding every message it sends like Meshtastic?](#54-q-how-does-a-node-discovery-a-path-to-its-destination-and-then-use-it-to-send-messages-in-the-future-instead-of-flooding-every-message-it-sends-like-meshtastic) + - [5.4. Q: How does a node discover a path to its destination and then use it to send messages in the future, instead of flooding every message it sends like Meshtastic?](#54-q-how-does-a-node-discover-a-path-to-its-destination-and-then-use-it-to-send-messages-in-the-future-instead-of-flooding-every-message-it-sends-like-meshtastic) - [5.5. Q: Do public channels always flood? Do private channels always flood?](#55-q-do-public-channels-always-flood-do-private-channels-always-flood) - [5.6. Q: what is the public key for the default public channel?](#56-q-what-is-the-public-key-for-the-default-public-channel) - [5.7. Q: Is MeshCore open source?](#57-q-is-meshcore-open-source) @@ -200,9 +200,9 @@ The T-Deck firmware is free to download and most features are available without ### 2.3. Q: What frequencies are supported by MeshCore? -**A:** It supports the 868MHz range in the UK/EU and the 915MHz range in New Zealand, Australia, and the USA. Countries and regions in these two frequency ranges are also supported. +**A:** Common deployments use the 868MHz and 915MHz ranges, and some builds/regions also use 433MHz. Use only frequencies and presets that are legal for your country/region. -Use the smartphone client or the repeater setup feature on there web flasher to set your radios' RF settings by choosing the preset for your regions. +Use the smartphone client or the repeater setup feature on the web flasher to set your radio RF settings by choosing the preset for your region. Recently, as of October 2025, many regions have moved to the "narrow" setting, aka using BW62.5 and a lower SF number (instead of the original SF11). For example, USA/Canada (Recommended) preset is 910.525MHz, SF7, BW62.5, CR5. @@ -446,16 +446,17 @@ So, it's balancing act between speed of the transmission and resistance to noise things network is mainly focused on LoRaWAN, but the LoRa low-level stuff still checks out for any LoRa project ### 5.2. Q: Do MeshCore clients repeat? -**A:** No, MeshCore clients do not repeat. This is the core of MeshCore's messaging-first design. This is to avoid devices flooding the air ware and create endless collisions, so messages sent aren't received. -In MeshCore, only repeaters and room server with `set repeat on` repeat. +**A:** By default, clients do not repeat. In normal operation, repeaters and room servers (with `set repeat on`) are the nodes that relay traffic. + +Companion firmware has an optional client repeat mode controlled by app protocol settings (`client_repeat`). In current firmware, enabling this mode is restricted to specific frequencies (433.000, 869.000, and 918.000 MHz). ### 5.3. Q: What happens when a node learns a route via a mobile repeater, and that repeater is gone? **A:** If you used to reach a node through a repeater and the repeater is no longer reachable, the client will send the message using the existing (but now broken) known path, the message will fail after 3 retries, and the app will reset the path and send the message as flood on the last retry by default. This can be turned off in settings. If the destination is reachable directly or through another repeater, the new path will be used going forward. Or you can set the path manually if you know a specific repeater to use to reach that destination. -In the case if users are moving around frequently, and the paths are breaking, they just see the phone client retries and revert to flood to attempt to re-establish a path. +If users are moving around frequently and paths are breaking, the phone client retries and reverts to flood to re-establish a path. -### 5.4. Q: How does a node discovery a path to its destination and then use it to send messages in the future, instead of flooding every message it sends like Meshtastic? +### 5.4. Q: How does a node discover a path to its destination and then use it to send messages in the future, instead of flooding every message it sends like Meshtastic? Routes are stored in sender's contact list. When you send a message the first time, the message first gets to your destination by flood routing. When your destination node gets the message, it will send back a delivery report to the sender with all repeaters that the original message went through. This delivery report is flood-routed back to you the sender and is a basis for future direct path. When you send the next message, the path will get embedded into the packet and be evaluated by repeaters. If the hop and address of the repeater matches, it will retransmit the message, otherwise it will not retransmit, hence minimizing utilization. @@ -533,13 +534,13 @@ Javascript: https://github.com/liamcottle/meshcore.js ### 5.11. Q: Does MeshCore support ATAK **A:** ATAK is not currently on MeshCore's roadmap. -Meshcore would not be best suited to ATAK because MeshCore: -clients do not repeat and therefore you would need a network of repeaters in place +MeshCore would not be best suited to ATAK because MeshCore: +clients do not repeat by default and therefore you still need a network of repeaters in place will not have a stable path where all clients are constantly moving between repeaters MeshCore clients would need to reset path constantly and flood traffic across the network which could lead to lots of collisions with something as chatty as ATAK. -This could change in the future if MeshCore develops a client firmware that repeats. +Companion firmware now has an optional repeat mode, but it is frequency-restricted and does not remove ATAK's broader mobility and path-stability challenges. [Source](https://discord.com/channels/826570251612323860/1330643963501351004/1354780032140054659) ### 5.12. Q: How do I add a node to the [MeshCore Map](https://meshcore.co.uk/map.html) @@ -553,14 +554,14 @@ You can use the same companion (same public key) that you used to add your repea ### 5.13. Q: Can I use a Raspberry Pi to update a MeshCore radio? -** A:** Yes. +**A:** Yes. Below are the instructions to flash firmware onto a supported LoRa device using a Raspberry Pi over USB serial. > Instructions for nRF devices like RAK, T1000-E, T114 are immediately after the ESP instructions For ESP-based devices (e.g. Heltec V3) you need: - Download firmware file from flasher.meshcore.co.uk - - Go to the web site on a browser, find the section that has the firmware up need + - Go to the website in a browser, find the section that has the firmware you need - Click the Download button, right click on the file you need, for example, - `Heltec_V3_companion_radio_ble-v1.7.1-165fb33.bin` - Non-merged bin keeps the existing Bluetooth pairing database @@ -588,7 +589,7 @@ For ESP-based devices (e.g. Heltec V3) you need: For nRF devices (e.g. RAK, Heltec T114) you need the following: - Download firmware file from flasher.meshcore.co.uk - - Go to the web site on a browser, find the section that has the firmware up need + - Go to the website in a browser, find the section that has the firmware you need - You need the ZIP version for the adafruit flash tool (below) - Click the Download button, right click on the ZIP file, for example: - `RAK_4631_companion_radio_ble-v1.7.1-165fb33.zip` @@ -629,7 +630,7 @@ https://github.com/samuk/awesome-meshcore. #### 5.14.2. programming libraries, command line software ##### 5.14.2.1. meshcoremqtt -A Python script to send meshcore debug and packet capture data to MQTT for analysis. Cisien's version is a fork of Andrew-a-g's and is being used to to collect data for https://map.w0z.is/messages and https://analyzer.letsmesh.net/ +A Python script to send meshcore debug and packet capture data to MQTT for analysis. Cisien's version is a fork of Andrew-a-g's and is being used to collect data for https://map.w0z.is/messages and https://analyzer.letsmesh.net/ https://github.com/Cisien/meshcoretomqtt https://github.com/Andrew-a-g/meshcoretomqtt @@ -757,7 +758,7 @@ You can get the epoch time on and use it to se - For RAK, click the reset button **TWICE** - For T1000-e, quickly disconnect and reconnect the magnetic side of the cable from the device **TWICE** - For Heltec T114, click the reset button **TWICE** (the bottom button) - - For Xiao nRF52, click the reset button once. If that doesn't work, quickly double click the reset button twice. If that doesn't work, disconnection the board from your PC and reconnect again ([seeed studio wiki](https://wiki.seeedstudio.com/XIAO_BLE/#access-the-swd-pins-for-debugging-and-reflashing-bootloader)) + - For Xiao nRF52, click the reset button once. If that doesn't work, quickly double click the reset button twice. If that doesn't work, disconnect the board from your PC and reconnect again ([seeed studio wiki](https://wiki.seeedstudio.com/XIAO_BLE/#access-the-swd-pins-for-debugging-and-reflashing-bootloader)) 5. A new folder will appear on your computer's desktop 6. Download the `flash_erase*.uf2` file for your device on flasher.meshcore.co.uk - RAK WisBlock and Heltec T114: `Flash_erase-nRF32_softdevice_v6.uf2` @@ -795,7 +796,7 @@ Allow the browser user on it: 9. Select the firmware zip file you downloaded 10. Select the device you want to update. If the device you want to update is not on the list, try enabling`OTA` on the device again 11. If the device is not found, enable `Force Scanning` in the DFU app -12. Tab the `Upload` to begin OTA update +12. Tap `Upload` to begin OTA update 13. If it fails, try turning off and on Bluetooth on your phone. If that doesn't work, try rebooting your phone. 14. Wait for the update to complete. It can take a few minutes. @@ -813,8 +814,8 @@ After this bootloader is flashed onto the device, you can trigger over the air u 2. From the MeshCore app, login remotely to the repeater you want to update with admin privilege 4. Go to the Command Line tab, type `start ota` and hit enter. 5. you should see `OK` to confirm the repeater device is now in OTA mode -6. The command `start ota` on an ESP32-based device starts a wifi hotspot named `MeshCore OTA` -7. From your phone or computer connect to the 'MeshCore OTA' hotspot +6. The command `start ota` on an ESP32-based device starts a Wi-Fi hotspot named `MeshCore-OTA` +7. From your phone or computer connect to the 'MeshCore-OTA' hotspot 8. From a browser, go to http://192.168.4.1/update and upload the non-merged bin from the flasher @@ -857,11 +858,15 @@ where `&type` is: ### 7.6. Q: How do I connect to the companion via WIFI, e.g. using a heltec v3? **A:** WiFi firmware requires you to compile it yourself, as you need to set the wifi ssid and password. -Edit WIFI_SSID and WIFI_PWD in `./variants/heltec_v3/platformio.ini` and then flash it to your device. +Edit `WIFI_SSID` and `WIFI_PWD` in your board's `platformio.ini` companion WiFi environment and then flash it to your device. + +Current companion WiFi build environments include: +- `env:Heltec_V3_companion_radio_wifi` in `./variants/heltec_v3/platformio.ini` +- `env:T_Beam_S3_Supreme_SX1262_companion_radio_wifi` in `./variants/lilygo_tbeam_supreme_SX1262/platformio.ini` ### 7.7. Q: I have a Station G2, or a Heltec V4, or an Ikoka Stick, or a radio with a EByte E22-900M30S or a E22-900M33S module, what should their transmit power be set to? **A:** -For companion radios, you can set these radios' transmit power in the smartphone app. For repeater and room server radios, you can set their transmit power using the command line command `set tx`. You can get their current value using command line comand `get tx` +For companion radios, you can set these radios' transmit power in the smartphone app. For repeater and room server radios, you can set their transmit power using the command line command `set tx`. You can get their current value using command line command `get tx` > ### ⚠️ **WARNING: Set these values at your own risk. Incorrect power settings can permanently damage your radio hardware.** diff --git a/docs/packet_format.md b/docs/packet_format.md index 50f9c01a7..1f004dc05 100644 --- a/docs/packet_format.md +++ b/docs/packet_format.md @@ -9,7 +9,7 @@ This document describes the MeshCore packet format. ## Version 1 Packet Format -This is the protocol level packet structure used in MeshCore firmware v1.12.0 +This is the protocol-level packet structure used in current MeshCore v1 firmware. ``` [header][transport_codes(optional)][path_length][path][payload] diff --git a/docs/payloads.md b/docs/payloads.md index 3648b6557..f33b6ba48 100644 --- a/docs/payloads.md +++ b/docs/payloads.md @@ -46,12 +46,23 @@ Appdata Appdata Flags +The `flags` byte mixes node type and optional field flags: +- Lower 4 bits (`flags & 0x0F`) = node type +- Upper 4 bits (`flags & 0xF0`) = optional fields present + +Node type values (lower nibble): + +| Value | Name | +|--------|----------------| +| `0x01` | chat node | +| `0x02` | repeater node | +| `0x03` | room server | +| `0x04` | sensor node | + +Optional field flags (upper bits): + | Value | Name | Description | |--------|----------------|---------------------------------------| -| `0x01` | is chat node | advert is for a chat node | -| `0x02` | is repeater | advert is for a repeater | -| `0x03` | is room server | advert is for a room server | -| `0x04` | is sensor | advert is for a sensor server | | `0x10` | has location | appdata contains lat/long information | | `0x20` | has feature 1 | Reserved for future use. | | `0x40` | has feature 2 | Reserved for future use. | @@ -59,11 +70,11 @@ Appdata Flags # Acknowledgement -An acknowledgement that a message was received. Note that for returned path messages, an acknowledgement can be sent in the "extra" payload (see [Returned Path](#returned-path)) instead of as a separate ackowledgement packet. CLI commands do not cause acknowledgement responses, neither discrete nor extra. +An acknowledgement that a message was received. Note that for returned path messages, an acknowledgement can be sent in the "extra" payload (see [Returned Path](#returned-path)) instead of as a separate acknowledgement packet. CLI commands do not cause acknowledgement responses, neither discrete nor extra. | Field | Size (bytes) | Description | |----------|--------------|------------------------------------------------------------| -| checksum | 4 | CRC checksum of message timestamp, text, and sender pubkey | +| checksum | 4 | first 4 bytes of SHA-256 over message timestamp, text, and sender pubkey | # Returned path, request, response, and plain text message @@ -90,11 +101,11 @@ Returned path messages provide a description of the route a packet took from the ## Request -| Field | Size (bytes) | Description | -|--------------|-----------------|----------------------------| -| timestamp | 4 | send time (unix timestamp) | -| request type | 1 | see below | -| request data | rest of payload | depends on request type | +| Field | Size (bytes) | Description | +|--------------|-----------------|------------------------------------------------------------------------------------------| +| tag | 4 | request tag (typically sender timestamp/unique timestamp); reflected in response bytes 0..3 | +| request type | 1 | see below | +| request data | rest of payload | depends on request type | Request type @@ -102,7 +113,7 @@ Request type |--------|----------------------|---------------------------------------| | `0x01` | get stats | get stats of repeater or room server | | `0x02` | keepalive | (deprecated) | -| `0x03` | get telemetry data | TODO | +| `0x03` | get telemetry data | get telemetry payload from target node | | `0x04` | get min,max,avg data | sensor nodes - get min, max, average for given time span | | `0x05` | get access list | get node's approved access list | | `0x06` | get neighbors | get repeater node's neighbors | @@ -128,40 +139,82 @@ Gets information about the node, possibly including the following: * Last SNR value * Number of direct route duplicates * Number of flood route duplicates -* Number posted (?) -* Number of post pushes (?) +* Number of posts created (room server) +* Number of post push notifications sent (room server) ### Get telemetry data -Request data about sensors on the node, including battery level. +Requests telemetry payload from the target node. -### Get Telemetry +Typical request data (used by companion/mesh helpers): +- byte 0: inverse telemetry permission mask (`~mask`) used by node-side filtering +- bytes 1..3: reserved -TODO +Response content: +- telemetry payload bytes (LPP-style encoded telemetry), prefixed by the 4-byte response tag. ### Get Min/Max/Ave (Sensor nodes) -TODO +Sensor request data: +- bytes 0..3: `start_secs_ago` (`uint32`) +- bytes 4..7: `end_secs_ago` (`uint32`) +- byte 8: reserved (must be `0`) +- byte 9: reserved (must be `0`) + +Sensor response content (after 4-byte response tag): +- bytes 0..3: current node time (`uint32`) +- repeated per record: + - channel (`uint8`) + - telemetry type (`uint8`) + - min value (encoded by telemetry type) + - max value (encoded by telemetry type) + - avg value (encoded by telemetry type) ### Get Access List -TODO +Returns ACL entries (admin-only operation on server-side handlers). + +Request data: +- reserved bytes, expected as zero by current handlers. -### Get Neighors +Response content (after 4-byte response tag): +- repeated entries of: + - pubkey prefix (6 bytes) + - permissions (`uint8`) -TODO +### Get Neighbors (Repeater) + +Request data format (version `0`): + +| Field | Size (bytes) | Description | +|----------------------|--------------|-------------| +| request version | 1 | `0` currently supported | +| count | 1 | max neighbors to return | +| offset | 2 | start index into sorted neighbors | +| order_by | 1 | `0` newest->oldest, `1` oldest->newest, `2` strongest->weakest, `3` weakest->strongest | +| pubkey_prefix_length | 1 | number of pubkey bytes per entry (clamped to 32) | +| random | 4 | request uniqueness blob | + +Response content (after 4-byte response tag): +- `neighbours_count` (`uint16`): total available neighbors +- `results_count` (`uint16`): entries returned in this response +- repeated entries: + - pubkey prefix (`pubkey_prefix_length` bytes) + - `heard_seconds_ago` (`uint32`) + - `snr_x4` (`int8`) ### Get Owner Info -TODO +Repeater response content is UTF-8 text: +- `"\n\n"` ## Response | Field | Size (bytes) | Description | |---------|-----------------|-------------| -| tag | 4 | TODO | -| content | rest of payload | TODO | +| tag | 4 | mirrored request tag/sender timestamp | +| content | rest of payload | request-specific response bytes | ## Plain text message @@ -246,7 +299,7 @@ The plaintext contained in the ciphertext matches the format described in [plain | Field | Size (bytes) | Description | |--------------|-----------------|--------------------------------------------| -| flags | 1 | upper 4 bits is sub_type | +| flags | 1 | upper 4 bits are sub_type, lower bits are subtype-specific | | data | rest of payload | typically unencrypted data | ## DISCOVER_REQ (sub_type) @@ -254,10 +307,15 @@ The plaintext contained in the ciphertext matches the format described in [plain | Field | Size (bytes) | Description | |--------------|-----------------|----------------------------------------------| | flags | 1 | 0x8 (upper 4 bits), prefix_only (lowest bit) | -| type_filter | 1 | bit for each ADV_TYPE_* | +| type_filter | 1 | bit mask by advert type (`1 << ADV_TYPE_*`) | | tag | 4 | randomly generate by sender | | since | 4 | (optional) epoch timestamp (0 by default) | +`type_filter` examples: +- repeater: `1 << 2` (`0x04`) +- room server: `1 << 3` (`0x08`) +- sensor: `1 << 4` (`0x10`) + ## DISCOVER_RESP (sub_type) | Field | Size (bytes) | Description |