Skip to content

Commit 7e96877

Browse files
committed
Improve debugging output
1 parent acf63d6 commit 7e96877

File tree

1 file changed

+68
-70
lines changed

1 file changed

+68
-70
lines changed

src/modulino/firmware_flasher.py

Lines changed: 68 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
CMD_GET_ID = const(0x02) # Get chip ID
1414
CMD_ERASE = const(0x44) # Erase memory
1515
CMD_GO = const(0x21) # Jumps to user application code located in the internal flash memory
16-
CMD_WRITE = const(0x32) # Write memory
16+
CMD_WRITE_NO_STRETCH = const(0x32) # Writes up to 256 bytes to the memory, starting from an address specified
17+
CHUNK_SIZE = const(128) # Size of the memory chunk to write
1718

1819
# Define I2C pins and initialize I2C
1920
i2c = I2C(0, freq=100000)
@@ -29,9 +30,9 @@ def send_reset(address):
2930
buffer += b'\x00' * (8 - len(buffer)) # Pad buffer to 8 bytes
3031

3132
try:
32-
print(f"Sending reset command to address {hex(address)}")
33+
print(f"🔄 Resetting device at address {hex(address)}")
3334
i2c.writeto(address, buffer, True)
34-
print("Reset command sent successfully")
35+
print("Reset command sent successfully")
3536
time.sleep(0.25) # Wait for the device to reset
3637
return True
3738
except OSError as e:
@@ -55,13 +56,12 @@ def wait_for_ack():
5556
while res == BUSY:
5657
time.sleep(0.1)
5758
res = i2c.readfrom(BOOTLOADER_I2C_ADDRESS, 1)[0]
58-
print("Waiting for device to be finish processing")
5959
if res != ACK:
60-
print(f"Error processing command: {hex(res)}")
60+
print(f"Error processing command. Result code: {hex(res)}")
6161
return False
6262
return True
6363

64-
def execute_command(opcode, command_data, response_length = 0, verbose=True):
64+
def execute_command(opcode, command_data, response_length = 0, verbose=False):
6565
"""
6666
Execute an I2C command on the device.
6767
@@ -72,34 +72,36 @@ def execute_command(opcode, command_data, response_length = 0, verbose=True):
7272
:return: The number of response bytes read, or -1 if an error occurred.
7373
"""
7474
if verbose:
75-
print(f"Executing command {hex(opcode)}")
75+
print(f"🕵️ Executing command {hex(opcode)}")
7676

7777
cmd = bytes([opcode, 0xFF ^ opcode]) # Send command code and complement (XOR = 0x00)
7878
i2c.writeto(BOOTLOADER_I2C_ADDRESS, cmd, True)
7979
if not wait_for_ack():
80-
print(f"Command not acknowledged: {hex(opcode)}")
80+
print(f"Command not acknowledged: {hex(opcode)}")
8181
return None
8282

8383
if command_data is not None:
8484
i2c.writeto(BOOTLOADER_I2C_ADDRESS, command_data, True)
8585
if not wait_for_ack():
86-
print("Command failed")
86+
print("Command failed")
8787
return None
8888

8989
if response_length == 0:
9090
return None
9191

9292
data = i2c.readfrom(BOOTLOADER_I2C_ADDRESS, response_length)
9393
amount_of_bytes = data[0] + 1
94-
print(f"Retrieved {amount_of_bytes} bytes") # TODO: Remove this line
94+
95+
if verbose:
96+
print(f"📦 Received {amount_of_bytes} bytes")
9597

9698
if not wait_for_ack():
97-
print("Failed completing command")
99+
print("Failed completing command")
98100
return None
99101

100102
return data[1 : amount_of_bytes + 1]
101103

102-
def flash_firmware(firmware_path, verbose=True):
104+
def flash_firmware(firmware_path, verbose=False):
103105
"""
104106
Flash the firmware to the I2C device.
105107
@@ -110,87 +112,85 @@ def flash_firmware(firmware_path, verbose=True):
110112
"""
111113
data = execute_command(CMD_GET, None, 20, verbose)
112114
if data is None:
113-
print("Failed :(")
115+
print("Failed to get command list")
114116
return False
115117

116-
print(f"Bootloader version: {hex(data[0])}")
117-
print("Supported commands:")
118-
for byte in data[1:]:
119-
print(hex(byte))
118+
print(f"ℹ️ Bootloader version: {hex(data[0])}")
119+
print("👀 Supported commands:")
120+
print(", ".join([hex(byte) for byte in data[1:]]))
120121

121122
data = execute_command(CMD_GET_ID, None, 3, verbose)
122123
if data is None:
123-
print("Failed to get device ID")
124+
print("Failed to get device ID")
124125
return False
125126

126127
chip_id = (data[0] << 8) | data[1] # Chip ID: Byte 1 = MSB, Byte 2 = LSB
127-
print(f"Chip ID: {chip_id}")
128+
print(f"ℹ️ Chip ID: {chip_id}")
128129

129-
print("Erasing memory...")
130+
print("🗑️ Erasing memory...")
130131
erase_params = bytearray([0xFF, 0xFF, 0x0]) # Mass erase flash
131132
#execute_command(CMD_ERASE, erase_params, 0, verbose)
132133

133134
with open(firmware_path, 'rb') as file:
134135
firmware_data = file.read()
135136
total_bytes = len(firmware_data)
136137

137-
print(f"Flashing {total_bytes} bytes of firmware")
138-
for i in range(0, total_bytes, 128):
138+
print(f"🔥 Flashing {total_bytes} bytes of firmware")
139+
for i in range(0, total_bytes, CHUNK_SIZE):
139140
progress_bar(i, total_bytes)
140-
write_buffer = bytearray([8, 0, i // 256, i % 256])
141-
# if write_firmware_page(write_buffer, 5, firmware_data[i:i + 128], 128, verbose) < 0:
142-
# print(f"Failed to write page {hex(i)}")
143-
# return False
144-
time.sleep(0.01)
141+
start_address = bytearray([8, 0, i // 256, i % 256]) # 4-byte address: byte 1 = MSB, byte 4 = LSB
142+
checksum = 0
143+
for b in start_address:
144+
checksum ^= b
145+
start_address.append(checksum)
146+
data_slice = firmware_data[i:i + CHUNK_SIZE]
147+
if not write_firmware_page(start_address, data_slice):
148+
print(f"❌ Failed to write page {hex(i)}")
149+
return False
150+
time.sleep(0.01) # Give the device some time to process the data
145151

146152
progress_bar(total_bytes, total_bytes) # Complete the progress bar
147153

148-
print("Starting firmware")
154+
print("🏃 Starting firmware")
149155
go_params = bytearray([0x8, 0x00, 0x00, 0x00, 0x8])
150156
#execute_command(CMD_GO, go_params, 0, verbose) # Jump to the application
151157

152158
return True
153159

154-
def write_firmware_page(command_buffer, command_length, firmware_buffer, firmware_length, verbose=True):
160+
def write_firmware_page(command_params, firmware_data):
155161
"""
156162
Write a page of the firmware to the I2C device.
157163
158-
:param opcode: The command opcode.
159-
:param command_buffer: The buffer containing the command data.
160-
:param command_length: The length of the command data.
161-
:param firmware_buffer: The buffer containing the firmware data.
162-
:param firmware_length: The length of the firmware data.
164+
:param command_params: The buffer containing the command data.
165+
:param firmware_data: The buffer containing the firmware data.
163166
:param verbose: Whether to print debug information.
164167
:return: The number of bytes written, or -1 if an error occurred.
165168
"""
166-
cmd = bytes([CMD_WRITE, 0xFF ^ CMD_WRITE])
167-
i2c.writeto(100, cmd)
168-
169-
if command_length > 0:
170-
command_buffer[command_length - 1] = 0
171-
for i in range(command_length - 1):
172-
command_buffer[command_length - 1] ^= command_buffer[i]
173-
i2c.writeto(100, command_buffer)
169+
cmd = bytes([CMD_WRITE_NO_STRETCH, 0xFF ^ CMD_WRITE_NO_STRETCH])
170+
i2c.writeto(BOOTLOADER_I2C_ADDRESS, cmd)
171+
if not wait_for_ack():
172+
print("❌ Write command not acknowledged")
173+
return False
174174

175-
ack = i2c.readfrom(100, 1)[0]
176-
if ack != 0x79:
177-
print(f"Error first ack: {hex(ack)}")
178-
return -1
175+
i2c.writeto(BOOTLOADER_I2C_ADDRESS, command_params)
176+
if not wait_for_ack():
177+
print("❌ Failed to write command parameters")
178+
return False
179179

180-
tmp_buffer = bytearray(firmware_length + 2)
181-
tmp_buffer[0] = firmware_length - 1
182-
tmp_buffer[1:firmware_length + 1] = firmware_buffer
183-
tmp_buffer[firmware_length + 1] = 0
184-
for i in range(firmware_length + 1):
185-
tmp_buffer[firmware_length + 1] ^= tmp_buffer[i]
180+
data_size = len(firmware_data)
181+
tmp_buffer = bytearray(data_size + 2) # Data plus size and checksum
182+
tmp_buffer[0] = data_size - 1 # Size of the data # TODO Arduino code uses data_size - 1
183+
tmp_buffer[1:data_size + 1] = firmware_data
184+
tmp_buffer[-1] = 0 # Checksum placeholder
185+
for i in range(data_size + 1): # Calculate checksum over size byte + data bytes
186+
tmp_buffer[-1] ^= tmp_buffer[i]
186187

187-
i2c.writeto(100, tmp_buffer)
188-
ack = i2c.readfrom(100, 1)[0]
189-
if ack != 0x79:
190-
print(f"Error: {hex(ack)}")
191-
return -1
188+
i2c.writeto(BOOTLOADER_I2C_ADDRESS, tmp_buffer)
189+
if not wait_for_ack():
190+
print("❌ Failed to write firmware")
191+
return False
192192

193-
return firmware_length
193+
return True
194194

195195
def progress_bar(current, total, bar_length=40):
196196
"""
@@ -223,11 +223,11 @@ def select_file(bin_files):
223223
:return: The selected .bin file name.
224224
"""
225225
if len(bin_files) == 1:
226-
confirm = input(f"Found one bin file: {bin_files[0]}. Do you want to flash it? (yes/no) ")
226+
confirm = input(f"👀 Found one bin file: {bin_files[0]}. Do you want to flash it? (yes/no) ")
227227
if confirm.lower() == 'yes':
228228
return bin_files[0]
229229
else:
230-
print("Found bin files:")
230+
print("👀 Found bin files:")
231231
for index, file in enumerate(bin_files):
232232
print(f"{index + 1}. {file}")
233233
choice = int(input("Select the file to flash (number): "))
@@ -240,7 +240,7 @@ def select_i2c_device():
240240
:return: The selected I2C device address.
241241
"""
242242
devices = i2c.scan()
243-
print("I2C devices found:")
243+
print("👀 I2C devices found:")
244244
for index, device in enumerate(devices):
245245
print(f"{index + 1}. Address: {hex(device)}")
246246
choice = int(input("Select the I2C device to flash (number): "))
@@ -251,29 +251,27 @@ def setup():
251251
Setup function to initialize the flashing process.
252252
Finds .bin files, scans for I2C devices, and flashes the selected firmware.
253253
"""
254-
print("Starting setup")
255254

256255
bin_files = find_bin_files()
257256
if not bin_files:
258-
print("No .bin files found in the root directory.")
257+
print("No .bin files found in the root directory.")
259258
return
260259

261260
bin_file = "node_base.bin" # select_file(bin_files)
262261

263-
device_address = 30 # select_i2c_device()
264-
print(f"Resetting device at address {hex(device_address)}")
262+
device_address = 30 # select_i2c_device()
265263
if send_reset(device_address):
266-
print("Device reset successfully")
264+
print("Device reset successfully")
267265
else:
268-
print("Failed to reset device")
266+
print("Failed to reset device")
269267
return
270268

271-
print(f"Flashing {bin_file} to device at address {hex(BOOTLOADER_I2C_ADDRESS)}")
269+
print(f"🕵️ Flashing {bin_file} to device at address {hex(BOOTLOADER_I2C_ADDRESS)}")
272270

273271
if flash_firmware(bin_file):
274-
print("Firmware flashed successfully")
272+
print("Firmware flashed successfully")
275273
else:
276-
print("Failed to flash firmware")
274+
print("Failed to flash firmware")
277275

278276
# Start the setup
279277
setup()

0 commit comments

Comments
 (0)