1818FLASH_LEGO_START = 0x8008000
1919FLASH_PYBRICKS_START = 0x80C0000
2020
21+ BLOCK_READ_SIZE = 32
22+ BLOCK_WRITE_SIZE = BLOCK_READ_SIZE * 4
23+
2124FF = 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+
3446def 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+
4887def 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