Skip to content

Add Support for Multi-Byte Routing Paths#450

Open
PacoX wants to merge 8 commits into
zjs81:devfrom
PacoX:dev
Open

Add Support for Multi-Byte Routing Paths#450
PacoX wants to merge 8 commits into
zjs81:devfrom
PacoX:dev

Conversation

@PacoX
Copy link
Copy Markdown

@PacoX PacoX commented May 13, 2026

This PR adds support for variable-length multi-byte routing paths in MeshCore Open.
The implementation is inspired by the meshcore-py project.
Capture d’écran du 2026-05-13 09-10-16
Capture d’écran du 2026-05-13 09-13-06

Copilot AI review requested due to automatic review settings May 13, 2026 07:14
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds variable-length, multi-byte routing-path support across the UI and path utilities so routing can scale beyond single-byte hop IDs, with documentation and tests to describe/validate the new behavior.

Changes:

  • Introduces hop-aware path utilities (splitPathBytes, formatHopHex) and updates name resolution to support multi-byte hop prefixes.
  • Updates path-related UI (custom path entry, path details, path trace/map views) to respect the device-reported pathHashByteWidth.
  • Adds documentation for routing path encoding/capability detection and expands unit tests for path parsing/name resolution.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
windows/flutter/generated_plugins.cmake Adds jni to the Windows FFI plugin list.
linux/flutter/generated_plugins.cmake Adds jni to the Linux FFI plugin list.
lib/helpers/path_helper.dart Adds multi-byte hop formatting/splitting and updates resolvePathNames to be width-aware.
test/helpers/path_helper_test.dart Adds tests for hop-splitting and multi-byte path name resolution.
lib/widgets/path_selection_dialog.dart Updates custom path entry/selection UI to parse and display hop prefixes using the configured hash width.
lib/widgets/path_management_dialog.dart Passes pathHashByteWidth into path name resolution and the selection dialog.
lib/screens/chat_screen.dart Uses width-aware path name resolution when showing full path details.
lib/screens/channel_message_path_screen.dart Converts observed/reported path byte lengths into hop counts based on hash width; updates path display formatting accordingly.
lib/screens/path_trace_map.dart Refactors path trace parsing/matching/labeling to handle multi-byte hop prefixes.
lib/services/notification_service.dart Sanitizes notification identifiers/device-info logging strings for safer debug output.
documentation/routing-paths.md New documentation describing multi-byte routing path encoding and UI/display conventions.
documentation/README.md Adds the new “Routing Paths” documentation link.
documentation/chat-and-messaging.md Documents multi-byte custom path entry format in the Chat UI.
Comments suppressed due to low confidence (2)

lib/screens/path_trace_map.dart:870

  • formatDirectionSubText() can be called with index == pathTraceData.pathData.length (the ListView uses itemCount: pathData.length + 1). In that case, the else-branch reads pathData[index], which will throw a RangeError and crash for any non-empty trace. Handle the last UI row explicitly (e.g., treat index == pathData.length as the final “you” endpoint) or adjust indexing so pathData[index] is never out of bounds.
    } else {
      final hop = pathTraceData.pathData[index];
      final contactName = pathTraceData.pathContacts[_hopKey(hop)]?.name;
      final hex = PathHelper.formatHopHex(hop);
      return contactName != null

lib/screens/path_trace_map.dart:445

  • Target inference compares the selected hop key to c.path.last (single byte). With multi-byte paths this breaks matching and prevents inferring the target location from peers. Use the last hop chunk (width bytes) from c.path when building the comparison key.
                  (c) =>
                      c.hasLocation &&
                      c.path.isNotEmpty &&
                      _hopKey(Uint8List.fromList([c.path.last])) == lastHopKey,

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/screens/path_trace_map.dart Outdated
}
}
return traceBytes;
mirroredHops.addAll(pathHops.reversed);
Comment thread lib/screens/path_trace_map.dart Outdated
Comment on lines +398 to +399
c.path.isNotEmpty &&
_hopKey(Uint8List.fromList([c.path.last])) == hopKey,
Comment thread documentation/routing-paths.md Outdated
Comment on lines +26 to +30
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
Comment on lines +13 to +17
| 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 |
@PacoX PacoX marked this pull request as draft May 13, 2026 07:29
@PacoX PacoX marked this pull request as ready for review May 13, 2026 08:44
Copilot AI review requested due to automatic review settings May 13, 2026 08:44
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Comment on lines 127 to 131
final pathBytesList = <int>[];
final invalidPrefixes = <String>[];
final hexCharsPerHop = widget.pathHashByteWidth.clamp(1, 8) * 2;

for (final id in pathIds) {
Comment thread lib/services/notification_service.dart Outdated
AppLocalizations get _l10n => lookupAppLocalizations(_locale);

String _logSafe(String value) {
return Uri.encodeComponent(value.replaceAll('\n', ' '));
Comment thread documentation/routing-paths.md Outdated
Comment on lines +36 to +40
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:
previousPosition = resolvedPosition;
}

// If the best candidate is much farther than the previous hop, it's likely not the correct match.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to ask if you could remove this filter, because introduces a lot of problems and you are editing this part already?
The closest candidate gets thrown away if next hop is further than 50km away and then it can have a cascading effect. Whereas this scenario is possible, for example I have the repeater "Sonnenberg AG/BL" with direct contact to "Transalp N1" 110km away one direction, and from there i could have about the same amount of distance, cumulating to over 200km.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants