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.
This commit is contained in:
parent
38ebd17008
commit
f3cafedb60
3 changed files with 53 additions and 22 deletions
|
|
@ -646,37 +646,48 @@ class BLEInterface(Interface):
|
|||
Called when driver has established a connection. We read the identity
|
||||
characteristic and prepare to receive data.
|
||||
"""
|
||||
RNS.log(f"{self} connected to {address}, reading identity...", RNS.LOG_INFO)
|
||||
# Check connection role to determine identity exchange method
|
||||
role = self.driver.get_peer_role(address)
|
||||
|
||||
# Read identity characteristic
|
||||
try:
|
||||
identity_bytes = self.driver.read_characteristic(
|
||||
address,
|
||||
BLEInterface.CHARACTERISTIC_IDENTITY_UUID
|
||||
)
|
||||
if role == "central":
|
||||
# We are the central, we must read the peer's identity
|
||||
RNS.log(f"{self} connected to {address} as CENTRAL, reading identity...", RNS.LOG_INFO)
|
||||
try:
|
||||
identity_bytes = self.driver.read_characteristic(
|
||||
address,
|
||||
BLEInterface.CHARACTERISTIC_IDENTITY_UUID
|
||||
)
|
||||
|
||||
if identity_bytes and len(identity_bytes) == 16:
|
||||
peer_identity = bytes(identity_bytes)
|
||||
identity_hash = self._compute_identity_hash(peer_identity)
|
||||
if identity_bytes and len(identity_bytes) == 16:
|
||||
peer_identity = bytes(identity_bytes)
|
||||
identity_hash = self._compute_identity_hash(peer_identity)
|
||||
|
||||
# Store identity mappings
|
||||
self.address_to_identity[address] = peer_identity
|
||||
self.identity_to_address[identity_hash] = address
|
||||
# Store identity mappings
|
||||
self.address_to_identity[address] = peer_identity
|
||||
self.identity_to_address[identity_hash] = address
|
||||
|
||||
RNS.log(f"{self} received peer identity from {address}: {identity_hash}", RNS.LOG_INFO)
|
||||
RNS.log(f"{self} received peer identity from {address}: {identity_hash}", RNS.LOG_INFO)
|
||||
self._record_connection_success(address)
|
||||
else:
|
||||
RNS.log(f"{self} invalid identity from {address}, disconnecting", RNS.LOG_WARNING)
|
||||
self.driver.disconnect(address)
|
||||
self._record_connection_failure(address)
|
||||
|
||||
# Record successful connection
|
||||
self._record_connection_success(address)
|
||||
|
||||
else:
|
||||
RNS.log(f"{self} invalid identity from {address}, disconnecting", RNS.LOG_WARNING)
|
||||
except Exception as e:
|
||||
RNS.log(f"{self} failed to read identity from {address}: {e}", RNS.LOG_ERROR)
|
||||
self.driver.disconnect(address)
|
||||
self._record_connection_failure(address)
|
||||
|
||||
except Exception as e:
|
||||
RNS.log(f"{self} failed to read identity from {address}: {e}", RNS.LOG_ERROR)
|
||||
elif role == "peripheral":
|
||||
# We are the peripheral, we must wait for the central to send its identity
|
||||
RNS.log(f"{self} connected to {address} as PERIPHERAL, waiting for identity handshake...", RNS.LOG_INFO)
|
||||
# The identity will be received in `handle_peripheral_data` or `_data_received_callback`
|
||||
# No action is needed here.
|
||||
pass
|
||||
|
||||
else:
|
||||
RNS.log(f"{self} connected to {address}, but role is unknown. Disconnecting.", RNS.LOG_WARNING)
|
||||
self.driver.disconnect(address)
|
||||
self._record_connection_failure(address)
|
||||
|
||||
def _mtu_negotiated_callback(self, address: str, mtu: int):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -181,6 +181,19 @@ class BLEDriverInterface(ABC):
|
|||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_peer_role(self, address: str) -> Optional[str]:
|
||||
"""
|
||||
Returns the connection role for a connected peer.
|
||||
|
||||
Args:
|
||||
address: The MAC address of the peer.
|
||||
|
||||
Returns:
|
||||
A string ('central' or 'peripheral') or None if not connected.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def set_service_discovery_delay(self, seconds: float):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1079,6 +1079,13 @@ class LinuxBluetoothDriver(BLEDriverInterface):
|
|||
"""Return local Bluetooth adapter MAC address."""
|
||||
return self.local_address or "00:00:00:00:00:00"
|
||||
|
||||
def get_peer_role(self, address: str) -> Optional[str]:
|
||||
"""Return the connection role ('central' or 'peripheral') for a peer."""
|
||||
with self._peers_lock:
|
||||
if address in self._peers:
|
||||
return self._peers[address].connection_type
|
||||
return None
|
||||
|
||||
def set_service_discovery_delay(self, seconds: float):
|
||||
"""Set delay between connection and service discovery."""
|
||||
self.service_discovery_delay = seconds
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue