fix(ble): Restore identity handshake detection for peripheral connections
## Problem After the driver refactor (commitd1d94e5), peripheral devices were dropping the identity handshake sent by central devices. The logs showed: ``` [Warning] BLEInterface[BLE Interface] no identity for dev:B8:27:EB:A8:A7:22, cannot create fragmenter [Warning] BLEInterface[BLE Interface] no identity for peer dev:B8:27:EB:A8:A7:22, dropping data ``` Root cause: When the central sends its 16-byte identity handshake, the peripheral's `_data_received_callback` passed it to `_handle_ble_data`, which immediately dropped it (chicken-and-egg: no identity = drop data, but the dropped data IS the identity). The handshake detection logic existed in commitbabb237but was lost during the driver architecture refactor. ## Solution Added `_handle_identity_handshake()` method that: 1. Detects identity handshakes (exactly 16 bytes, no existing identity) 2. Stores the central's identity in bidirectional mappings 3. Creates fragmenter/reassembler with negotiated MTU 4. Spawns peer interface for the central 5. Returns True to prevent normal data processing Updated `_data_received_callback()` to check for handshakes before passing data to normal reassembly logic. ## Benefits - ✅ Restores bidirectional communication for peripheral connections - ✅ Peripheral can learn central's identity without scanning - ✅ Clean separation of handshake vs. data processing - ✅ Proper error handling with informative logging ## Testing Should resolve the asymmetric identity exchange seen in Pi1/Pi2 logs where central successfully connected but peripheral couldn't create fragmenter. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
d1d94e5252
commit
88bb2fc3fa
1 changed files with 74 additions and 1 deletions
|
|
@ -738,12 +738,85 @@ class BLEInterface(Interface):
|
||||||
connection_type=connection_type
|
connection_type=connection_type
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _handle_identity_handshake(self, address: str, data: bytes) -> bool:
|
||||||
|
"""
|
||||||
|
Handle identity handshake from central device (peripheral role only).
|
||||||
|
|
||||||
|
When a central connects to us (we're peripheral), it sends exactly 16 bytes
|
||||||
|
as the first packet - its identity hash. This allows the peripheral to learn
|
||||||
|
the central's identity without requiring discovery/scanning.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
address: MAC address of the central device
|
||||||
|
data: Received data bytes
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if data was handled as identity handshake, False otherwise
|
||||||
|
"""
|
||||||
|
# Check if we already have peer identity
|
||||||
|
peer_identity = self.address_to_identity.get(address)
|
||||||
|
if peer_identity:
|
||||||
|
return False # Already have identity, not a handshake
|
||||||
|
|
||||||
|
# Identity handshake detection: exactly 16 bytes, no existing identity
|
||||||
|
if len(data) != 16:
|
||||||
|
return False # Not a handshake
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Store central's identity
|
||||||
|
central_identity = bytes(data)
|
||||||
|
identity_hash = self._compute_identity_hash(central_identity)
|
||||||
|
|
||||||
|
self.address_to_identity[address] = central_identity
|
||||||
|
self.identity_to_address[identity_hash] = address
|
||||||
|
|
||||||
|
RNS.log(f"{self} received identity handshake from {address}: {identity_hash}", RNS.LOG_INFO)
|
||||||
|
|
||||||
|
# Get MTU for this connection (should be negotiated by now)
|
||||||
|
mtu = self.driver.get_peer_mtu(address)
|
||||||
|
if not mtu:
|
||||||
|
mtu = 23 # BLE 4.0 minimum MTU
|
||||||
|
|
||||||
|
# Create fragmenter/reassembler
|
||||||
|
frag_key = self._get_fragmenter_key(central_identity, address)
|
||||||
|
|
||||||
|
with self.frag_lock:
|
||||||
|
self.fragmenters[frag_key] = BLEFragmenter(mtu=mtu)
|
||||||
|
if frag_key not in self.reassemblers:
|
||||||
|
self.reassemblers[frag_key] = BLEReassembler()
|
||||||
|
|
||||||
|
# Spawn peer interface if not already spawned
|
||||||
|
if identity_hash not in self.spawned_interfaces:
|
||||||
|
peer_name = f"Central-{address[-8:]}"
|
||||||
|
connection_type = "peripheral" # We're the peripheral
|
||||||
|
|
||||||
|
self._spawn_peer_interface(
|
||||||
|
address=address,
|
||||||
|
name=peer_name,
|
||||||
|
peer_identity=central_identity,
|
||||||
|
mtu=mtu,
|
||||||
|
connection_type=connection_type
|
||||||
|
)
|
||||||
|
|
||||||
|
RNS.log(f"{self} identity handshake complete for {address}", RNS.LOG_INFO)
|
||||||
|
return True # Handshake processed successfully
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
RNS.log(f"{self} failed to process identity handshake from {address}: {e}", RNS.LOG_ERROR)
|
||||||
|
return True # Still consumed the data, don't pass it on
|
||||||
|
|
||||||
def _data_received_callback(self, address: str, data: bytes):
|
def _data_received_callback(self, address: str, data: bytes):
|
||||||
"""
|
"""
|
||||||
Driver callback: Handle received data from peer.
|
Driver callback: Handle received data from peer.
|
||||||
|
|
||||||
Passes data to reassembly and routing logic.
|
First checks for identity handshake (peripheral role), then passes
|
||||||
|
normal data to reassembly and routing logic.
|
||||||
"""
|
"""
|
||||||
|
# Handle identity handshake if applicable
|
||||||
|
if self._handle_identity_handshake(address, data):
|
||||||
|
return # Handshake handled, done
|
||||||
|
|
||||||
|
# Normal data processing
|
||||||
self._handle_ble_data(address, data)
|
self._handle_ble_data(address, data)
|
||||||
|
|
||||||
def _device_disconnected_callback(self, address: str):
|
def _device_disconnected_callback(self, address: str):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue