fix python warning in uf2conf (#4235)

the old regex worked but was technically incorrect.  fixes:
Generating NRF52 uf2 file
/home/kevinh/development/meshtastic/firmware/bin/uf2conv.py:195: SyntaxWarning: invalid escape sequence '\s'
  words = re.split('\s+', line)
Converting to uf2, output size: 1458688, start address: 0x26000
This commit is contained in:
geeksville 2024-07-09 05:19:03 -07:00 committed by GitHub
parent 308060b1fe
commit 33c46d6eb1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,39 +1,38 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import sys import argparse
import struct
import subprocess
import re
import os import os
import os.path import os.path
import argparse import re
import struct
import subprocess
import sys
UF2_MAGIC_START0 = 0x0A324655 # "UF2\n"
UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected
UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected UF2_MAGIC_END = 0x0AB16F30 # Ditto
UF2_MAGIC_END = 0x0AB16F30 # Ditto
families = { families = {
'SAMD21': 0x68ed2b88, "SAMD21": 0x68ED2B88,
'SAML21': 0x1851780a, "SAML21": 0x1851780A,
'SAMD51': 0x55114460, "SAMD51": 0x55114460,
'NRF52': 0x1b57745f, "NRF52": 0x1B57745F,
'STM32F0': 0x647824b6, "STM32F0": 0x647824B6,
'STM32F1': 0x5ee21072, "STM32F1": 0x5EE21072,
'STM32F2': 0x5d1a0a2e, "STM32F2": 0x5D1A0A2E,
'STM32F3': 0x6b846188, "STM32F3": 0x6B846188,
'STM32F4': 0x57755a57, "STM32F4": 0x57755A57,
'STM32F7': 0x53b80f00, "STM32F7": 0x53B80F00,
'STM32G0': 0x300f5633, "STM32G0": 0x300F5633,
'STM32G4': 0x4c71240a, "STM32G4": 0x4C71240A,
'STM32H7': 0x6db66082, "STM32H7": 0x6DB66082,
'STM32L0': 0x202e3a91, "STM32L0": 0x202E3A91,
'STM32L1': 0x1e1f432d, "STM32L1": 0x1E1F432D,
'STM32L4': 0x00ff6919, "STM32L4": 0x00FF6919,
'STM32L5': 0x04240bdf, "STM32L5": 0x04240BDF,
'STM32WB': 0x70d16653, "STM32WB": 0x70D16653,
'STM32WL': 0x21460ff0, "STM32WL": 0x21460FF0,
'ATMEGA32': 0x16573617, "ATMEGA32": 0x16573617,
'MIMXRT10XX': 0x4FB2D5BD "MIMXRT10XX": 0x4FB2D5BD,
} }
INFO_FILE = "/INFO_UF2.TXT" INFO_FILE = "/INFO_UF2.TXT"
@ -46,15 +45,17 @@ def is_uf2(buf):
w = struct.unpack("<II", buf[0:8]) w = struct.unpack("<II", buf[0:8])
return w[0] == UF2_MAGIC_START0 and w[1] == UF2_MAGIC_START1 return w[0] == UF2_MAGIC_START0 and w[1] == UF2_MAGIC_START1
def is_hex(buf): def is_hex(buf):
try: try:
w = buf[0:30].decode("utf-8") w = buf[0:30].decode("utf-8")
except UnicodeDecodeError: except UnicodeDecodeError:
return False return False
if w[0] == ':' and re.match(b"^[:0-9a-fA-F\r\n]+$", buf): if w[0] == ":" and re.match(b"^[:0-9a-fA-F\r\n]+$", buf):
return True return True
return False return False
def convert_from_uf2(buf): def convert_from_uf2(buf):
global appstartaddr global appstartaddr
numblocks = len(buf) // 512 numblocks = len(buf) // 512
@ -62,7 +63,7 @@ def convert_from_uf2(buf):
outp = b"" outp = b""
for blockno in range(numblocks): for blockno in range(numblocks):
ptr = blockno * 512 ptr = blockno * 512
block = buf[ptr:ptr + 512] block = buf[ptr : ptr + 512]
hd = struct.unpack(b"<IIIIIIII", block[0:32]) hd = struct.unpack(b"<IIIIIIII", block[0:32])
if hd[0] != UF2_MAGIC_START0 or hd[1] != UF2_MAGIC_START1: if hd[0] != UF2_MAGIC_START0 or hd[1] != UF2_MAGIC_START1:
print("Skipping block at " + ptr + "; bad magic") print("Skipping block at " + ptr + "; bad magic")
@ -80,7 +81,7 @@ def convert_from_uf2(buf):
padding = newaddr - curraddr padding = newaddr - curraddr
if padding < 0: if padding < 0:
assert False, "Block out of order at " + ptr assert False, "Block out of order at " + ptr
if padding > 10*1024*1024: if padding > 10 * 1024 * 1024:
assert False, "More than 10M of padding needed at " + ptr assert False, "More than 10M of padding needed at " + ptr
if padding % 4 != 0: if padding % 4 != 0:
assert False, "Non-word padding size at " + ptr assert False, "Non-word padding size at " + ptr
@ -91,6 +92,7 @@ def convert_from_uf2(buf):
curraddr = newaddr + datalen curraddr = newaddr + datalen
return outp return outp
def convert_to_carray(file_content): def convert_to_carray(file_content):
outp = "const unsigned char bindata[] __attribute__((aligned(16))) = {" outp = "const unsigned char bindata[] __attribute__((aligned(16))) = {"
for i in range(len(file_content)): for i in range(len(file_content)):
@ -100,6 +102,7 @@ def convert_to_carray(file_content):
outp += "\n};\n" outp += "\n};\n"
return outp return outp
def convert_to_uf2(file_content): def convert_to_uf2(file_content):
global familyid global familyid
datapadding = b"" datapadding = b""
@ -109,13 +112,21 @@ def convert_to_uf2(file_content):
outp = b"" outp = b""
for blockno in range(numblocks): for blockno in range(numblocks):
ptr = 256 * blockno ptr = 256 * blockno
chunk = file_content[ptr:ptr + 256] chunk = file_content[ptr : ptr + 256]
flags = 0x0 flags = 0x0
if familyid: if familyid:
flags |= 0x2000 flags |= 0x2000
hd = struct.pack(b"<IIIIIIII", hd = struct.pack(
UF2_MAGIC_START0, UF2_MAGIC_START1, b"<IIIIIIII",
flags, ptr + appstartaddr, 256, blockno, numblocks, familyid) UF2_MAGIC_START0,
UF2_MAGIC_START1,
flags,
ptr + appstartaddr,
256,
blockno,
numblocks,
familyid,
)
while len(chunk) < 256: while len(chunk) < 256:
chunk += b"\x00" chunk += b"\x00"
block = hd + chunk + datapadding + struct.pack(b"<I", UF2_MAGIC_END) block = hd + chunk + datapadding + struct.pack(b"<I", UF2_MAGIC_END)
@ -123,6 +134,7 @@ def convert_to_uf2(file_content):
outp += block outp += block
return outp return outp
class Block: class Block:
def __init__(self, addr): def __init__(self, addr):
self.addr = addr self.addr = addr
@ -133,35 +145,44 @@ class Block:
flags = 0x0 flags = 0x0
if familyid: if familyid:
flags |= 0x2000 flags |= 0x2000
hd = struct.pack("<IIIIIIII", hd = struct.pack(
UF2_MAGIC_START0, UF2_MAGIC_START1, "<IIIIIIII",
flags, self.addr, 256, blockno, numblocks, familyid) UF2_MAGIC_START0,
UF2_MAGIC_START1,
flags,
self.addr,
256,
blockno,
numblocks,
familyid,
)
hd += self.bytes[0:256] hd += self.bytes[0:256]
while len(hd) < 512 - 4: while len(hd) < 512 - 4:
hd += b"\x00" hd += b"\x00"
hd += struct.pack("<I", UF2_MAGIC_END) hd += struct.pack("<I", UF2_MAGIC_END)
return hd return hd
def convert_from_hex_to_uf2(buf): def convert_from_hex_to_uf2(buf):
global appstartaddr global appstartaddr
appstartaddr = None appstartaddr = None
upper = 0 upper = 0
currblock = None currblock = None
blocks = [] blocks = []
for line in buf.split('\n'): for line in buf.split("\n"):
if line[0] != ":": if line[0] != ":":
continue continue
i = 1 i = 1
rec = [] rec = []
while i < len(line) - 1: while i < len(line) - 1:
rec.append(int(line[i:i+2], 16)) rec.append(int(line[i : i + 2], 16))
i += 2 i += 2
tp = rec[3] tp = rec[3]
if tp == 4: if tp == 4:
upper = ((rec[4] << 8) | rec[5]) << 16 upper = ((rec[4] << 8) | rec[5]) << 16
elif tp == 2: elif tp == 2:
upper = ((rec[4] << 8) | rec[5]) << 4 upper = ((rec[4] << 8) | rec[5]) << 4
assert (upper & 0xffff) == 0 assert (upper & 0xFFFF) == 0
elif tp == 1: elif tp == 1:
break break
elif tp == 0: elif tp == 0:
@ -170,10 +191,10 @@ def convert_from_hex_to_uf2(buf):
appstartaddr = addr appstartaddr = addr
i = 4 i = 4
while i < len(rec) - 1: while i < len(rec) - 1:
if not currblock or currblock.addr & ~0xff != addr & ~0xff: if not currblock or currblock.addr & ~0xFF != addr & ~0xFF:
currblock = Block(addr & ~0xff) currblock = Block(addr & ~0xFF)
blocks.append(currblock) blocks.append(currblock)
currblock.bytes[addr & 0xff] = rec[i] currblock.bytes[addr & 0xFF] = rec[i]
addr += 1 addr += 1
i += 1 i += 1
numblocks = len(blocks) numblocks = len(blocks)
@ -182,17 +203,28 @@ def convert_from_hex_to_uf2(buf):
resfile += blocks[i].encode(i, numblocks) resfile += blocks[i].encode(i, numblocks)
return resfile return resfile
def to_str(b): def to_str(b):
return b.decode("utf-8") return b.decode("utf-8")
def get_drives(): def get_drives():
drives = [] drives = []
if sys.platform == "win32": if sys.platform == "win32":
r = subprocess.check_output(["wmic", "PATH", "Win32_LogicalDisk", r = subprocess.check_output(
"get", "DeviceID,", "VolumeName,", [
"FileSystem,", "DriveType"]) "wmic",
for line in to_str(r).split('\n'): "PATH",
words = re.split('\s+', line) "Win32_LogicalDisk",
"get",
"DeviceID,",
"VolumeName,",
"FileSystem,",
"DriveType",
]
)
for line in to_str(r).split("\n"):
words = re.split("\\s+", line)
if len(words) >= 3 and words[1] == "2" and words[2] == "FAT": if len(words) >= 3 and words[1] == "2" and words[2] == "FAT":
drives.append(words[0]) drives.append(words[0])
else: else:
@ -206,7 +238,6 @@ def get_drives():
for d in os.listdir(rootpath): for d in os.listdir(rootpath):
drives.append(os.path.join(rootpath, d)) drives.append(os.path.join(rootpath, d))
def has_info(d): def has_info(d):
try: try:
return os.path.isfile(d + INFO_FILE) return os.path.isfile(d + INFO_FILE)
@ -217,7 +248,7 @@ def get_drives():
def board_id(path): def board_id(path):
with open(path + INFO_FILE, mode='r') as file: with open(path + INFO_FILE, mode="r") as file:
file_content = file.read() file_content = file.read()
return re.search("Board-ID: ([^\r\n]*)", file_content).group(1) return re.search("Board-ID: ([^\r\n]*)", file_content).group(1)
@ -235,30 +266,61 @@ def write_file(name, buf):
def main(): def main():
global appstartaddr, familyid global appstartaddr, familyid
def error(msg): def error(msg):
print(msg) print(msg)
sys.exit(1) sys.exit(1)
parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.')
parser.add_argument('input', metavar='INPUT', type=str, nargs='?', parser = argparse.ArgumentParser(description="Convert to UF2 or flash directly.")
help='input file (HEX, BIN or UF2)') parser.add_argument(
parser.add_argument('-b' , '--base', dest='base', type=str, "input",
default="0x2000", metavar="INPUT",
help='set base address of application for BIN format (default: 0x2000)') type=str,
parser.add_argument('-o' , '--output', metavar="FILE", dest='output', type=str, nargs="?",
help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible') help="input file (HEX, BIN or UF2)",
parser.add_argument('-d' , '--device', dest="device_path", )
help='select a device path to flash') parser.add_argument(
parser.add_argument('-l' , '--list', action='store_true', "-b",
help='list connected devices') "--base",
parser.add_argument('-c' , '--convert', action='store_true', dest="base",
help='do not flash, just convert') type=str,
parser.add_argument('-D' , '--deploy', action='store_true', default="0x2000",
help='just flash, do not convert') help="set base address of application for BIN format (default: 0x2000)",
parser.add_argument('-f' , '--family', dest='family', type=str, )
default="0x0", parser.add_argument(
help='specify familyID - number or name (default: 0x0)') "-o",
parser.add_argument('-C' , '--carray', action='store_true', "--output",
help='convert binary file to a C array, not UF2') metavar="FILE",
dest="output",
type=str,
help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible',
)
parser.add_argument(
"-d", "--device", dest="device_path", help="select a device path to flash"
)
parser.add_argument(
"-l", "--list", action="store_true", help="list connected devices"
)
parser.add_argument(
"-c", "--convert", action="store_true", help="do not flash, just convert"
)
parser.add_argument(
"-D", "--deploy", action="store_true", help="just flash, do not convert"
)
parser.add_argument(
"-f",
"--family",
dest="family",
type=str,
default="0x0",
help="specify familyID - number or name (default: 0x0)",
)
parser.add_argument(
"-C",
"--carray",
action="store_true",
help="convert binary file to a C array, not UF2",
)
args = parser.parse_args() args = parser.parse_args()
appstartaddr = int(args.base, 0) appstartaddr = int(args.base, 0)
@ -268,14 +330,17 @@ def main():
try: try:
familyid = int(args.family, 0) familyid = int(args.family, 0)
except ValueError: except ValueError:
error("Family ID needs to be a number or one of: " + ", ".join(families.keys())) error(
"Family ID needs to be a number or one of: "
+ ", ".join(families.keys())
)
if args.list: if args.list:
list_drives() list_drives()
else: else:
if not args.input: if not args.input:
error("Need input file") error("Need input file")
with open(args.input, mode='rb') as f: with open(args.input, mode="rb") as f:
inpbuf = f.read() inpbuf = f.read()
from_uf2 = is_uf2(inpbuf) from_uf2 = is_uf2(inpbuf)
ext = "uf2" ext = "uf2"
@ -291,8 +356,10 @@ def main():
ext = "h" ext = "h"
else: else:
outbuf = convert_to_uf2(inpbuf) outbuf = convert_to_uf2(inpbuf)
print("Converting to %s, output size: %d, start address: 0x%x" % print(
(ext, len(outbuf), appstartaddr)) "Converting to %s, output size: %d, start address: 0x%x"
% (ext, len(outbuf), appstartaddr)
)
if args.convert or ext != "uf2": if args.convert or ext != "uf2":
drives = [] drives = []
if args.output == None: if args.output == None: