mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-07-11 19:17:04 +10:00
update doc
This commit is contained in:
@@ -6,61 +6,70 @@ This page covers how MeshCore Open represents, selects, validates, and stores ro
|
||||
|
||||
MeshCore supports variable-length multi-byte routing paths so the app can scale from small meshes to very large node sets.
|
||||
|
||||
### Path Encoding Format
|
||||
### Hash Width and Multi-Byte Paths
|
||||
|
||||
Each path byte packs both the hop count and the hash width:
|
||||
The device capability determines the hash width (number of bytes per hop):
|
||||
|
||||
```
|
||||
Bit 7-6: Hash mode (2 bits) → hash_bytes = 1 << mode
|
||||
Bit 5-0: Hop count (6 bits) → max 63 hops
|
||||
```
|
||||
|
||||
| Mode | Hash Bytes | Max Hops | Max Unique Nodes | Firmware |
|
||||
|------|-----------|----------|------------------|----------|
|
||||
| 0 | 1 | 63 | 256 | v1.13+ |
|
||||
| 1 | 2 | 63 | 65,536 | v1.14+ |
|
||||
| 2 | 3 | 63 | 16.7M | v1.14+ |
|
||||
| 3 | 4 | 63 | 4.3B | v1.14+ |
|
||||
|
||||
### Path Byte Calculation
|
||||
|
||||
```dart
|
||||
final pathLenRaw = frameData[index];
|
||||
final hopCount = pathLenRaw & 0x3F;
|
||||
final hashMode = (pathLenRaw >> 6) & 0x03;
|
||||
final hashBytes = 1 << hashMode;
|
||||
|
||||
final pathByteLength = hopCount * hashBytes;
|
||||
final pathData = frameData.sublist(index + 1, index + 1 + pathByteLength);
|
||||
```
|
||||
| Width | Max Unique Nodes | Typical Use |
|
||||
|-------|-----------------|-------------|
|
||||
| 1 byte | 256 | Single-byte node IDs |
|
||||
| 2 bytes | 65,536 | Medium meshes |
|
||||
| 3 bytes | 16.7M | Large networks |
|
||||
| 4 bytes | 4.3B | Gigantic deployments |
|
||||
|
||||
### Device Capability Detection
|
||||
|
||||
The app reads the device's reported capability byte to determine whether multi-byte paths are available:
|
||||
On device connection, the app reads the firmware capability to set `pathHashByteWidth`:
|
||||
|
||||
```dart
|
||||
if (firmwareBytes.length >= 82) {
|
||||
final mode = (firmwareBytes[81] & 0xFF).clamp(0, 2);
|
||||
pathHashByteWidth = mode + 1;
|
||||
} else {
|
||||
pathHashByteWidth = 1;
|
||||
}
|
||||
// Read from device info response (offset 81)
|
||||
final modeRaw = firmwareBytes.length >= 82
|
||||
? (firmwareBytes[81] & 0x3F)
|
||||
: 0;
|
||||
final mode = modeRaw.clamp(0, 3);
|
||||
_pathHashByteWidth = mode + 1; // 1, 2, 3, or 4 bytes per hop
|
||||
```
|
||||
|
||||
### Path Data Structure
|
||||
|
||||
Paths in messages and storage consist of:
|
||||
|
||||
- **`pathLength`**: Hop count reported in the radio header (may differ from decoded path)
|
||||
- **`pathBytes`**: Raw bytes of the path, grouped by `pathHashByteWidth`
|
||||
- **Example**: With `pathHashByteWidth=2`, a 3-hop path needs 6 bytes:
|
||||
- `pathBytes = [0xA1, 0xA2, 0xB1, 0xB2, 0xC1, 0xC2]`
|
||||
- Hops: `[0xA1A2]`, `[0xB1B2]`, `[0xC1C2]`
|
||||
|
||||
### Hop Count Calculation
|
||||
|
||||
Convert path byte length to hop count:
|
||||
|
||||
```dart
|
||||
int hopCount = (byteCount + hashByteWidth - 1) ~/ hashByteWidth;
|
||||
```
|
||||
|
||||
Use this consistently when displaying hop counts in UI to avoid mismatch between metadata (`pathLength`) and observed paths (`pathBytes`).
|
||||
|
||||
### Path Usage in Different Message Types
|
||||
|
||||
- Direct messages extract the path from the decrypted payload to trace the sender route.
|
||||
- Channel messages decrypt a hop-by-hop routing chain from the payload.
|
||||
- Contact storage keeps the path length encoding in byte 32 and the raw path bytes in bytes 33-96.
|
||||
- **Direct messages**: Extract path from decrypted payload to trace sender route.
|
||||
- **Channel messages**: Decrypt hop-by-hop routing chain from payload; header includes `pathLength` metadata.
|
||||
- **Contact storage**: Path length in byte 32, raw path bytes in bytes 33-96, grouped by detected `pathHashByteWidth`.
|
||||
|
||||
### Example Contact Path Parsing
|
||||
### UI Hop Count Display
|
||||
|
||||
⚠️ **Important**: In screens like "Channel Message Path", prefer the actual decoded `pathBytes` hop count over `pathLength` metadata:
|
||||
|
||||
```dart
|
||||
// Mode 0 (1-byte): 3 hops = 3 bytes needed
|
||||
// [0x83, 0xA1, 0xB2, 0xC3] → hopCount=3, mode=0, path=[A1,B2,C3]
|
||||
// Preferred: use actual observed path length
|
||||
final effectiveHopCount = (pathBytes.length + width - 1) ~/ width;
|
||||
|
||||
// Mode 1 (2-byte): 3 hops = 6 bytes needed
|
||||
// [0xC3, 0xA1, 0xA2, 0xB1, 0xB2, 0xC1, 0xC2]
|
||||
// → hopCount=3, mode=1, path=[A1A2, B1B2, C1C2]
|
||||
// Avoid: using radio metadata directly
|
||||
// pathLength can diverge from decoded bytes and cause UI mismatches
|
||||
```
|
||||
|
||||
Example scenario:
|
||||
- Radio header reports `pathLength: 32`
|
||||
- Decoded path bytes: `[0xAB, 0xCD]` (2 bytes = 1 hop with width=2)
|
||||
- **Display**: "1 hop" (from pathBytes), NOT "32 hops" (from pathLength)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user