Skip to content

Commit 383ef08

Browse files
committed
connections.pybricks: implement USB SUBSCRIBE
Implement the USB SUBSCRIBE mechanism that is part of the Pybricks USB protocol. This is how hubs know if there is a Pybricks app ready to service requests.
1 parent f59513c commit 383ef08

File tree

1 file changed

+17
-11
lines changed

1 file changed

+17
-11
lines changed

pybricksdev/connections/pybricks.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -866,9 +866,24 @@ async def _client_connect(self) -> bool:
866866
return True
867867

868868
async def _client_disconnect(self) -> bool:
869+
await self._send_message(bytes([PybricksUsbOutEpMessageType.SUBSCRIBE, 0]))
869870
self._monitor_task.cancel()
870871
self._handle_disconnect()
871872

873+
async def _send_message(self, msg: bytes) -> None:
874+
# REVISIT: technically, this is blocking, but pyusb doesn't support asyncio
875+
self._ep_out.write(msg)
876+
877+
# FIXME: This needs to race with hub disconnect, and could also use a
878+
# timeout, otherwise it blocks forever. Pyusb doesn't currently seem to
879+
# have any disconnect callback.
880+
reply = await self._response_queue.get()
881+
882+
# REVISIT: could look up status error code and convert to string,
883+
# although BLE doesn't do that either.
884+
if int.from_bytes(reply[:4], "little") != 0:
885+
raise RuntimeError(f"Write failed: {reply[0]}")
886+
872887
async def read_gatt_char(self, uuid: str) -> bytearray:
873888
# Most stuff is available via other properties due to reading BOS
874889
# descriptor during connect.
@@ -881,19 +896,10 @@ async def write_gatt_char(self, uuid: str, data, response: bool) -> None:
881896
if not response:
882897
raise ValueError("Response is required for USB")
883898

884-
self._ep_out.write(bytes([PybricksUsbOutEpMessageType.COMMAND]) + data)
885-
# FIXME: This needs to race with hub disconnect, and could also use a
886-
# timeout, otherwise it blocks forever. Pyusb doesn't currently seem to
887-
# have any disconnect callback.
888-
reply = await self._response_queue.get()
889-
890-
# REVISIT: could look up status error code and convert to string,
891-
# although BLE doesn't do that either.
892-
if int.from_bytes(reply[:4], "little") != 0:
893-
raise RuntimeError(f"Write failed: {reply[0]}")
899+
await self._send_message(bytes([PybricksUsbOutEpMessageType.COMMAND]) + data)
894900

895901
async def start_notify(self, uuid: str, callback: Callable) -> None:
896-
# TODO: need to send subscribe message over USB
902+
await self._send_message(bytes([PybricksUsbOutEpMessageType.SUBSCRIBE, 1]))
897903
self._notify_callbacks[uuid] = callback
898904

899905
async def _monitor_usb(self):

0 commit comments

Comments
 (0)