diff options
Diffstat (limited to 'util/uf2conv.py')
| -rwxr-xr-x | util/uf2conv.py | 114 | 
1 files changed, 74 insertions, 40 deletions
| diff --git a/util/uf2conv.py b/util/uf2conv.py index 8677a828c9..fb82fd03ca 100755 --- a/util/uf2conv.py +++ b/util/uf2conv.py @@ -6,40 +6,13 @@ import re  import os  import os.path  import argparse +import json  UF2_MAGIC_START0 = 0x0A324655 # "UF2\n"  UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected  UF2_MAGIC_END    = 0x0AB16F30 # Ditto -families = { -    'SAMD21': 0x68ed2b88, -    'SAML21': 0x1851780a, -    'SAMD51': 0x55114460, -    'NRF52': 0x1b57745f, -    'STM32F0': 0x647824b6, -    'STM32F1': 0x5ee21072, -    'STM32F2': 0x5d1a0a2e, -    'STM32F3': 0x6b846188, -    'STM32F4': 0x57755a57, -    'STM32F7': 0x53b80f00, -    'STM32G0': 0x300f5633, -    'STM32G4': 0x4c71240a, -    'STM32H7': 0x6db66082, -    'STM32L0': 0x202e3a91, -    'STM32L1': 0x1e1f432d, -    'STM32L4': 0x00ff6919, -    'STM32L5': 0x04240bdf, -    'STM32WB': 0x70d16653, -    'STM32WL': 0x21460ff0, -    'ATMEGA32': 0x16573617, -    'MIMXRT10XX': 0x4FB2D5BD, -    'LPC55': 0x2abc77ec, -    'GD32F350': 0x31D228C6, -    'ESP32S2': 0xbfdd4eee, -    'RP2040': 0xe48bff56 -} -  INFO_FILE = "/INFO_UF2.TXT"  appstartaddr = 0x2000 @@ -61,8 +34,13 @@ def is_hex(buf):  def convert_from_uf2(buf):      global appstartaddr +    global familyid      numblocks = len(buf) // 512      curraddr = None +    currfamilyid = None +    families_found = {} +    prev_flag = None +    all_flags_same = True      outp = []      for blockno in range(numblocks):          ptr = blockno * 512 @@ -78,9 +56,13 @@ def convert_from_uf2(buf):          if datalen > 476:              assert False, "Invalid UF2 data size at " + ptr          newaddr = hd[3] -        if curraddr is None: -            appstartaddr = newaddr +        if (hd[2] & 0x2000) and (currfamilyid == None): +            currfamilyid = hd[7] +        if curraddr == None or ((hd[2] & 0x2000) and hd[7] != currfamilyid): +            currfamilyid = hd[7]              curraddr = newaddr +            if familyid == 0x0 or familyid == hd[7]: +                appstartaddr = newaddr          padding = newaddr - curraddr          if padding < 0:              assert False, "Block out of order at " + ptr @@ -91,8 +73,37 @@ def convert_from_uf2(buf):          while padding > 0:              padding -= 4              outp += b"\x00\x00\x00\x00" -        outp.append(block[32 : 32 + datalen]) +        if familyid == 0x0 or ((hd[2] & 0x2000) and familyid == hd[7]): +            outp.append(block[32 : 32 + datalen])          curraddr = newaddr + datalen +        if hd[2] & 0x2000: +            if hd[7] in families_found.keys(): +                if families_found[hd[7]] > newaddr: +                    families_found[hd[7]] = newaddr +            else: +                families_found[hd[7]] = newaddr +        if prev_flag == None: +            prev_flag = hd[2] +        if prev_flag != hd[2]: +            all_flags_same = False +        if blockno == (numblocks - 1): +            print("--- UF2 File Header Info ---") +            families = load_families() +            for family_hex in families_found.keys(): +                family_short_name = "" +                for name, value in families.items(): +                    if value == family_hex: +                        family_short_name = name +                print("Family ID is {:s}, hex value is 0x{:08x}".format(family_short_name,family_hex)) +                print("Target Address is 0x{:08x}".format(families_found[family_hex])) +            if all_flags_same: +                print("All block flag values consistent, 0x{:04x}".format(hd[2])) +            else: +                print("Flags were not all the same") +            print("----------------------------") +            if len(families_found) > 1 and familyid == 0x0: +                outp = [] +                appstartaddr = 0x0      return b"".join(outp)  def convert_to_carray(file_content): @@ -166,12 +177,11 @@ def convert_from_hex_to_uf2(buf):              upper = ((rec[4] << 8) | rec[5]) << 16          elif tp == 2:              upper = ((rec[4] << 8) | rec[5]) << 4 -            assert (upper & 0xffff) == 0          elif tp == 1:              break          elif tp == 0: -            addr = upper | (rec[1] << 8) | rec[2] -            if appstartaddr is None: +            addr = upper + ((rec[1] << 8) | rec[2]) +            if appstartaddr == None:                  appstartaddr = addr              i = 4              while i < len(rec) - 1: @@ -215,7 +225,7 @@ def get_drives():      def has_info(d):          try:              return os.path.isfile(d + INFO_FILE) -        except Exception: +        except:              return False      return list(filter(has_info, drives)) @@ -238,10 +248,26 @@ def write_file(name, buf):      print("Wrote %d bytes to %s" % (len(buf), name)) +def load_families(): +    # The expectation is that the `uf2families.json` file is in the same +    # directory as this script. Make a path that works using `__file__` +    # which contains the full path to this script. +    filename = "uf2families.json" +    pathname = os.path.join(os.path.dirname(os.path.abspath(__file__)), filename) +    with open(pathname) as f: +        raw_families = json.load(f) + +    families = {} +    for family in raw_families: +        families[family["short_name"]] = int(family["id"], 0) + +    return families + +  def main():      global appstartaddr, familyid      def error(msg): -        print(msg) +        print(msg, file=sys.stderr)          sys.exit(1)      parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.')      parser.add_argument('input', metavar='INPUT', type=str, nargs='?', @@ -264,9 +290,13 @@ def main():                          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.add_argument('-i', '--info', action='store_true', +                        help='display header information from UF2, do not convert')      args = parser.parse_args()      appstartaddr = int(args.base, 0) +    families = load_families() +      if args.family.upper() in families:          familyid = families[args.family.upper()]      else: @@ -286,9 +316,12 @@ def main():          ext = "uf2"          if args.deploy:              outbuf = inpbuf -        elif from_uf2: +        elif from_uf2 and not args.info:              outbuf = convert_from_uf2(inpbuf)              ext = "bin" +        elif from_uf2 and args.info: +            outbuf = "" +            convert_from_uf2(inpbuf)          elif is_hex(inpbuf):              outbuf = convert_from_hex_to_uf2(inpbuf.decode("utf-8"))          elif args.carray: @@ -296,11 +329,12 @@ 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)) +        if not args.deploy and not args.info: +            print("Converted to %s, output size: %d, start address: 0x%x" % +                  (ext, len(outbuf), appstartaddr))          if args.convert or ext != "uf2":              drives = [] -            if args.output is None: +            if args.output == None:                  args.output = "flash." + ext          else:              drives = get_drives() | 
