33
33
import os
34
34
import os .path
35
35
import argparse
36
+ import json
36
37
37
38
38
39
UF2_MAGIC_START0 = 0x0A324655 # "UF2\n"
39
40
UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected
40
41
UF2_MAGIC_END = 0x0AB16F30 # Ditto
41
42
42
- families = {
43
- "SAMD21" : 0x68ED2B88 ,
44
- "SAMD51" : 0x55114460 ,
45
- "NRF52" : 0x1B57745F ,
46
- "STM32F1" : 0x5EE21072 ,
47
- "STM32F4" : 0x57755A57 ,
48
- "ATMEGA32" : 0x16573617 ,
49
- }
50
-
51
43
INFO_FILE = "/INFO_UF2.TXT"
52
44
53
45
appstartaddr = 0x2000
@@ -71,9 +63,14 @@ def is_hex(buf):
71
63
72
64
def convert_from_uf2 (buf ):
73
65
global appstartaddr
66
+ global familyid
74
67
numblocks = len (buf ) // 512
75
68
curraddr = None
76
- outp = b""
69
+ currfamilyid = None
70
+ families_found = {}
71
+ prev_flag = None
72
+ all_flags_same = True
73
+ outp = []
77
74
for blockno in range (numblocks ):
78
75
ptr = blockno * 512
79
76
block = buf [ptr : ptr + 512 ]
@@ -88,9 +85,13 @@ def convert_from_uf2(buf):
88
85
if datalen > 476 :
89
86
assert False , "Invalid UF2 data size at " + ptr
90
87
newaddr = hd [3 ]
91
- if curraddr == None :
92
- appstartaddr = newaddr
88
+ if (hd [2 ] & 0x2000 ) and (currfamilyid == None ):
89
+ currfamilyid = hd [7 ]
90
+ if curraddr == None or ((hd [2 ] & 0x2000 ) and hd [7 ] != currfamilyid ):
91
+ currfamilyid = hd [7 ]
93
92
curraddr = newaddr
93
+ if familyid == 0x0 or familyid == hd [7 ]:
94
+ appstartaddr = newaddr
94
95
padding = newaddr - curraddr
95
96
if padding < 0 :
96
97
assert False , "Block out of order at " + ptr
@@ -101,19 +102,53 @@ def convert_from_uf2(buf):
101
102
while padding > 0 :
102
103
padding -= 4
103
104
outp += b"\x00 \x00 \x00 \x00 "
104
- outp += block [32 : 32 + datalen ]
105
+ if familyid == 0x0 or ((hd [2 ] & 0x2000 ) and familyid == hd [7 ]):
106
+ outp .append (block [32 : 32 + datalen ])
105
107
curraddr = newaddr + datalen
106
- return outp
108
+ if hd [2 ] & 0x2000 :
109
+ if hd [7 ] in families_found .keys ():
110
+ if families_found [hd [7 ]] > newaddr :
111
+ families_found [hd [7 ]] = newaddr
112
+ else :
113
+ families_found [hd [7 ]] = newaddr
114
+ if prev_flag == None :
115
+ prev_flag = hd [2 ]
116
+ if prev_flag != hd [2 ]:
117
+ all_flags_same = False
118
+ if blockno == (numblocks - 1 ):
119
+ print ("--- UF2 File Header Info ---" )
120
+ families = load_families ()
121
+ for family_hex in families_found .keys ():
122
+ family_short_name = ""
123
+ for name , value in families .items ():
124
+ if value == family_hex :
125
+ family_short_name = name
126
+ print (
127
+ "Family ID is {:s}, hex value is 0x{:08x}" .format (
128
+ family_short_name , family_hex
129
+ )
130
+ )
131
+ print ("Target Address is 0x{:08x}" .format (families_found [family_hex ]))
132
+ if all_flags_same :
133
+ print ("All block flag values consistent, 0x{:04x}" .format (hd [2 ]))
134
+ else :
135
+ print ("Flags were not all the same" )
136
+ print ("----------------------------" )
137
+ if len (families_found ) > 1 and familyid == 0x0 :
138
+ outp = []
139
+ appstartaddr = 0x0
140
+ return b"" .join (outp )
107
141
108
142
109
143
def convert_to_carray (file_content ):
110
- outp = "const unsigned char bindata[] __attribute__((aligned(16))) = {"
144
+ outp = "const unsigned long bindata_len = %d;\n " % len (file_content )
145
+ outp += "const unsigned char bindata[] __attribute__((aligned(16))) = {"
111
146
for i in range (len (file_content )):
112
147
if i % 16 == 0 :
113
148
outp += "\n "
114
- outp += "0x%02x, " % ord ( file_content [i ])
149
+ outp += "0x%02x, " % file_content [i ]
115
150
outp += "\n };\n "
116
- return outp
151
+ return bytes ( outp , "utf-8" )
117
152
118
153
119
154
def convert_to_uf2 (file_content ):
@@ -122,7 +157,7 @@ def convert_to_uf2(file_content):
122
157
while len (datapadding ) < 512 - 256 - 32 - 4 :
123
158
datapadding += b"\x00 \x00 \x00 \x00 "
124
159
numblocks = (len (file_content ) + 255 ) // 256
125
- outp = b""
160
+ outp = []
126
161
for blockno in range (numblocks ):
127
162
ptr = 256 * blockno
128
163
chunk = file_content [ptr : ptr + 256 ]
@@ -144,8 +179,8 @@ def convert_to_uf2(file_content):
144
179
chunk += b"\x00 "
145
180
block = hd + chunk + datapadding + struct .pack (b"<I" , UF2_MAGIC_END )
146
181
assert len (block ) == 512
147
- outp += block
148
- return outp
182
+ outp . append ( block )
183
+ return b"" . join ( outp )
149
184
150
185
151
186
class Block :
@@ -195,11 +230,10 @@ def convert_from_hex_to_uf2(buf):
195
230
upper = ((rec [4 ] << 8 ) | rec [5 ]) << 16
196
231
elif tp == 2 :
197
232
upper = ((rec [4 ] << 8 ) | rec [5 ]) << 4
198
- assert (upper & 0xFFFF ) == 0
199
233
elif tp == 1 :
200
234
break
201
235
elif tp == 0 :
202
- addr = upper | ( rec [1 ] << 8 ) | rec [2 ]
236
+ addr = upper + (( rec [1 ] << 8 ) | rec [2 ])
203
237
if appstartaddr == None :
204
238
appstartaddr = addr
205
239
i = 4
@@ -217,6 +251,10 @@ def convert_from_hex_to_uf2(buf):
217
251
return resfile
218
252
219
253
254
+ def to_str (b ):
255
+ return b .decode ("utf-8" )
256
+
257
+
220
258
def get_drives ():
221
259
drives = []
222
260
if sys .platform == "win32" :
@@ -232,7 +270,7 @@ def get_drives():
232
270
"DriveType" ,
233
271
]
234
272
)
235
- for line in r .split ("\n " ):
273
+ for line in to_str ( r ) .split ("\n " ):
236
274
words = re .split ("\s+" , line )
237
275
if len (words ) >= 3 and words [1 ] == "2" and words [2 ] == "FAT" :
238
276
drives .append (words [0 ])
@@ -270,7 +308,23 @@ def list_drives():
270
308
def write_file (name , buf ):
271
309
with open (name , "wb" ) as f :
272
310
f .write (buf )
273
- print ("Wrote %d bytes to %s." % (len (buf ), name ))
311
+ print ("Wrote %d bytes to %s" % (len (buf ), name ))
312
+
313
+
314
+ def load_families ():
315
+ # The expectation is that the `uf2families.json` file is in the same
316
+ # directory as this script. Make a path that works using `__file__`
317
+ # which contains the full path to this script.
318
+ filename = "uf2families.json"
319
+ pathname = os .path .join (os .path .dirname (os .path .abspath (__file__ )), filename )
320
+ with open (pathname ) as f :
321
+ raw_families = json .load (f )
322
+
323
+ families = {}
324
+ for family in raw_families :
325
+ families [family ["short_name" ]] = int (family ["id" ], 0 )
326
+
327
+ return families
274
328
275
329
276
330
def main ():
@@ -303,6 +357,7 @@ def error(msg):
303
357
parser .add_argument ("-d" , "--device" , dest = "device_path" , help = "select a device path to flash" )
304
358
parser .add_argument ("-l" , "--list" , action = "store_true" , help = "list connected devices" )
305
359
parser .add_argument ("-c" , "--convert" , action = "store_true" , help = "do not flash, just convert" )
360
+ parser .add_argument ("-D" , "--deploy" , action = "store_true" , help = "just flash, do not convert" )
306
361
parser .add_argument (
307
362
"-f" ,
308
363
"--family" ,
@@ -314,9 +369,17 @@ def error(msg):
314
369
parser .add_argument (
315
370
"-C" , "--carray" , action = "store_true" , help = "convert binary file to a C array, not UF2"
316
371
)
372
+ parser .add_argument (
373
+ "-i" ,
374
+ "--info" ,
375
+ action = "store_true" ,
376
+ help = "display header information from UF2, do not convert" ,
377
+ )
317
378
args = parser .parse_args ()
318
379
appstartaddr = int (args .base , 0 )
319
380
381
+ families = load_families ()
382
+
320
383
if args .family .upper () in families :
321
384
familyid = families [args .family .upper ()]
322
385
else :
@@ -334,21 +397,27 @@ def error(msg):
334
397
inpbuf = f .read ()
335
398
from_uf2 = is_uf2 (inpbuf )
336
399
ext = "uf2"
337
- if from_uf2 :
400
+ if args .deploy :
401
+ outbuf = inpbuf
402
+ elif from_uf2 and not args .info :
338
403
outbuf = convert_from_uf2 (inpbuf )
339
404
ext = "bin"
405
+ elif from_uf2 and args .info :
406
+ outbuf = ""
407
+ convert_from_uf2 (inpbuf )
340
408
elif is_hex (inpbuf ):
341
409
outbuf = convert_from_hex_to_uf2 (inpbuf .decode ("utf-8" ))
342
410
elif args .carray :
343
411
outbuf = convert_to_carray (inpbuf )
344
412
ext = "h"
345
413
else :
346
414
outbuf = convert_to_uf2 (inpbuf )
347
- print (
348
- "Converting to %s, output size: %d, start address: 0x%x"
349
- % (ext , len (outbuf ), appstartaddr )
350
- )
351
- if args .convert :
415
+ if not args .deploy and not args .info :
416
+ print (
417
+ "Converted to %s, output size: %d, start address: 0x%x"
418
+ % (ext , len (outbuf ), appstartaddr )
419
+ )
420
+ if args .convert or ext != "uf2" :
352
421
drives = []
353
422
if args .output == None :
354
423
args .output = "flash." + ext
0 commit comments