Skip to content

Commit b567ed2

Browse files
committed
cli/flash: fix rebooting in update mode
Pybricks Profile v1.2.0 added a new reset command and changed how download and run works, so we can use the new command instead of downloading and running a reset program. Fixes: #43
1 parent 9f8527a commit b567ed2

File tree

3 files changed

+52
-6
lines changed

3 files changed

+52
-6
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
### Added
10+
- Added `pybricksdev.ble.pybricks.Command.PBIO_PYBRICKS_COMMAND_REBOOT_TO_UPDATE_MODE`.
11+
12+
### Fixed
13+
- Fixed reboot in update mode for Pybricks Profile >= 1.2.0 in `pybricksdev flash` CLI.
14+
915
## [1.0.0-alpha.33] - 2022-11-06
1016

1117
### Changed

pybricksdev/ble/pybricks.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,17 @@ class Command(IntEnum):
113113
.. availability:: Since Pybricks protocol v1.2.0.
114114
"""
115115

116+
PBIO_PYBRICKS_COMMAND_REBOOT_TO_UPDATE_MODE = 5
117+
"""
118+
Requests for the hub to reboot in firmware update mode.
119+
120+
If this command was successful, the hub will reboot immediately, which
121+
means the GATT write request will fail because Bluetooth became
122+
disconnected.
123+
124+
.. availability:: Since Pybricks protocol v1.2.0.
125+
"""
126+
116127

117128
class CommandError(IntEnum):
118129
"""

pybricksdev/cli/flash.py

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import hashlib
66
import json
77
import logging
8+
import struct
89
import sys
910
import zipfile
1011
from tempfile import NamedTemporaryFile
@@ -34,7 +35,10 @@
3435
from ..ble.pybricks import (
3536
FW_REV_UUID,
3637
PNP_ID_UUID,
38+
PYBRICKS_COMMAND_EVENT_UUID,
3739
PYBRICKS_SERVICE_UUID,
40+
SW_REV_UUID,
41+
Command,
3842
unpack_pnp_id,
3943
)
4044
from ..compile import compile_file
@@ -66,7 +70,7 @@ def match_hub(hub_kind: HubKind, adv: AdvertisementData) -> bool:
6670
6771
Args:
6872
hub_kind: The hub type ID to match.
69-
adv: The advertisemet data to check.
73+
adv: The advertisement data to check.
7074
7175
Returns:
7276
``True`` if *adv* matches the criteria, otherwise ``False``.
@@ -217,11 +221,36 @@ async def reboot_pybricks_to_bootloader(hub_kind: HubKind, device: BLEDevice) ->
217221

218222
print("Rebooting in update mode...")
219223

220-
# HACK: there isn't a proper way to get the MPY ABI version from hub
221-
# so we use heuristics on the firmware version
222-
abi = 6 if Version(fw_ver) >= Version("3.2.0b2") else 5
223-
224-
await download_and_run(client, REBOOT_SCRIPT, abi)
224+
profile_ver = await client.read_gatt_char(SW_REV_UUID)
225+
226+
if Version(profile_ver.decode()) >= Version("1.2.0"):
227+
try:
228+
await client.write_gatt_char(
229+
PYBRICKS_COMMAND_EVENT_UUID,
230+
struct.pack(
231+
"<B", Command.PBIO_PYBRICKS_COMMAND_REBOOT_TO_UPDATE_MODE
232+
),
233+
response=True,
234+
)
235+
# This causes the hub to become disconnected before completing
236+
# the write request, so we expect an exception here.
237+
except Exception:
238+
# REVISIT: Should probably check for more specific exception.
239+
# However, OK for now since code will just timeout later while
240+
# scanning for bootloader.
241+
pass
242+
else:
243+
raise RuntimeError("hub did not reset")
244+
245+
else:
246+
# older protocol doesn't support this command, so we have to
247+
# download and run a program
248+
249+
# HACK: there isn't a proper way to get the MPY ABI version from hub
250+
# so we use heuristics on the firmware version
251+
abi = 6 if Version(fw_ver) >= Version("3.2.0b2") else 5
252+
253+
await download_and_run(client, REBOOT_SCRIPT, abi)
225254

226255

227256
async def flash_ble(hub_kind: HubKind, firmware: bytes, metadata: dict):

0 commit comments

Comments
 (0)