Commit graph

8 commits

Author SHA1 Message Date
torlando-tech
b503718bf8 fix(ble): Remove device name from advertisements to fix packet size limit
Fixes "Failed to register advertisement" error (BlueZ error 0x03) caused by
device name exceeding 31-byte BLE advertisement packet limit.

Changes:
- Make device_name optional (default: None) to save advertisement space
- Remove auto-generation of long identity-based names (RNS-{32-hex-identity})
- Update driver to handle None device names when creating peripheral
- Use full 16-byte identity (32 hex chars) for fragmenter keys to avoid collisions
- Update documentation to reflect device name is optional and discovery is UUID-based

Discovery is based on service UUID matching only. Identity is obtained from
the Identity GATT characteristic after connection, not from device name.

Tested on Raspberry Pi Zero W with BlueZ 5.82 - advertisement now registers
successfully (ActiveInstances: 1).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 23:52:04 -05:00
torlando-tech
2a34efc5c5 fix(ble): Add get_peer_mtu method to LinuxBluetoothDriver
## Problem

The identity handshake handler called `self.driver.get_peer_mtu(address)`,
but this method didn't exist, causing:

```
[Error] BLEInterface[BLE Interface] failed to process identity handshake from dev:B8:27:EB:A8:A7:22: 'LinuxBluetoothDriver' object has no attribute 'get_peer_mtu'
```

## Solution

Added `get_peer_mtu(address)` method to LinuxBluetoothDriver that:

1. Checks central connections (self._peers) for MTU when we're the central
2. Checks peripheral connections (gatt_server.connected_centrals) for MTU when we're the peripheral
3. Returns None if peer not found in either

This mirrors the existing `get_peer_role()` pattern and provides
thread-safe access to MTU information for both connection types.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 01:04:03 -05:00
torlando-tech
d1d94e5252 fix(ble): Pass peer identity via callback to eliminate redundant read
## Problem

The central device was timing out when trying to read the identity
characteristic from peripheral devices, causing connection failures:

```
ERROR: Error reading characteristic ...28e6 from B8:27:EB:10:28:CD: TimeoutError
```

Root cause: The driver already reads the identity during connection setup
(line 806 in _connect_to_peer), but then BLEInterface tried to read it
AGAIN in _device_connected_callback. The second read consistently timed
out, likely due to BlueZ/D-Bus caching issues or characteristic state.

## Solution

Changed the `on_device_connected` callback signature to pass the peer
identity directly, following the established pattern of other callbacks
like `on_data_received(address, data)` and `on_mtu_negotiated(address, mtu)`.

### Changes

1. **Driver Interface** (bluetooth_driver.py)
   - Updated callback: `on_device_connected(str, Optional[bytes])`
   - Identity is None for peripheral connections (arrives via handshake)

2. **PeerConnection** (linux_bluetooth_driver.py)
   - Added `peer_identity: Optional[bytes]` field
   - Store identity read during connection setup

3. **Connection Flow** (linux_bluetooth_driver.py)
   - Central: Pass identity to callback after reading it
   - Peripheral: Pass None (identity comes later via handshake)

4. **BLEInterface** (BLEInterface.py)
   - Updated callback signature to accept peer_identity parameter
   - Removed buggy `read_characteristic()` call
   - Use passed identity directly for central connections
   - Added typing.Optional import

## Benefits

-  Eliminates redundant GATT read operation
-  Fixes timeout bug for central connections
-  More efficient: reuses identity already read by driver
-  Cleaner architecture: follows callback pattern consistency
-  Explicit about identity availability by connection role

## Testing

Tested on Raspberry Pi Zero W devices with BlueZ 5.82:
- Central connections now receive identity immediately
- Peripheral connections correctly wait for handshake
- No more timeout errors

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 00:50:42 -05:00
torlando-tech
98025e8600 enforce id char 2025-11-04 00:35:06 -05:00
torlando-tech
e9f62ab28e fix missing prop 2025-11-04 00:19:12 -05:00
torlando-tech
9ce0e920c3 fix(ble): Harden peripheral identity characteristic handling
This commit addresses a timeout issue where a central device would fail
to read the identity characteristic from the peripheral.

The root cause is suspected to be a race condition in the underlying
BlueZ/D-Bus stack, where the `read_callback` for the characteristic
was not firing reliably, causing the central's read request to hang
and time out.

To make this process more robust and less dependent on timing, the
GATT server implementation has been hardened:

1.  The identity characteristic is now initialized with a 16-byte
    placeholder value. This ensures the D-Bus object is created with
    the correct data length from the start.

2.  When the asynchronous RNS identity becomes available, the server now
    proactively pushes the identity to the characteristic using
    `set_value()`. This no longer relies exclusively on the fragile
    `read_callback` mechanism.

Additionally, error logging within the driver has been improved to
include the exception type, aiding future diagnostics.
2025-11-04 00:09:11 -05:00
torlando-tech
67eb2ef0c2 fix(ble): Resolve connection role and startup errors
This commit addresses two critical issues that prevented the BLE
interface from functioning correctly after the driver abstraction
refactor.

1.  **Fix `exec()` Startup Error:**
    The interface failed to load via `rnsd` due to a `KeyError: '__name__'`
    caused by using relative imports (`from . import ...`). The `exec()`
    environment used by Reticulum does not preserve package context,
    breaking these imports. This is fixed by reverting to absolute
    imports (`from bluetooth_driver import ...`) which work correctly
    with the existing `sys.path` manipulation logic.

2.  **Fix Connection Role Logic:**
    Connections were failing because the interface would always attempt
    to read the peer's identity, even when acting as the peripheral.
    This caused a `Can only read characteristics in central mode` error.

    The fix introduces role-aware logic into the connection callback:
    - A `get_peer_role()` method was added to the driver interface.
    - `BLEInterface` now checks the role on connection.
    - If central, it reads the identity characteristic.
    - If peripheral, it waits for the identity handshake packet,
      preventing the invalid operation.
2025-11-03 23:43:30 -05:00
torlando-tech
4eaa9a4173 Refactor BLEInterface to driver-based architecture
Major architectural refactoring to separate high-level Reticulum protocol
logic from platform-specific Bluetooth operations. This enables code sharing
between pure Python and Android (Columba) implementations, improves
testability, and creates a clean boundary for future platform support.

ARCHITECTURE CHANGES:

1. **Driver Abstraction Layer**
   - Created BLEDriverInterface (bluetooth_driver.py) defining the contract
     for all platform-specific BLE drivers
   - Abstraction includes 18 methods + 6 callbacks for complete BLE lifecycle
   - Enhanced BLEDevice dataclass with service_uuids and manufacturer_data
   - Added on_mtu_negotiated callback for delayed MTU reporting
   - Added on_error callback for consistent platform error reporting

2. **Linux Driver Implementation**
   - Created LinuxBluetoothDriver (linux_bluetooth_driver.py, 1534 lines)
   - Moved ALL bleak/bluezero/D-Bus code from BLEInterface
   - Preserves 5 critical platform workarounds:
     * BlueZ ServicesResolved race condition patch
     * D-Bus LE-only connection (ConnectDevice)
     * BLE Agent registration for Just Works pairing
     * MTU negotiation with 3-method fallback
     * Service discovery delay for bluezero timing
   - Role-aware send() automatically chooses GATT write vs notification
   - Dedicated asyncio event loop management in separate thread
   - Configuration via constructor (no Reticulum dependencies)

3. **Refactored BLEInterface**
   - Removed 801 lines (32.3% reduction: 2479 → 1678 lines)
   - Removed all platform-specific imports (bleak, bluezero, dbus_fast)
   - Removed 9 async methods (moved to driver)
   - Driver dependency injection via constructor
   - Implemented 6 driver callbacks for event handling
   - PRESERVED high-level logic:
     * Peer scoring algorithm (RSSI + history + recency)
     * Connection blacklist with exponential backoff
     * MAC-based connection direction (prevents dual connections)
     * Fragmentation/reassembly orchestration (identity-based keying)
     * Interface spawning per peer

4. **Simplified BLEPeerInterface**
   - Removed connection_type, client, mtu parameters
   - Deleted _send_via_central() and _send_via_peripheral() methods
   - Single send path via driver.send() (driver handles role routing)
   - 77 lines removed from peer interface class

5. **Mock Driver for Testing**
   - Created MockBLEDriver (tests/mock_ble_driver.py)
   - Complete BLEDriverInterface implementation without hardware
   - Bidirectional communication via link_drivers()
   - Enables unit testing of BLEInterface logic (fragmentation, reassembly,
     peer lifecycle, blacklist management)

CRITICAL FIXES:

1. **Restored Periodic Cleanup Task** (CRITICAL: prevents memory leaks)
   - Converted from async (driver-owned loop) to threading.Timer
   - Runs every 30 seconds to clean stale reassembly buffers
   - Essential for long-running instances (Pi Zero with 512MB RAM)
   - Properly cancelled in detach() for clean shutdown

2. **Fixed Naming Consistency**
   - Renamed processOutgoing → process_outgoing (snake_case)

FILES MODIFIED:
- src/RNS/Interfaces/BLEInterface.py (refactored, -801 lines)

FILES ADDED:
- bluetooth_driver.py (driver abstraction interface)
- linux_bluetooth_driver.py (Linux/BlueZ implementation, 1534 lines)
- tests/mock_ble_driver.py (mock driver for unit tests)
- REFACTORING_GUIDE.md (comprehensive refactoring documentation)
- BLE_PROTOCOL_v2.2.md (protocol specification)
- tests/test_refactor_suite.py (initial test suite)

BENEFITS:

1. **Testability** - Mock driver enables hardware-free unit testing
2. **Portability** - Easy to create Android/Windows/macOS drivers
3. **Maintainability** - Platform quirks isolated in single driver file
4. **Code Sharing** - High-level logic shared across all platforms
5. **Clean Architecture** - Clear separation of concerns

TESTING REQUIRED:

- Tier 1 (Unit): Test with MockBLEDriver (fragmentation, reassembly, lifecycle)
- Tier 2 (Integration): Test on Raspberry Pi hardware (scanning, connecting,
  dual mode, MTU negotiation, identity exchange)
- Tier 3 (Regression): Full Reticulum stack (announces, LXMF, multi-hop)
- Tier 4 (Edge Cases): MAC rotation, identity handshake, reconnection,
  reassembly timeout, discovery cache pruning

BACKWARD COMPATIBILITY:

- Configuration: Fully backward compatible (same config parameters)
- Protocol: No changes to BLE wire protocol (v2.2)
- Interface API: Unchanged for Reticulum Transport integration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 23:15:22 -05:00