Skip to content

Commit 90fac68

Browse files
authored
Merge pull request #1 from brentru/generate-uf2
Generate uf2
2 parents 9c244d6 + fc374d6 commit 90fac68

File tree

1 file changed

+126
-76
lines changed

1 file changed

+126
-76
lines changed

Diff for: build_platform.py

+126-76
Original file line numberDiff line numberDiff line change
@@ -50,86 +50,87 @@
5050

5151
ALL_PLATFORMS={
5252
# classic Arduino AVR
53-
"uno" : "arduino:avr:uno",
54-
"leonardo" : "arduino:avr:leonardo",
55-
"mega2560" : "arduino:avr:mega:cpu=atmega2560",
53+
"uno" : ["arduino:avr:uno", None],
54+
"leonardo" : ["arduino:avr:leonardo", None],
55+
"mega2560" : ["arduino:avr:mega:cpu=atmega2560", None],
5656
# Arduino SAMD
57-
"zero" : "arduino:samd:arduino_zero_native",
58-
"cpx" : "arduino:samd:adafruit_circuitplayground_m0",
57+
"zero" : ["arduino:samd:arduino_zero_native", "0x68ed2b88"],
58+
"cpx" : ["arduino:samd:adafruit_circuitplayground_m0", "0x68ed2b88"],
5959
# Espressif
60-
"esp8266" : "esp8266:esp8266:huzzah:eesz=4M3M,xtal=80",
61-
"esp32" : "esp32:esp32:featheresp32:FlashFreq=80",
62-
"magtag" : "esp32:esp32:adafruit_magtag29_esp32s2",
63-
"funhouse" : "esp32:esp32:adafruit_funhouse_esp32s2",
64-
"metroesp32s2" : "esp32:esp32:adafruit_metro_esp32s2",
60+
"esp8266" : ["esp8266:esp8266:huzzah:eesz=4M3M,xtal=80", "0x7eab61ed"],
61+
"esp32" : ["esp32:esp32:featheresp32:FlashFreq=80", "0x1c5f21b0"],
62+
"magtag" : ["esp32:esp32:adafruit_magtag29_esp32s2", "0xbfdd4eee"],
63+
"funhouse" : ["esp32:esp32:adafruit_funhouse_esp32s2", "0xbfdd4eee"],
64+
"metroesp32s2" : ["esp32:esp32:adafruit_metro_esp32s2", "0xbfdd4eee"],
6565
# Adafruit AVR
66-
"trinket_3v" : "adafruit:avr:trinket3",
67-
"trinket_5v" : "adafruit:avr:trinket5",
68-
"protrinket_3v" : "adafruit:avr:protrinket3",
69-
"protrinket_5v" : "adafruit:avr:protrinket5",
70-
"gemma" : "adafruit:avr:gemma",
71-
"flora" : "adafruit:avr:flora8",
72-
"feather32u4" : "adafruit:avr:feather32u4",
73-
"cpc" : "arduino:avr:circuitplay32u4cat",
66+
"trinket_3v" : ["adafruit:avr:trinket3", None],
67+
"trinket_5v" : ["adafruit:avr:trinket5", None],
68+
"protrinket_3v" : ["adafruit:avr:protrinket3", None],
69+
"protrinket_5v" : ["adafruit:avr:protrinket5", None],
70+
"gemma" : ["adafruit:avr:gemma", None],
71+
"flora" : ["adafruit:avr:flora8", None],
72+
"feather32u4" : ["adafruit:avr:feather32u4", None],
73+
"cpc" : ["arduino:avr:circuitplay32u4cat", None],
7474
# Adafruit SAMD
75-
"gemma_m0" : "adafruit:samd:adafruit_gemma_m0",
76-
"trinket_m0" : "adafruit:samd:adafruit_trinket_m0",
77-
"feather_m0_express" : "adafruit:samd:adafruit_feather_m0_express",
78-
"feather_m4_can" : "adafruit:samd:adafruit_feather_m4_can:speed=120",
79-
"feather_m4_can_tinyusb" : "adafruit:samd:adafruit_feather_m4_can:speed=120,usbstack=tinyusb",
80-
"metro_m0" : "adafruit:samd:adafruit_metro_m0",
81-
"metro_m0_tinyusb" : "adafruit:samd:adafruit_metro_m0:usbstack=tinyusb",
82-
"metro_m4" : "adafruit:samd:adafruit_metro_m4:speed=120",
83-
"metro_m4_tinyusb" : "adafruit:samd:adafruit_metro_m4:speed=120,usbstack=tinyusb",
84-
"metro_m4_airliftlite" : "adafruit:samd:adafruit_metro_m4_airliftlite:speed=120",
85-
"metro_m4_airliftlite_tinyusb" : "adafruit:samd:adafruit_metro_m4_airliftlite:speed=120,usbstack=tinyusb",
86-
"pybadge" : "adafruit:samd:adafruit_pybadge_m4:speed=120",
87-
"pybadge_tinyusb" : "adafruit:samd:adafruit_pybadge_m4:speed=120,usbstack=tinyusb",
88-
"pygamer" : "adafruit:samd:adafruit_pygamer_m4:speed=120",
75+
"gemma_m0" : ["adafruit:samd:adafruit_gemma_m0", "0x68ed2b88"],
76+
"trinket_m0" : ["adafruit:samd:adafruit_trinket_m0", "0x68ed2b88"],
77+
"feather_m0_express" : ["adafruit:samd:adafruit_feather_m0_express", "0x68ed2b88"],
78+
"feather_m4_can" : ["adafruit:samd:adafruit_feather_m4_can:speed=120", "0x68ed2b88"],
79+
"feather_m4_can_tinyusb" : ["adafruit:samd:adafruit_feather_m4_can:speed=120,usbstack=tinyusb", "0x68ed2b88"],
80+
"metro_m0" : ["adafruit:samd:adafruit_metro_m0", "0x68ed2b88"],
81+
"metro_m0_tinyusb" : ["adafruit:samd:adafruit_metro_m0:usbstack=tinyusb", "0x68ed2b88"],
82+
"metro_m4" : ["adafruit:samd:adafruit_metro_m4:speed=120", "0x55114460"],
83+
"metro_m4_tinyusb" : ["adafruit:samd:adafruit_metro_m4:speed=120,usbstack=tinyusb", "0x55114460"],
84+
"metro_m4_airliftlite" : ["adafruit:samd:adafruit_metro_m4_airliftlite:speed=120", "0x55114460"],
85+
"metro_m4_airliftlite_tinyusb" : ["adafruit:samd:adafruit_metro_m4_airliftlite:speed=120,usbstack=tinyusb", "0x55114460"],
86+
"pybadge" : ["adafruit:samd:adafruit_pybadge_m4:speed=120", "0x55114460"],
87+
"pybadge_tinyusb" : ["adafruit:samd:adafruit_pybadge_m4:speed=120,usbstack=tinyusb", "0x55114460"],
88+
"pygamer" : ["adafruit:samd:adafruit_pygamer_m4:speed=120", "0x55114460"],
8989
"hallowing_m0" : "adafruit:samd:adafruit_hallowing",
90-
"hallowing_m4" : "adafruit:samd:adafruit_hallowing_m4:speed=120",
91-
"hallowing_m4_tinyusb" : "adafruit:samd:adafruit_hallowing_m4:speed=120,usbstack=tinyusb",
92-
"neotrellis_m4" : "adafruit:samd:adafruit_trellis_m4:speed=120",
93-
"monster_m4sk" : "adafruit:samd:adafruit_monster_m4sk:speed=120",
94-
"monster_m4sk_tinyusb" : "adafruit:samd:adafruit_monster_m4sk:speed=120,usbstack=tinyusb",
95-
"pyportal" : "adafruit:samd:adafruit_pyportal_m4:speed=120",
96-
"pyportal_tinyusb" : "adafruit:samd:adafruit_pyportal_m4:speed=120,usbstack=tinyusb",
97-
"pyportal_titano" : "adafruit:samd:adafruit_pyportal_m4_titano:speed=120",
98-
"pyportal_titano_tinyusb" : "adafruit:samd:adafruit_pyportal_m4_titano:speed=120,usbstack=tinyusb",
99-
"cpx_ada" : "adafruit:samd:adafruit_circuitplayground_m0",
100-
"grand_central" : "adafruit:samd:adafruit_grandcentral_m4:speed=120",
101-
"grand_central_tinyusb" : "adafruit:samd:adafruit_grandcentral_m4:speed=120,usbstack=tinyusb",
102-
"matrixportal" : "adafruit:samd:adafruit_matrixportal_m4:speed=120",
103-
"matrixportal_tinyusb" : "adafruit:samd:adafruit_matrixportal_m4:speed=120,usbstack=tinyusb",
104-
"neotrinkey_m0" : "adafruit:samd:adafruit_neotrinkey_m0",
105-
"rotarytrinkey_m0" : "adafruit:samd:adafruit_rotarytrinkey_m0",
106-
"neokeytrinkey_m0" : "adafruit:samd:adafruit_neokeytrinkey_m0",
107-
"slidetrinkey_m0" : "adafruit:samd:adafruit_slidetrinkey_m0",
108-
"proxlighttrinkey_m0" : "adafruit:samd:adafruit_proxlighttrinkey_m0",
90+
"hallowing_m4" : ["adafruit:samd:adafruit_hallowing_m4:speed=120", "0x55114460"],
91+
"hallowing_m4_tinyusb" : ["adafruit:samd:adafruit_hallowing_m4:speed=120,usbstack=tinyusb", "0x55114460"],
92+
"neotrellis_m4" : ["adafruit:samd:adafruit_trellis_m4:speed=120", "0x55114460"],
93+
"monster_m4sk" : ["adafruit:samd:adafruit_monster_m4sk:speed=120", "0x55114460"],
94+
"monster_m4sk_tinyusb" : ["adafruit:samd:adafruit_monster_m4sk:speed=120,usbstack=tinyusb", "0x55114460"],
95+
"pyportal" : ["adafruit:samd:adafruit_pyportal_m4:speed=120", "0x55114460"],
96+
"pyportal_tinyusb" : ["adafruit:samd:adafruit_pyportal_m4:speed=120,usbstack=tinyusb", "0x55114460"],
97+
"pyportal_titano" : ["adafruit:samd:adafruit_pyportal_m4_titano:speed=120", "0x55114460"],
98+
"pyportal_titano_tinyusb" : ["adafruit:samd:adafruit_pyportal_m4_titano:speed=120,usbstack=tinyusb", "0x55114460"],
99+
"cpx_ada" : ["adafruit:samd:adafruit_circuitplayground_m0", "0x68ed2b88"],
100+
"grand_central" : ["adafruit:samd:adafruit_grandcentral_m4:speed=120", "0x55114460"],
101+
"grand_central_tinyusb" : ["adafruit:samd:adafruit_grandcentral_m4:speed=120,usbstack=tinyusb", "0x55114460"],
102+
"matrixportal" : ["adafruit:samd:adafruit_matrixportal_m4:speed=120", "0x55114460"],
103+
"matrixportal_tinyusb" : ["adafruit:samd:adafruit_matrixportal_m4:speed=120,usbstack=tinyusb", "0x55114460"],
104+
"neotrinkey_m0" : ["adafruit:samd:adafruit_neotrinkey_m0", "0x68ed2b88"],
105+
"rotarytrinkey_m0" : ["adafruit:samd:adafruit_rotarytrinkey_m0", "0x68ed2b88"],
106+
"neokeytrinkey_m0" : ["adafruit:samd:adafruit_neokeytrinkey_m0", "0x68ed2b88"],
107+
"slidetrinkey_m0" : ["adafruit:samd:adafruit_slidetrinkey_m0", "0x68ed2b88"],
108+
"proxlighttrinkey_m0" : ["adafruit:samd:adafruit_proxlighttrinkey_m0", "0x68ed2b88"],
109109
# Arduino nRF
110-
"microbit" : "sandeepmistry:nRF5:BBCmicrobit:softdevice=s110",
110+
"microbit" : ["sandeepmistry:nRF5:BBCmicrobit:softdevice=s110", None],
111111
# Adafruit nRF
112-
"nrf52832" : "adafruit:nrf52:feather52832:softdevice=s132v6,debug=l0",
113-
"nrf52840" : "adafruit:nrf52:feather52840:softdevice=s140v6,debug=l0",
114-
"cpb" : "adafruit:nrf52:cplaynrf52840:softdevice=s140v6,debug=l0",
115-
"clue" : "adafruit:nrf52:cluenrf52840:softdevice=s140v6,debug=l0",
112+
"nrf52832" : ["adafruit:nrf52:feather52832:softdevice=s132v6,debug=l0", None],
113+
"nrf52840" : ["adafruit:nrf52:feather52840:softdevice=s140v6,debug=l0", "0xada52840"],
114+
"cpb" : ["adafruit:nrf52:cplaynrf52840:softdevice=s140v6,debug=l0", "0xada52840"],
115+
"clue" : ["adafruit:nrf52:cluenrf52840:softdevice=s140v6,debug=l0", "0xada52840"],
116116
# RP2040 (Philhower)
117-
"pico_rp2040" : "rp2040:rp2040:rpipico:freq=125,flash=2097152_0",
118-
"pico_rp2040_tinyusb" : "rp2040:rp2040:rpipico:flash=2097152_0,freq=125,dbgport=Disabled,dbglvl=None,usbstack=tinyusb",
119-
"feather_rp2040" : "rp2040:rp2040:adafruitfeather:freq=125,flash=8388608_0",
120-
"feather_rp2040_tinyusb" : "rp2040:rp2040:adafruit_feather:flash=8388608_0,freq=125,dbgport=Disabled,dbglvl=None,usbstack=tinyusb",
121-
"qt2040_trinkey" : "rp2040:rp2040:adafruit_trinkeyrp2040qt:freq=125,flash=8388608_0",
122-
"qt2040_trinkey_tinyusb" : "rp2040:rp2040:adafruit_trinkeyrp2040qt:flash=8388608_0,freq=125,dbgport=Disabled,dbglvl=None,usbstack=tinyusb",
117+
"pico_rp2040" : ["rp2040:rp2040:rpipico:freq=125,flash=2097152_0", "0xe48bff56"],
118+
"pico_rp2040_tinyusb" : ["rp2040:rp2040:rpipico:flash=2097152_0,freq=125,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56"],
119+
"feather_rp2040" : ["rp2040:rp2040:adafruitfeather:freq=125,flash=8388608_0", "0xe48bff56"],
120+
"feather_rp2040_tinyusb" : ["rp2040:rp2040:adafruit_feather:flash=8388608_0,freq=125,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56"],
121+
"qt2040_trinkey" : ["rp2040:rp2040:adafruit_trinkeyrp2040qt:freq=125,flash=8388608_0", "0xe48bff56"],
122+
"qt2040_trinkey_tinyusb" : ["rp2040:rp2040:adafruit_trinkeyrp2040qt:flash=8388608_0,freq=125,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56"],
123123
# Attiny8xy (SpenceKonde)
124-
"attiny817" : "megaTinyCore:megaavr:atxy7:chip=817",
125-
"attiny816" : "megaTinyCore:megaavr:atxy6:chip=816",
126-
"attiny807" : "megaTinyCore:megaavr:atxy7:chip=807",
127-
"attiny806" : "megaTinyCore:megaavr:atxy6:chip=806",
124+
"attiny817" : ["megaTinyCore:megaavr:atxy7:chip=817", None],
125+
"attiny816" : ["megaTinyCore:megaavr:atxy6:chip=816", None],
126+
"attiny807" : ["megaTinyCore:megaavr:atxy7:chip=807", None],
127+
"attiny806" : ["megaTinyCore:megaavr:atxy6:chip=806", None],
128128
# groupings
129129
"main_platforms" : ("uno", "leonardo", "mega2560", "zero",
130130
"esp8266", "esp32", "metro_m4", "trinket_m0"),
131131
"arcada_platforms" : ("pybadge", "pygamer", "hallowing_m4",
132132
"cpb", "cpx_ada"),
133+
"wippersnapper_platforms" : ("metro_m4_airliftlite_tinyusb", "pyportal_tinyusb"),
133134
"rp2040_platforms" : ("pico_rp2040", "feather_rp2040")
134135
}
135136

@@ -211,12 +212,38 @@ def run_or_die(cmd, error):
211212

212213
print("Libraries installed: ", glob.glob(os.environ['HOME']+'/Arduino/libraries/*'))
213214

214-
# link our library folder to the arduino libraries folder
215-
if not IS_LEARNING_SYS:
216-
try:
217-
os.symlink(BUILD_DIR, os.environ['HOME']+'/Arduino/libraries/' + os.path.basename(BUILD_DIR))
218-
except FileExistsError:
219-
pass
215+
################################ UF2 Utils.
216+
217+
def glob1(pattern):
218+
result = glob.glob(pattern)
219+
if len(result) != 1:
220+
raise RuntimeError(f"Required pattern {pattern} to match exactly 1 file, got {result}")
221+
return result[0]
222+
223+
def generate_uf2(example_path):
224+
"""Generates a .uf2 file from a .bin or .hex file.
225+
:param str example_path: A path to the compiled .bin or .hex file.
226+
"""
227+
if ALL_PLATFORMS[platform][1] == None:
228+
return False
229+
# Convert .hex to .uf2
230+
family_id = ALL_PLATFORMS[platform][1]
231+
cli_build_path = "build/*.*." + fqbn.split(':')[2] + "/*.hex"
232+
input_file = glob1(os.path.join(example_path, cli_build_path))
233+
output_file = os.path.splitext(input_file)[0] + ".uf2"
234+
cmd = ['python3', 'uf2conv.py', input_file, '-c', '-f', family_id, '-o', output_file]
235+
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
236+
r = proc.wait(timeout=60)
237+
out = proc.stdout.read()
238+
err = proc.stderr.read()
239+
if r == 0 and not err:
240+
ColorPrint.print_pass(CHECK)
241+
else:
242+
ColorPrint.print_fail(CROSS)
243+
ColorPrint.print_fail(out.decode("utf-8"))
244+
ColorPrint.print_fail(err.decode("utf-8"))
245+
return False
246+
return True
220247

221248
################################ Test platforms
222249
platforms = []
@@ -225,9 +252,9 @@ def run_or_die(cmd, error):
225252
# expand groups:
226253
for arg in sys.argv[1:]:
227254
platform = ALL_PLATFORMS.get(arg, None)
228-
if isinstance(platform, str):
255+
if isinstance(platform, list):
229256
platforms.append(arg)
230-
elif isinstance(platform, collections.abc.Iterable):
257+
elif isinstance(platform, tuple):
231258
for p in platform:
232259
platforms.append(p)
233260
else:
@@ -248,15 +275,35 @@ def test_examples_in_folder(folderpath):
248275
# check if we should SKIP
249276
skipfilename = folderpath+"/."+platform+".test.skip"
250277
onlyfilename = folderpath+"/."+platform+".test.only"
278+
# check if we should GENERATE UF2
279+
gen_file_name = folderpath+"/."+platform+".generate"
251280
if os.path.exists(skipfilename):
252281
ColorPrint.print_warn("skipping")
253282
continue
254283
if glob.glob(folderpath+"/.*.test.only") and not os.path.exists(onlyfilename):
255284
ColorPrint.print_warn("skipping")
256285
continue
286+
if os.path.exists(gen_file_name):
287+
ColorPrint.print_info("Generating UF2 after compile.")
288+
# Download uf2conv.py and dependency if we don't already have it
289+
cmd = "wget -nc --no-check-certificate http://raw.githubusercontent.com/microsoft/uf2/master/utils/uf2families.json https://raw.githubusercontent.com/microsoft/uf2/master/utils/uf2conv.py"
290+
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
291+
r = proc.wait(timeout=60)
292+
out = proc.stdout.read()
293+
if r != 0:
294+
ColorPrint.print_fail("Failed to download UF2 Utils!")
295+
ColorPrint.print_fail(out.decode("utf-8"))
296+
ColorPrint.print_fail(err.decode("utf-8"))
297+
continue
298+
# Create a uf2 directory if doesn't exist
299+
if not os.path.isdir("uf2"):
300+
os.mkdir("uf2")
257301

258302
if BUILD_WARN:
259-
cmd = ['arduino-cli', 'compile', '--warnings', 'all', '--fqbn', fqbn, examplepath]
303+
if os.path.exists(gen_file_name):
304+
cmd = ['arduino-cli', 'compile', '--warnings', 'all', '--fqbn', fqbn, '-e', examplepath]
305+
else:
306+
cmd = ['arduino-cli', 'compile', '--warnings', 'all', '--fqbn', fqbn, examplepath]
260307
else:
261308
cmd = ['arduino-cli', 'compile', '--warnings', 'none', '--export-binaries', '--fqbn', fqbn, examplepath]
262309
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
@@ -269,6 +316,9 @@ def test_examples_in_folder(folderpath):
269316
if err:
270317
# also print out warning message
271318
ColorPrint.print_fail(err.decode("utf-8"))
319+
if os.path.exists(gen_file_name):
320+
ColorPrint.print_info("Generating UF2...")
321+
success = generate_uf2(folderpath)
272322
else:
273323
ColorPrint.print_fail(CROSS)
274324
ColorPrint.print_fail(out.decode("utf-8"))
@@ -315,7 +365,7 @@ def test_examples_in_learningrepo(folderpath):
315365

316366

317367
for platform in platforms:
318-
fqbn = ALL_PLATFORMS[platform]
368+
fqbn = ALL_PLATFORMS[platform][0]
319369
print('#'*80)
320370
ColorPrint.print_info("SWITCHING TO "+fqbn)
321371
install_platform(":".join(fqbn.split(':', 2)[0:2])) # take only first two elements

0 commit comments

Comments
 (0)