Skip to content

Commit 2fa86cb

Browse files
committed
fix a windows specific issue where the wait_for_user_program_stop function doesn't detect the hub being turned off properly
1 parent 476a1cd commit 2fa86cb

File tree

2 files changed

+40
-28
lines changed

2 files changed

+40
-28
lines changed

pybricksdev/cli/__init__.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -268,16 +268,18 @@ async def reconnect_hub():
268268
]
269269
while True:
270270
try:
271-
response = await hub.race_power_button_press(
272-
questionary.select(
273-
"Would you like to re-compile your code?",
274-
response_options,
275-
default=(
276-
response_options[0]
277-
if args.start
278-
else response_options[1]
279-
),
280-
).ask_async()
271+
response = await hub.race_disconnect(
272+
hub.race_power_button_press(
273+
questionary.select(
274+
"Would you like to re-compile your code?",
275+
response_options,
276+
default=(
277+
response_options[0]
278+
if args.start
279+
else response_options[1]
280+
),
281+
).ask_async()
282+
)
281283
)
282284
with _get_script_path(args.file) as script_path:
283285
if response == response_options[0]:
@@ -292,10 +294,22 @@ async def reconnect_hub():
292294
# current program, so the menu was canceled and we are now printing
293295
# the hub stdout until the user program ends on the hub.
294296
try:
295-
await hub._wait_for_user_program_stop(5)
297+
await hub._wait_for_user_program_stop(
298+
2.25, raise_error_on_timeout=True
299+
)
300+
296301
except HubDisconnectError:
297302
hub = await reconnect_hub()
298303

304+
except asyncio.TimeoutError:
305+
# On windows, it takes significantly longer
306+
# for the device to register that the hub was
307+
# disconnected. If _wait_for_user_program_stop
308+
# throws a timeout error, we can assume that the
309+
# hub was disconnected.
310+
await hub.disconnect()
311+
hub = await reconnect_hub()
312+
299313
except HubDisconnectError:
300314
# let terminal cool off before making a new prompt
301315
await asyncio.sleep(0.3)

pybricksdev/connections/pybricks.py

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -717,24 +717,20 @@ async def race_power_button_press(self, awaitable: Awaitable[T]) -> T:
717717
power_button_press_event = asyncio.Event()
718718
power_button_press_task = asyncio.ensure_future(power_button_press_event.wait())
719719

720-
disconnect_event = asyncio.Event()
721-
disconnect_task = asyncio.ensure_future(disconnect_event.wait())
722-
723-
def handle_disconnect(state: ConnectionState):
724-
if state == ConnectionState.DISCONNECTED:
725-
disconnect_event.set()
726-
727720
def handle_power_button_press(status: StatusFlag):
728721
if status.value & StatusFlag.POWER_BUTTON_PRESSED:
729722
power_button_press_event.set()
730723

731-
with self.status_observable.subscribe(
732-
handle_power_button_press
733-
), self.connection_state_observable.subscribe(handle_disconnect):
734-
done, pending = await asyncio.wait(
735-
{awaitable_task, power_button_press_task, disconnect_task},
736-
return_when=asyncio.FIRST_COMPLETED,
737-
)
724+
with self.status_observable.subscribe(handle_power_button_press):
725+
try:
726+
done, pending = await asyncio.wait(
727+
{awaitable_task, power_button_press_task},
728+
return_when=asyncio.FIRST_COMPLETED,
729+
)
730+
except BaseException:
731+
awaitable_task.cancel()
732+
power_button_press_task.cancel()
733+
raise
738734

739735
for t in pending:
740736
t.cancel()
@@ -743,11 +739,11 @@ def handle_power_button_press(status: StatusFlag):
743739
raise HubPowerButtonPressedError(
744740
"the hub's power button was pressed during operation"
745741
)
746-
if disconnect_task in done:
747-
raise HubDisconnectError("the hub was disconnected during operation")
748742
return awaitable_task.result()
749743

750-
async def _wait_for_user_program_stop(self, program_start_timeout=1):
744+
async def _wait_for_user_program_stop(
745+
self, program_start_timeout=1, raise_error_on_timeout=False
746+
):
751747
user_program_running: asyncio.Queue[bool] = asyncio.Queue()
752748

753749
with self.status_observable.pipe(
@@ -768,6 +764,8 @@ async def _wait_for_user_program_stop(self, program_start_timeout=1):
768764
program_start_timeout,
769765
)
770766
except asyncio.TimeoutError:
767+
if raise_error_on_timeout:
768+
raise
771769
# if it doesn't start, assume it was a very short lived
772770
# program and we just missed the status message
773771
logger.debug(

0 commit comments

Comments
 (0)