Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serial number handling #6

Merged
merged 7 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified firmware.bin
Binary file not shown.
1 change: 1 addition & 0 deletions flash-bootloader.template
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ file bootloader.elf
target extended-remote BLACKMAGIC_PORT
monitor swdp_scan
attach 1
monitor serial
monitor unlock_bootprot
monitor erase_mass
load
Expand Down
68 changes: 55 additions & 13 deletions tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,14 +475,44 @@ def run_command(cmd):
f"Command '{cmd}' failed with exit status {process.returncode}.\n\n" +
"Output of failed command:\n\n" +
f"{process.stdout.decode().rstrip()}")
return process

def flash_bootloader():
with task(f"Flashing Saturn-V bootloader to MCU via SWD"):
script = open('flash-bootloader.gdb', 'w')
for line in open('flash-bootloader.template', 'r').readlines():
script.write(line.replace('BLACKMAGIC_PORT', blackmagic_port))
script.close()
run_command('gdb-multiarch --batch -x flash-bootloader.gdb')
with group(f"Flashing Saturn-V bootloader to MCU via SWD"):
with task("Running flash script"):
script = open('flash-bootloader.gdb', 'w')
for line in open('flash-bootloader.template', 'r').readlines():
script.write(line.replace('BLACKMAGIC_PORT', blackmagic_port))
script.close()
process = run_command('gdb-multiarch --batch -x flash-bootloader.gdb')
with task("Checking for MCU serial number"):
prefix = "Serial Number: 0x"
for line in process.stdout.decode().split('\n'):
if line.startswith(prefix):
serial_string = line[len(prefix):].rstrip()
break
else:
raise RuntimeError("MCU serial number not found in output:\n\n" +
f"{process.stdout.decode().rstrip()}")
serial_bytes = bytes.join(b'', [
int(serial_string[i:i+8], 16).to_bytes(4, byteorder='little')
for i in (0, 8, 16, 24)]) + b'\x00'
buffer = serial_bytes[0]
bits_left = 8
next_byte = 1
serial = ''
for count in range(26):
if bits_left < 5:
buffer <<= 8
buffer |= serial_bytes[next_byte] & 0xFF
next_byte += 1
bits_left += 8
bits_left -= 5
index = (buffer >> bits_left) & 0x1F
serial += chr(index + (ord('A') if index < 26 else ord('2')))
item(f"MCU serial number: {info(serial)}")
global mcu_serial
mcu_serial = serial

def flash_firmware():
with task(f"Flashing Apollo to MCU via DFU"):
Expand All @@ -492,13 +522,15 @@ def test_saturnv_present():
with group(f"Checking for Saturn-V"):
return find_device(0x1d50, 0x615c,
"Great Scott Gadgets",
"Saturn-V")
"Saturn-V",
mcu_serial)

def test_apollo_present():
with group(f"Checking for Apollo"):
find_device(0x1d50, 0x615c,
"Great Scott Gadgets",
"Apollo Debugger")
"Apollo Debugger",
mcu_serial)
with task("Connecting to Apollo"):
apollo = ApolloDebugger()
return apollo
Expand Down Expand Up @@ -574,6 +606,9 @@ def test_flash_id(apollo, expected_mfg, expected_part):
programmer = apollo.create_jtag_programmer(jtag)
with task("Reading flash ID"):
mfg, part = programmer.read_flash_id()
with task("Reading flash UID"):
uid = programmer.read_flash_uid()
item(f"Flash UID is {info(f'0x{uid:08X}')}")
with task(f"Checking manufacturer ID is {info(f'0x{expected_mfg:02X}')}"):
if mfg != expected_mfg:
raise ValueError(f"Wrong flash chip manufacturer ID: 0x{mfg:02X}")
Expand Down Expand Up @@ -605,7 +640,7 @@ def request_control_handoff_to_fpga(apollo):
apollo.honor_fpga_adv()
apollo.close()

def check_device(device, mfg, prod):
def check_device(device, mfg, prod, serial):
global last_bus, last_addr
bus = device.getBusNumber()
addr = device.getDeviceAddress()
Expand All @@ -626,17 +661,24 @@ def check_device(device, mfg, prod):
if (string := device.getProduct()) != prod:
raise ValueError(
f"Wrong product string: '{string}'")
serial = device.getSerialNumber()
item(f"Device serial is {info(serial)}")
if serial is not None:
with task(f"Checking serial is {info(serial)}"):
if (string := device.getSerialNumber()) != serial:
raise ValueError(
f"Wrong serial string: '{string}'")
else:
serial = device.getSerialNumber()
item(f"Device serial is {info(serial)}")
last_bus = bus
last_addr = addr
return True

def find_device(vid, pid, mfg=None, prod=None, timeout=3):
def find_device(vid, pid, mfg=None, prod=None, serial=None, timeout=3):
with group(f"Looking for device with"):
item(f"VID: {info(f'0x{vid:04x}')}, PID: {info(f'0x{pid:04x}')}")
item(f"Manufacturer: {info(mfg)}")
item(f"Product: {info(prod)}")
item(f"Serial: {info(serial)}")

candidates = []

Expand All @@ -657,7 +699,7 @@ def callback(context, device, event):
try:
while device := candidates.pop():
try:
if check_device(device, mfg, prod):
if check_device(device, mfg, prod, serial):
context.hotplugDeregisterCallback(callback_handle)
return device
except usb1.USBError:
Expand Down