Skip to content

Commit 69ea0e1

Browse files
committed
repl_installer: write combined firmware
1 parent 6539875 commit 69ea0e1

File tree

1 file changed

+59
-4
lines changed

1 file changed

+59
-4
lines changed

pybricksdev/resources/install_pybricks.py

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def get_pybricks_reset_vector():
3838
"""Gets the boot vector of the pybricks firmware."""
3939

4040
# Extract reset vector from dual boot firmware.
41-
with open("_pybricks/firmware.bin") as pybricks_bin_file:
41+
with open("_pybricks/firmware.bin", "rb") as pybricks_bin_file:
4242
pybricks_bin_file.seek(4)
4343
return pybricks_bin_file.read(4)
4444

@@ -84,6 +84,34 @@ def get_lego_firmware(size, reset_vector):
8484
yield block
8585

8686

87+
def get_pybricks_firmware(reset_vector):
88+
"""Gets the Pybricks firmware with an updated reset vector."""
89+
90+
# Open the file and get it chunk by chunk
91+
with open("_pybricks/firmware.bin", "rb") as pybricks_bin_file:
92+
93+
# Read first chunk and override boot vector
94+
block = bytearray(pybricks_bin_file.read(BLOCK_WRITE_SIZE))
95+
block[4:8] = reset_vector
96+
yield bytes(block)
97+
98+
# Yield remaining blocks
99+
while len(block) > 0:
100+
block = pybricks_bin_file.read(BLOCK_WRITE_SIZE)
101+
yield block
102+
103+
104+
def get_padding(padding_length):
105+
"""Gets empty padding blocks with extra information put in at the end."""
106+
107+
# Pad whole blocks as far as we can.
108+
for _ in range(padding_length // BLOCK_WRITE_SIZE):
109+
yield FF * BLOCK_WRITE_SIZE
110+
111+
# Pad remaining FF as a partial block.
112+
yield FF * (padding_length % BLOCK_WRITE_SIZE)
113+
114+
87115
def install(pybricks_hash):
88116
"""Main installation routine."""
89117

@@ -93,7 +121,7 @@ def install(pybricks_hash):
93121
pybricks_hash_calc = uhashlib.sha256()
94122
pybricks_size = 0
95123

96-
with open("_pybricks/firmware.bin") as pybricks_bin_file:
124+
with open("_pybricks/firmware.bin", "rb") as pybricks_bin_file:
97125
data = b'START'
98126
while len(data) > 0:
99127
data = pybricks_bin_file.read(128)
@@ -121,9 +149,36 @@ def install(pybricks_hash):
121149
print("LEGO firmware too big.")
122150
return
123151

124-
if FLASH_PYBRICKS_START + pybricks_size >= FLASH_END:
152+
# Total size of combined firmwares, including checksum
153+
total_size = FLASH_PYBRICKS_START - FLASH_LEGO_START + pybricks_size + 4
154+
if total_size >= FLASH_END:
125155
print("Pybricks firmware too big.")
126156
return
127157

158+
# Initialize flash
159+
print("Initializing flash for {0} bytes.".format(total_size))
160+
if not firmware.appl_image_initialise(total_size):
161+
print("Failed to initialize external flash.")
162+
return
163+
164+
# Copy original firmware to external flash
165+
print("Copying LEGO firmware.")
128166
for block in get_lego_firmware(lego_size, get_pybricks_reset_vector()):
129-
pass
167+
firmware.appl_image_store(block)
168+
169+
# Add padding to external flash
170+
print("Copying padding.")
171+
for block in get_padding(FLASH_PYBRICKS_START - FLASH_LEGO_START - lego_size):
172+
firmware.appl_image_store(block)
173+
174+
# Copy pybricks firmware to external flash
175+
print("Copying Pybricks firmware.")
176+
for block in get_pybricks_firmware(get_lego_reset_vector()):
177+
firmware.appl_image_store(block)
178+
179+
# Get the combined checksum and store it.
180+
overall_checksum = firmware.info()['new_appl_image_calc_checksum']
181+
firmware.appl_image_store(overall_checksum.to_bytes(4, 'little'))
182+
183+
# Check result
184+
print(firmware.info())

0 commit comments

Comments
 (0)