diff options
Diffstat (limited to 'tools/uf2conv.py')
-rwxr-xr-x | tools/uf2conv.py | 170 |
1 files changed, 110 insertions, 60 deletions
diff --git a/tools/uf2conv.py b/tools/uf2conv.py index 2f2812abf..d67a55224 100755 --- a/tools/uf2conv.py +++ b/tools/uf2conv.py @@ -1,23 +1,23 @@ #!/usr/bin/env python3 # Microsoft UF2 -# +# # The MIT License (MIT) -# +# # Copyright (c) Microsoft Corporation -# +# # All rights reserved. -# +# # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -35,17 +35,17 @@ import os.path import argparse -UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" -UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected -UF2_MAGIC_END = 0x0AB16F30 # Ditto +UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" +UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected +UF2_MAGIC_END = 0x0AB16F30 # Ditto families = { - 'SAMD21': 0x68ed2b88, - 'SAMD51': 0x55114460, - 'NRF52': 0x1b57745f, - 'STM32F1': 0x5ee21072, - 'STM32F4': 0x57755a57, - 'ATMEGA32': 0x16573617, + "SAMD21": 0x68ED2B88, + "SAMD51": 0x55114460, + "NRF52": 0x1B57745F, + "STM32F1": 0x5EE21072, + "STM32F4": 0x57755A57, + "ATMEGA32": 0x16573617, } INFO_FILE = "/INFO_UF2.TXT" @@ -58,15 +58,17 @@ def is_uf2(buf): w = struct.unpack("<II", buf[0:8]) return w[0] == UF2_MAGIC_START0 and w[1] == UF2_MAGIC_START1 + def is_hex(buf): try: w = buf[0:30].decode("utf-8") except UnicodeDecodeError: 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 False + def convert_from_uf2(buf): global appstartaddr numblocks = len(buf) // 512 @@ -74,7 +76,7 @@ def convert_from_uf2(buf): outp = b"" for blockno in range(numblocks): ptr = blockno * 512 - block = buf[ptr:ptr + 512] + block = buf[ptr : ptr + 512] hd = struct.unpack(b"<IIIIIIII", block[0:32]) if hd[0] != UF2_MAGIC_START0 or hd[1] != UF2_MAGIC_START1: print("Skipping block at " + ptr + "; bad magic") @@ -92,7 +94,7 @@ def convert_from_uf2(buf): padding = newaddr - curraddr if padding < 0: 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 if padding % 4 != 0: assert False, "Non-word padding size at " + ptr @@ -103,6 +105,7 @@ def convert_from_uf2(buf): curraddr = newaddr + datalen return outp + def convert_to_carray(file_content): outp = "const unsigned char bindata[] __attribute__((aligned(16))) = {" for i in range(len(file_content)): @@ -112,6 +115,7 @@ def convert_to_carray(file_content): outp += "\n};\n" return outp + def convert_to_uf2(file_content): global familyid datapadding = b"" @@ -121,13 +125,21 @@ def convert_to_uf2(file_content): outp = b"" for blockno in range(numblocks): ptr = 256 * blockno - chunk = file_content[ptr:ptr + 256] + chunk = file_content[ptr : ptr + 256] flags = 0x0 if familyid: flags |= 0x2000 - hd = struct.pack(b"<IIIIIIII", - UF2_MAGIC_START0, UF2_MAGIC_START1, - flags, ptr + appstartaddr, 256, blockno, numblocks, familyid) + hd = struct.pack( + b"<IIIIIIII", + UF2_MAGIC_START0, + UF2_MAGIC_START1, + flags, + ptr + appstartaddr, + 256, + blockno, + numblocks, + familyid, + ) while len(chunk) < 256: chunk += b"\x00" block = hd + chunk + datapadding + struct.pack(b"<I", UF2_MAGIC_END) @@ -135,6 +147,7 @@ def convert_to_uf2(file_content): outp += block return outp + class Block: def __init__(self, addr): self.addr = addr @@ -145,35 +158,44 @@ class Block: flags = 0x0 if familyid: flags |= 0x2000 - hd = struct.pack("<IIIIIIII", - UF2_MAGIC_START0, UF2_MAGIC_START1, - flags, self.addr, 256, blockno, numblocks, familyid) + hd = struct.pack( + "<IIIIIIII", + UF2_MAGIC_START0, + UF2_MAGIC_START1, + flags, + self.addr, + 256, + blockno, + numblocks, + familyid, + ) hd += self.bytes[0:256] while len(hd) < 512 - 4: hd += b"\x00" hd += struct.pack("<I", UF2_MAGIC_END) return hd + def convert_from_hex_to_uf2(buf): global appstartaddr appstartaddr = None upper = 0 currblock = None blocks = [] - for line in buf.split('\n'): + for line in buf.split("\n"): if line[0] != ":": continue i = 1 rec = [] while i < len(line) - 1: - rec.append(int(line[i:i+2], 16)) + rec.append(int(line[i : i + 2], 16)) i += 2 tp = rec[3] if tp == 4: upper = ((rec[4] << 8) | rec[5]) << 16 elif tp == 2: upper = ((rec[4] << 8) | rec[5]) << 4 - assert (upper & 0xffff) == 0 + assert (upper & 0xFFFF) == 0 elif tp == 1: break elif tp == 0: @@ -182,10 +204,10 @@ def convert_from_hex_to_uf2(buf): appstartaddr = addr i = 4 while i < len(rec) - 1: - if not currblock or currblock.addr & ~0xff != addr & ~0xff: - currblock = Block(addr & ~0xff) + if not currblock or currblock.addr & ~0xFF != addr & ~0xFF: + currblock = Block(addr & ~0xFF) blocks.append(currblock) - currblock.bytes[addr & 0xff] = rec[i] + currblock.bytes[addr & 0xFF] = rec[i] addr += 1 i += 1 numblocks = len(blocks) @@ -194,14 +216,24 @@ def convert_from_hex_to_uf2(buf): resfile += blocks[i].encode(i, numblocks) return resfile + def get_drives(): drives = [] if sys.platform == "win32": - r = subprocess.check_output(["wmic", "PATH", "Win32_LogicalDisk", - "get", "DeviceID,", "VolumeName,", - "FileSystem,", "DriveType"]) - for line in r.split('\n'): - words = re.split('\s+', line) + r = subprocess.check_output( + [ + "wmic", + "PATH", + "Win32_LogicalDisk", + "get", + "DeviceID,", + "VolumeName,", + "FileSystem,", + "DriveType", + ] + ) + for line in r.split("\n"): + words = re.split("\s+", line) if len(words) >= 3 and words[1] == "2" and words[2] == "FAT": drives.append(words[0]) else: @@ -215,7 +247,6 @@ def get_drives(): for d in os.listdir(rootpath): drives.append(os.path.join(rootpath, d)) - def has_info(d): try: return os.path.isfile(d + INFO_FILE) @@ -226,7 +257,7 @@ def get_drives(): 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() return re.search("Board-ID: ([^\r\n]*)", file_content).group(1) @@ -244,28 +275,45 @@ def write_file(name, buf): def main(): global appstartaddr, familyid + def error(msg): print(msg) sys.exit(1) - parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.') - parser.add_argument('input', metavar='INPUT', type=str, nargs='?', - help='input file (HEX, BIN or UF2)') - parser.add_argument('-b' , '--base', dest='base', type=str, - default="0x2000", - help='set base address of application for BIN format (default: 0x2000)') - parser.add_argument('-o' , '--output', 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('-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') + + parser = argparse.ArgumentParser(description="Convert to UF2 or flash directly.") + parser.add_argument( + "input", metavar="INPUT", type=str, nargs="?", help="input file (HEX, BIN or UF2)" + ) + parser.add_argument( + "-b", + "--base", + dest="base", + type=str, + default="0x2000", + help="set base address of application for BIN format (default: 0x2000)", + ) + parser.add_argument( + "-o", + "--output", + 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( + "-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() appstartaddr = int(args.base, 0) @@ -282,7 +330,7 @@ def main(): else: if not args.input: error("Need input file") - with open(args.input, mode='rb') as f: + with open(args.input, mode="rb") as f: inpbuf = f.read() from_uf2 = is_uf2(inpbuf) ext = "uf2" @@ -296,8 +344,10 @@ def main(): ext = "h" else: outbuf = convert_to_uf2(inpbuf) - print("Converting to %s, output size: %d, start address: 0x%x" % - (ext, len(outbuf), appstartaddr)) + print( + "Converting to %s, output size: %d, start address: 0x%x" + % (ext, len(outbuf), appstartaddr) + ) if args.convert: drives = [] if args.output == None: |