Skip to content

Commit 6539875

Browse files
committed
repl_installer: read running firmware
1 parent 02a958c commit 6539875

File tree

1 file changed

+43
-1
lines changed

1 file changed

+43
-1
lines changed

pybricksdev/resources/install_pybricks.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
FLASH_LEGO_START = 0x8008000
1919
FLASH_PYBRICKS_START = 0x80C0000
2020

21+
BLOCK_READ_SIZE = 32
22+
BLOCK_WRITE_SIZE = BLOCK_READ_SIZE * 4
23+
2124
FF = b'\xFF'
2225

2326

@@ -31,6 +34,15 @@ def read_flash_int(address):
3134
return int.from_bytes(read_flash(address, 4), 'little')
3235

3336

37+
def get_pybricks_reset_vector():
38+
"""Gets the boot vector of the pybricks firmware."""
39+
40+
# Extract reset vector from dual boot firmware.
41+
with open("_pybricks/firmware.bin") as pybricks_bin_file:
42+
pybricks_bin_file.seek(4)
43+
return pybricks_bin_file.read(4)
44+
45+
3446
def get_lego_reset_vector():
3547
"""Gets the boot vector of the original firmware."""
3648

@@ -41,10 +53,37 @@ def get_lego_reset_vector():
4153
if int.from_bytes(reset_vector, 'little') < FLASH_PYBRICKS_START:
4254
return reset_vector
4355

44-
# Otherwise read the reset vector in Pybricks.
56+
# Otherwise read the reset vector in the dual-booted Pybricks that is
57+
# already installed, which points to the LEGO firmware.
4558
return read_flash(FLASH_PYBRICKS_START + 4, 4)
4659

4760

61+
def get_lego_firmware(size, reset_vector):
62+
"""Gets the LEGO firmware with an updated reset vector."""
63+
64+
bytes_read = 0
65+
66+
# Yield new blocks until done.
67+
while bytes_read < size:
68+
69+
# Read several chunks of 32 bytes into one block.
70+
block = b''
71+
for i in range(BLOCK_WRITE_SIZE // BLOCK_READ_SIZE):
72+
block += firmware.flash_read(bytes_read)
73+
bytes_read += BLOCK_READ_SIZE
74+
75+
# The first block is updated with the desired boot vector.
76+
if bytes_read == BLOCK_WRITE_SIZE:
77+
block = block[0:4] + reset_vector + block[8:]
78+
79+
# If we read past the end, cut off the extraneous bytes.
80+
if bytes_read > size:
81+
block = block[0: size % BLOCK_WRITE_SIZE]
82+
83+
# Yield the resulting block.
84+
yield block
85+
86+
4887
def install(pybricks_hash):
4988
"""Main installation routine."""
5089

@@ -85,3 +124,6 @@ def install(pybricks_hash):
85124
if FLASH_PYBRICKS_START + pybricks_size >= FLASH_END:
86125
print("Pybricks firmware too big.")
87126
return
127+
128+
for block in get_lego_firmware(lego_size, get_pybricks_reset_vector()):
129+
pass

0 commit comments

Comments
 (0)