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.
This commit is contained in:
torlando-tech 2025-11-04 00:09:11 -05:00
commit 77debfab8b

View file

@ -1017,7 +1017,7 @@ class LinuxBluetoothDriver(BLEDriverInterface):
result = future.result(timeout=5.0)
return bytes(result)
except Exception as e:
self._log(f"Error reading characteristic {char_uuid} from {address}: {e}", "ERROR")
self._log(f"Error reading characteristic {char_uuid} from {address}: {type(e).__name__}: {e}", "ERROR")
raise
def write_characteristic(self, address: str, char_uuid: str, data: bytes):
@ -1203,10 +1203,10 @@ class BluezeroGATTServer:
self.adapter_index = adapter_index
self.agent_capability = agent_capability
# State
self.running = False
# bluezero objects
self.peripheral_obj = None
self.tx_characteristic = None
self.identity_characteristic = None
# Identity
self.identity_bytes: Optional[bytes] = None
@ -1233,6 +1233,10 @@ class BluezeroGATTServer:
raise ValueError("Identity must be 16 bytes")
self.identity_bytes = identity_bytes
# Proactively update the characteristic value if it already exists
if self.identity_characteristic:
self.identity_characteristic.set_value(list(self.identity_bytes))
self._log(f"Identity set: {identity_bytes.hex()}")
def start(self, device_name: str):
@ -1368,16 +1372,16 @@ class BluezeroGATTServer:
self._log(f"Added TX characteristic: {self.tx_char_uuid}", "DEBUG")
# Add Identity characteristic (centrals read our identity)
identity_value = list(self.identity_bytes) if self.identity_bytes else []
self.peripheral_obj.add_characteristic(
srv_id=1,
chr_id=3,
uuid=self.identity_char_uuid,
value=identity_value,
value=[0]*16, # Initialize with 16-byte placeholder
notifying=False,
flags=['read'],
read_callback=self._handle_read_identity
)
self.identity_characteristic = self.peripheral_obj.characteristics[-1]
self._log(f"Added Identity characteristic: {self.identity_char_uuid}", "DEBUG")
# Save TX characteristic reference