Skip to content

feat(mesh): implement multi-hop BLE mesh routing with GATT relay and end-to-end message delivery#8

Merged
fionan313 merged 13 commits intomainfrom
mesh
Mar 1, 2026
Merged

feat(mesh): implement multi-hop BLE mesh routing with GATT relay and end-to-end message delivery#8
fionan313 merged 13 commits intomainfrom
mesh

Conversation

@fionan313
Copy link
Copy Markdown
Owner

@fionan313 fionan313 commented Feb 27, 2026

Summary

This PR introduces core mesh networking capabilities to CrowdLink, enabling
decentralised message routing across multiple devices using BLE and WiFi Direct.

The mesh branch implements a custom multi-hop routing protocol allowing devices
to relay messages for one another, extending communication range beyond
point-to-point limitations. It integrates a probabilistic flood-routing engine
with GATT-based BLE relaying and WiFi Direct transport.


Key Changes

1. Mesh Routing Engine

  • Created MeshRoutingEngine to handle message processing, TTL management, and hop-count tracking
  • Implemented SeenMessageCache for duplicate message suppression
  • Added probabilistic relay logic (75% default) to balance network reach with battery/bandwidth efficiency

2. BLE Transport & GATT Relay

  • Implemented a custom GATT server in BleAdvertiser to receive and relay mesh packets
  • Developed MeshMessageSerialiser for binary serialisation of mesh packets within BLE MTU limits
  • Added RelayMessageDao and Room persistence for outbound relay queue management

3. Transport Integration

  • Integrated routing engine with DeviceRepositoryImpl as the central orchestration point
  • Added WiFi Direct as a high-bandwidth fallback transport
  • Implemented RelayNodeScanner for discovering dedicated ESP32 relay infrastructure

4. Lifecycle & Reliability

  • Refactored DiscoveryViewModel and MainActivity to auto-start mesh services on launch
  • Ensured BLE scanning and advertising persist when navigating away from the discovery screen
  • Updated Hilt AppModule to manage singleton lifecycles for routing and discovery components

5. UI & UX

  • Updated DiscoveryScreen to show real-time mesh status (scanning, advertising, relay connectivity)
  • Added visual indicators for nearby peers with signal strength and estimated distance

Testing Performed

  • Unit tests for SeenMessageCache and MeshMessageSerialiser
  • Two-device integration testing (Samsung Galaxy, Nothing Phone 2) verifying:
    • BLE device discovery and GATT server initialisation
    • MTU negotiation (498 bytes achieved)
    • End-to-end message delivery via mesh routing with hop-count tracking
    • Background persistence of BLE services during screen navigation
  • Confirmed probabilistic relay and TTL drop behaviour via Logcat analysis

Known Limitations

  • Sequential GATT write queue: only one message flushed per connection;
    full write queue deferred to follow-up PR
  • GATT error 133 (Android BLE stack instability) handled via connection
    cleanup but no automatic retry yet
  • WiFi Direct MAC randomisation on Android 10+ limits reliable peer
    identification; demoted to fallback transport

- Create `RelayDiscoveryScreen` and `RelayDiscoveryViewModel` to manage discovery, manual connection, and auto-connect settings for relay nodes
- Enhance `RelayNodeScanner` with improved scan filtering, batch result handling, and RSSI-based sorting of discovered relays
- Update `RelayNodeConnection` to handle GATT connection lifecycle, including UTF-8 message encoding and improved error logging
- Integrate relay status into `DiscoveryScreen` via a new `RelayStatusBanner` component
- Implement auto-connect logic using `SharedPreferences` to automatically link to the strongest discovered relay node
- Register `relay_discovery` route in `MainActivity` navigation graph
- Refactor `DiscoveryViewModel` to handle both peer discovery and relay scanning simultaneously
- Standardize Bluetooth permission handling across discovery components using `@SuppressLint("MissingPermission")`
- Rename `FriendDatabase` to `AppDatabase` and update related DI providers and tests
- Implement relay message queue functionality in `MessageRepository` and `RelayMessageDao`
- Update UI icons in `RelayDiscoveryScreen` and `DiscoveryScreen` for better visual status representation
- Upgrade Kotlin to `2.1.0` and Gradle to `9.2.1`
- Add Timber logging library dependency
- Configure `gradle.properties` and `settings.gradle.kts` with updated build features and repository management
- Add resource packaging exclusion for OSGI manifest to improve build compatibility
- Introduce `MeshRoutingEngine` to handle message delivery, TTL-based filtering, and probabilistic relaying (75% forward rate)
- Implement `MeshMessageSerialiser` for converting mesh messages to/from a compact 512-byte BLE-compatible binary format
- Add `SeenMessageCache` using an LRU-based `LinkedHashSet` to prevent redundant message processing and circular relaying
- Define `MeshMessage` domain model and `RelayMessageEntity` for persistent storage of messages in transit
- Rename `FriendDatabase` to `AppDatabase` and update to version 8, adding `RelayMessageDao` and support for mesh message persistence
- Implement `MeshRoutingEngineTest` to verify local delivery, duplicate suppression, and TTL decrementing logic
- Add `RelayMessageDao` to manage the active relay queue, including expiration purging and message lifecycle methods
- Update `BleAdvertiser` to initialize and manage a `BluetoothGattServer` alongside BLE advertising
- Configure advertising settings to `setConnectable(true)` to support mesh relay write requests
- Implement `Mesh_CHARACTERISTIC_UUID` with write permissions to receive incoming mesh messages
- Integrate `MeshRoutingEngine` and `MeshMessageSerialiser` into `BleAdvertiser` to process received data
- Refactor logging in `BleAdvertiser` to use `Timber` and standardize Bluetooth permission handling
- Add `MeshMessageSerialiser` for converting `MeshMessage` objects to/from byte arrays with 16-byte fixed-length ID fields
- Add `MeshMessageSerialiserTest` to verify serialization round-trips, payload limits, and ID truncation logic
- Update current version to `v0.6.0-alpha` and project completion to ~55%
- Move Friend Pairing and WiFi Direct Messaging from "Planned" to "Current" features
- Update project architecture and directory structure to include WiFi Direct (`p2p`), QR pairing, and chat components
- Refresh test metrics: unit test pass rate increased to 95% and core domain coverage to 82%
- Update hardware and permission requirements to include WiFi Direct and QR scanning
- Increase "Lines of Code" metric to ~1200 and resolve distance estimation known issue status
…utingEngine, serialiser, persistence layer and simulation tests
… support

- Relocate `MeshMessageSerialiser`, `SeenMessageCache`, and `MeshRoutingEngine` from `com.fyp.crowdlink.data.mesh` to `com.fyp.crowdlink.data.mesh_backup`
- Update `AndroidManifest.xml` to include `android.support.LARGE_PAGE_SIZE` meta-data for Android 15+ compatibility
- Implement `MeshRoutingEngine` integration in `BleAdvertiser` and `BleScanner` to support gossip-based message delivery
- Enhance `BleAdvertiser` to manage a GATT server with a writable mesh characteristic for receiving relay packets
- Update `BleScanner` to handle GATT client connections, allowing it to write mesh messages to discovered peers and manage a retry queue
- Refactor `MessageViewModel` to use `MeshRoutingEngine` for outbound messages, enabling multi-hop delivery instead of direct P2P only
- Migrate persistent device ID management to `UserProfileRepository` and update `PairingViewModel` to use the new repository method
- Implement `relayToAllPeers` logic in `BleScanner` to broadcast mesh messages to all active GATT connections
- Update `AppModule` to provide Hilt dependencies for `MeshRoutingEngine`, `MeshMessageSerialiser`, and `SeenMessageCache`
- Standardize logging across BLE components using `android.util.Log` and improve error handling for advertising failures
- Fix GATT service UUIDs and characteristic properties to ensure reliable discovery and write operations
… transports

- Update `MessageViewModel` to use `MeshRoutingEngine` as the primary messaging path, adding support for BLE discovery and a combined discovery status UI
- Enhance `WifiDirectManager` to observe the global relay queue and attempt message delivery via WiFi P2P when peers are connected
- Update `RelayNodeConnection` to monitor the relay queue and automatically forward pending messages via connected ESP32 relay nodes
- Refactor `ChatScreen` UI with a new discovery status banner, message status icons (Pending, Sent, Delivered), and a "High-Speed" peer connection overlay for WiFi Direct
- Extend `Message` model with `transportType` and `hopCount` fields for better mesh network visibility
- Update `AppDatabase` to version 9 to support updated message schema
- Implement `MESH_RELAY_V1` protocol header in `WifiDirectManager` for structured mesh message exchange over socket connections
- Migrate `MeshMessageSerialiser`, `MeshRoutingEngine`, and `SeenMessageCache` to the core mesh package
- Update `MeshMessageSerialiser` with increased header size (100 bytes) and device ID size (36 bytes) to accommodate standard UUID strings - This is what caused me so much pain 🫩
- Enhance `MeshRoutingEngine` with `suspend` processing and local device ID verification to correctly identify messages intended for the current node
- Refactor `BleScanner` to handle MTU updates (512 bytes), manage active GATT connections, and implement a relay queue observer
- Update `BleAdvertiser` to process incoming GATT write requests asynchronously via the mesh routing engine
- Implement mesh callback wiring in `DeviceRepositoryImpl` to handle incoming messages and automated relaying
- Update `MainActivity` to automatically start mesh services (discovery and advertising) upon permission grant
- Refactor `DiscoveryViewModel` to track and expose discovery/advertising states as `StateFlow`
- Update `ChatScreen` to display message hop counts for multi-hop mesh transmissions
- Add `generativeai` dependency and update Android Gradle Plugin to v8.13.2
- Initialize `Timber` logging in `CrowdLinkApplication` and provide missing mesh components in `AppModule`
@fionan313 fionan313 changed the title mesh feat(mesh): implement multi-hop BLE mesh routing with GATT relay and end-to-end message delivery Feb 28, 2026
@fionan313 fionan313 linked an issue Feb 28, 2026 that may be closed by this pull request
7 tasks
- Refactor `MainActivity` by extracting the navigation logic into a new `MainScreen` and `AppNavHost` in `NavGraph.kt`
- Implement a `BottomNavigationBar` in `MainScreen` for top-level destinations (Discovery, Friends, Settings)
- Introduce `TransportType` enum to the `Message` model and replace the string-based transport field
- Update `WifiDirectManager`, `DeviceRepositoryImpl`, and `MessageViewModel` to use the new `TransportType` (WIFI, MESH, etc.)
- Add `relayNodes` field to the `Message` model and increment `AppDatabase` version to 10
- Force QR scanner activity to portrait orientation in `AndroidManifest.xml` and update `QRScannerScreen` configuration
- Add `androidx.compose.material.icons.extended` dependency for additional UI icons
- Scaffold new `CompassScreen` and `CompassViewModel` components
- Fix `RelayNodeScanner` by adding missing Bluetooth permission annotations
- Update unit and instrumented tests to reflect `Message` model changes and transport types
- Implement real-time synchronization of BLE discovery events to update `lastSeen` timestamps in the `friendRepository`
- Update `MeshRoutingEngine` message processing to refresh friend `lastSeen` metadata upon receiving incoming messages
- Refactor `DeviceRepositoryImpl` to streamline the discovery pipeline and reduce boilerplate logging
- Simplify member function declarations in `DeviceRepositoryImpl` using expression body syntax
- Maintain `lastSeen` persistence for paired friends during active scanning and message reception
@fionan313 fionan313 added the enhancement New feature or request label Mar 1, 2026
@fionan313 fionan313 self-assigned this Mar 1, 2026
- Remove deprecated backup mesh networking test suites including `MeshMessageSerialiserTest`, `MeshNetworkSimulationTest`, and `MeshRoutingEngineTest`
- Add `@SuppressLint("MissingPermission")` to `RelayNodeScanner` to suppress a lint false positive in the BLE batch scan callback
@fionan313 fionan313 merged commit 39671e9 into main Mar 1, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Implement BLE Mesh Networking with Store-and-Forward

1 participant