Skip to content
Closed
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
108 changes: 60 additions & 48 deletions utils/uf2conv.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/python

#!/usr/bin/env python3
import sys
import struct
import subprocess
Expand All @@ -8,6 +7,7 @@
import os.path
import argparse


UF2_MAGIC_START0 = 0x0A324655 # "UF2\n"
UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected
UF2_MAGIC_END = 0x0AB16F30 # Ditto
Expand All @@ -16,20 +16,22 @@

appstartaddr = 0x2000

def isUF2(buf):

def is_uf2(buf):
w = struct.unpack("<II", buf[0:8])
return w[0] == UF2_MAGIC_START0 and w[1] == UF2_MAGIC_START1

def convertFromUF2(buf):
numblocks = len(buf) / 512

def convert_from_uf2(buf):
numblocks = len(buf) // 512
curraddr = None
outp = ""
for blockno in range(0, numblocks):
outp = b""
for blockno in range(numblocks):
ptr = blockno * 512
block = buf[ptr:ptr + 512]
hd = struct.unpack("<IIIIIIII", block[0:32])
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"
print("Skipping block at " + ptr + "; bad magic")
continue
if hd[2] & 1:
# NO-flash flag set; skip block
Expand All @@ -50,34 +52,38 @@ def convertFromUF2(buf):
assert False, "Non-word padding size at " + ptr
while padding > 0:
padding -= 4
outp += "\x00\x00\x00\x00"
outp += b"\x00\x00\x00\x00"
outp += block[32 : 32 + datalen]
curraddr = newaddr + datalen
return outp

def convertToUF2(fileContent):
datapadding = ""

def convert_to_uf2(file_content):
datapadding = b""
while len(datapadding) < 512 - 256 - 32 - 4:
datapadding += "\x00\x00\x00\x00"
numblocks = (len(fileContent) + 255) / 256
outp = ""
for blockno in range(0, numblocks):
datapadding += b"\x00\x00\x00\x00"
numblocks = (len(file_content) + 255) // 256
outp = b""
for blockno in range(numblocks):
ptr = 256 * blockno
chunk = fileContent[ptr:ptr + 256]
hd = struct.pack("<IIIIIIII",
chunk = file_content[ptr:ptr + 256]
hd = struct.pack(b"<IIIIIIII",
UF2_MAGIC_START0, UF2_MAGIC_START1,
0, ptr + appstartaddr, 256, blockno, numblocks, 0)
while len(chunk) < 256:
chunk += "\x00"
block = hd + chunk + datapadding + struct.pack("<I", UF2_MAGIC_END)
chunk += b"\x00"
block = hd + chunk + datapadding + struct.pack(b"<I", UF2_MAGIC_END)
assert len(block) == 512
outp += block
return outp

def getdrives():

def get_drives():
drives = []
if sys.platform == "win32":
r = subprocess.check_output(["wmic", "PATH", "Win32_LogicalDisk", "get", "DeviceID,", "VolumeName,", "FileSystem,", "DriveType"])
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":
Expand All @@ -92,33 +98,38 @@ def getdrives():
rootpath = tmp
for d in os.listdir(rootpath):
drives.append(os.path.join(rootpath, d))



def hasInfo(d):
try:
return os.path.isfile(d + INFO_FILE)
except:
return False

return filter(hasInfo, drives)
return list(filter(hasInfo, drives))

def boardID(path):

def board_id(path):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the calls to the function didn't get renamed. (line 120 & line 179)

with open(path + INFO_FILE, mode='r') as file:
fileContent = file.read()
return re.search("Board-ID: ([^\r\n]*)", fileContent).group(1)

def listdrives():
for d in getdrives():
print d, boardID(d)

def writeFile(name, buf):
file_content = file.read()
return re.search("Board-ID: ([^\r\n]*)", file_content).group(1)


def list_drives():
for d in get_drives():
print(d, boardID(d))


def write_file(name, buf):
with open(name, "wb") as f:
f.write(buf)
print "Wrote %d bytes to %s." % (len(buf), name)
print("Wrote %d bytes to %s." % (len(buf), name))


def main():
global appstartaddr
def error(msg):
print 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='?',
Expand All @@ -137,36 +148,37 @@ def error(msg):
args = parser.parse_args()
appstartaddr = int(args.base, 0)
if args.list:
listdrives()
list_drives()
else:
if not args.input:
error("Need input file")
with open(args.input, mode='rb') as file:
inpbuf = file.read()
fromUF2 = isUF2(inpbuf)
with open(args.input, mode='rb') as f:
inpbuf = f.read()
from_uf2 = is_uf2(inpbuf)
ext = "uf2"
if fromUF2:
outbuf = convertFromUF2(inpbuf)
if from_uf2:
outbuf = convert_from_uf2(inpbuf)
ext = "bin"
else:
outbuf = convertToUF2(inpbuf)
print "Converting to %s, output size: %d, start address: 0x%x" % (ext, len(outbuf), appstartaddr)

outbuf = convert_to_uf2(inpbuf)
print("Converting to %s, output size: %d, start address: 0x%x" %
(ext, len(outbuf), appstartaddr))
if args.convert:
drives = []
if args.output == None:
args.output = "flash." + ext
else:
drives = getdrives()
drives = get_drives()

if args.output:
writeFile(args.output, outbuf)
write_file(args.output, outbuf)
else:
if len(drives) == 0:
error("No drive to deploy.")
for d in drives:
print "Flashing %s (%s)" % (d, boardID(d))
writeFile(outbuf, d + "/NEW.UF2")
print("Flashing %s (%s)" % (d, boardID(d)))
write_file(outbuf, d + "/NEW.UF2")


if __name__ == "__main__":
main()