And a few other nice things. The bootloader now has an embedded wozmon! If you know its offset, you can jump to it from the app.
78 lines
1.8 KiB
Python
78 lines
1.8 KiB
Python
import argparse
|
|
import serial
|
|
import struct
|
|
import sys
|
|
import threading
|
|
import time
|
|
|
|
offset = 0x80000000
|
|
tty = '/dev/ttyUSB1'
|
|
baud = 115200
|
|
chunksize = 128
|
|
|
|
|
|
def write(s, offset, dat):
|
|
for i in range(0, len(dat), chunksize):
|
|
chunk = dat[i: i + chunksize]
|
|
cmd = struct.pack('<cII', b'c', offset + i, len(chunk))
|
|
|
|
print(f'Sending {len(chunk)} bytes @0x{offset + i:04x}')
|
|
|
|
s.write(cmd)
|
|
s.write(chunk)
|
|
|
|
ack = s.read(2)
|
|
if len(ack) < 2:
|
|
raise RuntimeError(f'timeout waiting for full ack. got {ack}')
|
|
if ack[0] != b'a'[0]:
|
|
raise RuntimeError(f'expected ack, got this instead: {ack}')
|
|
print(f'Ack! len={ack[1]}')
|
|
|
|
|
|
def jump(s, offset):
|
|
cmd = struct.pack('<cI', b'j', offset)
|
|
print(f'Jumping to 0x{offset:04x}')
|
|
s.write(cmd)
|
|
|
|
|
|
def stream_logs(s):
|
|
while True:
|
|
dat = s.read()
|
|
if not dat:
|
|
continue
|
|
sys.stdout.buffer.write(dat.replace(b'\r', b''))
|
|
sys.stdout.buffer.flush()
|
|
|
|
|
|
def parse_args():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("binary")
|
|
parser.add_argument("--monitor", action="store_true",
|
|
help="wait for and display program serial output")
|
|
return parser.parse_args()
|
|
|
|
def main():
|
|
args = parse_args()
|
|
|
|
with open(args.binary, 'rb') as f:
|
|
dat = f.read()
|
|
|
|
s = serial.Serial(tty, baud, timeout=1)
|
|
write(s, offset, dat)
|
|
jump(s, offset)
|
|
|
|
if args.monitor:
|
|
t = threading.Thread(target=lambda: stream_logs(s), daemon=True)
|
|
t.start()
|
|
|
|
try:
|
|
while True:
|
|
dat = input("") + '\r'
|
|
s.write(dat.encode())
|
|
except KeyboardInterrupt:
|
|
print("Bye.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|