← index #6796PR #472
Related · medium · value 1.338
QUERY · ISSUE

extmod/bluetooth: handling of disconnect in ble_simple_central.py example is misleading

openby tveopened 2021-01-25updated 2021-01-25

The handling of the disconnect event in ble_simple_central.py is misleading. The condition if conn_handle == self._conn_handle:
(line 108) makes it look as if a different value for conn_handle would mean that there's nothing to do, but this is not the case. In particular, a disconnect can happen during the connection process, at least with nimble on the esp32, in which case self._conn_handle is still None and conn_handle != self._conn_handle but calling self._reset() is necessary.

https://github.com/micropython/micropython/blob/203e1d2a65273db3f6ff063ba1124a89c3482c0f/examples/bluetooth/ble_simple_central.py#L108

CANDIDATE · PULL REQUEST

aioble: Use DeviceDisconnectedError for disconnected guards.

openby andrewleechopened 2021-12-07updated 2026-03-24

Summary

When a BLE peer disconnects during L2CAP operations, callers get a mix of ValueError("Not connected"), bare L2CAPDisconnectedError(Exception), and OSError: [Errno 22] EINVAL depending on exactly which code path detects the disconnection first. Application code that catches DeviceDisconnectedError for clean disconnect handling (as the l2cap_file_server example does) misses all three.

This PR unifies the disconnect signalling:

  • L2CAPDisconnectedError becomes a subclass of DeviceDisconnectedError, so except DeviceDisconnectedError catches mid-operation L2CAP disconnections.
  • ValueError("Not connected") guards in L2CAPChannel.__init__, DeviceConnection.exchange_mtu, and Characteristic.indicate are replaced with the appropriate DeviceDisconnectedError (or subclass).
  • OSError(EINVAL) from the low-level ble.l2cap_send(), ble.l2cap_recvinto(), and ble.l2cap_disconnect() calls is caught and converted to L2CAPDisconnectedError. The BLE stack returns EINVAL when the connection handle or CID is no longer valid — semantically identical to a disconnection but previously not converted. disconnect() additionally sets _cid = None and returns cleanly since the channel is already gone.

Testing

Tested on STM32WB55 with an OTS (Object Transfer Service) file transfer interrupted by client disconnect. Before: three OSError: [Errno 22] EINVAL ERROR tracebacks per disconnect cycle. After: single INFO log "Transfer incomplete due to client disconnect".

Trade-offs and Alternatives

Could catch all OSError rather than checking errno == EINVAL specifically, but EINVAL is the only errno observed for this failure mode and catching broadly could mask real errors (e.g. ENOMEM).

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied