Skip to content

Commit a3c7bc9

Browse files
committed
Experiment with OTA support, better mbed upload
1 parent 5bb8311 commit a3c7bc9

File tree

1 file changed

+124
-5
lines changed

1 file changed

+124
-5
lines changed

builder/main.py

Lines changed: 124 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import sys
1616
from platform import system
17-
from os import makedirs
17+
from os import makedirs, remove
1818
from os.path import isdir, join, isfile
1919
import re
2020
import time
@@ -184,6 +184,22 @@ def generate_uf2(target, source, env):
184184
"$TARGET"
185185
]), "Building $TARGET"),
186186
suffix=".hex"
187+
),
188+
BinToSignedBin=Builder(
189+
action=env.VerboseAction(" ".join([
190+
'"$PYTHONEXE" "%s"' % join(
191+
platform.get_package_dir("framework-arduinopico") or "",
192+
"tools", "signing.py"),
193+
"--mode",
194+
"sign",
195+
"--privatekey",
196+
'"%s"' % join("$PROJECT_SRC_DIR", "private.key"),
197+
"--bin",
198+
"$SOURCES",
199+
"--out",
200+
"$TARGET"
201+
]), "Building $TARGET"),
202+
suffix=".bin.signed"
187203
)
188204
)
189205
)
@@ -209,14 +225,35 @@ def generate_uf2(target, source, env):
209225
)
210226
)
211227

228+
is_arduino_pico_build = env.BoardConfig().get("build.core", "arduino") == "earlephilhower" and "arduino" in env.get("PIOFRAMEWORK")
229+
target_gen_header = None
230+
if is_arduino_pico_build:
231+
header_file = join(env.subst("$BUILD_DIR"), "core", "Updater_Signing.h")
232+
env.Prepend(CFLAGS=['-I"%s"' % join("$BUILD_DIR", "core")])
233+
signing_header_cmd = env.Command(
234+
join("$BUILD_DIR", "core", "Updater_Signing.h"), # $TARGET
235+
join("$PROJECT_SRC_DIR", "public.key"), # $SOURCE
236+
env.VerboseAction(" ".join([
237+
'"$PYTHONEXE" "%s"' % join(
238+
platform.get_package_dir("framework-arduinopico"), "tools", "signing.py"),
239+
"--mode", "header",
240+
"--publickey", '"$SOURCE"',
241+
"--out", "$TARGET"
242+
]), "Generating $TARGET")
243+
)
244+
target_gen_header = env.Alias("gen_header", signing_header_cmd)
245+
AlwaysBuild(target_gen_header)
246+
212247
#
213248
# Target: Build executable and linkable firmware
214249
#
215250

216251
target_elf = None
252+
target_signed_bin = None
217253
if "nobuild" in COMMAND_LINE_TARGETS:
218254
target_elf = join("$BUILD_DIR", "${PROGNAME}.elf")
219255
target_firm = join("$BUILD_DIR", "${PROGNAME}.bin")
256+
target_firm = join("$BUILD_DIR", "${PROGNAME}.bin.signed")
220257
else:
221258
target_elf = env.BuildProgram()
222259
if set(["buildfs", "uploadfs"]) & set(COMMAND_LINE_TARGETS):
@@ -225,11 +262,14 @@ def generate_uf2(target, source, env):
225262
AlwaysBuild(target_firm)
226263
else:
227264
target_firm = env.ElfToBin(join("$BUILD_DIR", "${PROGNAME}"), target_elf)
265+
if is_arduino_pico_build:
266+
target_signed_bin = env.BinToSignedBin(join("$BUILD_DIR", "${PROGNAME}"), target_firm)
267+
env.Depends(target_signed_bin, "checkprogsize")
228268
env.Depends(target_firm, "checkprogsize")
229269

230270
env.AddPlatformTarget("buildfs", target_firm, target_firm, "Build Filesystem Image")
231271
AlwaysBuild(env.Alias("nobuild", target_firm))
232-
target_buildprog = env.Alias("buildprog", target_firm, target_firm)
272+
target_buildprog = env.Alias("buildprog", [target_firm, target_signed_bin], target_firm)
233273

234274
env.AddPostAction(
235275
target_elf, env.VerboseAction(generate_uf2, "Generating UF2 image")
@@ -284,14 +324,93 @@ def UploadUF2ToDisk(target, source, env):
284324
copyfile(fpath, join(env.subst("$UPLOAD_PORT"), "%s.%s" % (progname, ext)))
285325
print(
286326
"Firmware has been successfully uploaded.\n"
287-
"(Some boards may require manual hard reset)"
288327
)
289328

329+
def TryResetPico(target, source, env):
330+
upload_options = {}
331+
if "BOARD" in env:
332+
upload_options = env.BoardConfig().get("upload", {})
333+
ports = list_serial_ports()
334+
if len(ports) != 0:
335+
last_port = ports[-1]["port"]
336+
if upload_options.get("use_1200bps_touch", False):
337+
env.TouchSerialPort(last_port, 1200)
338+
time.sleep(2.0)
339+
340+
from platformio.device.list.util import list_logical_devices
341+
from platformio.device.finder import is_pattern_port
342+
from fnmatch import fnmatch
343+
344+
def find_rpi_disk(initial_port):
345+
msdlabels = ("RPI-RP2")
346+
item:str
347+
for item in list_logical_devices():
348+
if item["path"].startswith("/net"):
349+
continue
350+
if (
351+
initial_port
352+
and is_pattern_port(initial_port)
353+
and not fnmatch(item["path"], initial_port)
354+
):
355+
continue
356+
mbed_pages = [join(item["path"], n) for n in ("INDEX.HTM", "INFO_UF2.TXT")]
357+
if any(isfile(p) for p in mbed_pages):
358+
return item["path"]
359+
if item["name"] and any(l in item["name"].lower() for l in msdlabels):
360+
return item["path"]
361+
return None
362+
363+
def AutodetectPicoDisk(target, source, env):
364+
initial_port = env.subst("$UPLOAD_PORT")
365+
if initial_port and not is_pattern_port(initial_port):
366+
print(env.subst("Using manually specified: $UPLOAD_PORT"))
367+
return
368+
369+
if upload_protocol == "mbed":
370+
env.Replace(UPLOAD_PORT=find_rpi_disk(initial_port))
371+
372+
if env.subst("$UPLOAD_PORT"):
373+
print(env.subst("Auto-detected: $UPLOAD_PORT"))
374+
else:
375+
sys.stderr.write(
376+
"Error: Please specify `upload_port` for environment or use "
377+
"global `--upload-port` option.\n"
378+
"For some development platforms it can be a USB flash "
379+
"drive (i.e. /media/<user>/<device name>)\n"
380+
)
381+
env.Exit(1)
382+
290383
if upload_protocol == "mbed":
291384
upload_actions = [
292-
env.VerboseAction(env.AutodetectUploadPort, "Looking for upload disk..."),
385+
env.VerboseAction(TryResetPico, "Trying to reset Pico into bootloader mode..."),
386+
env.VerboseAction(AutodetectPicoDisk, "Looking for upload disk..."),
293387
env.VerboseAction(UploadUF2ToDisk, "Uploading $SOURCE")
294388
]
389+
elif upload_protocol == "espota":
390+
if not env.subst("$UPLOAD_PORT"):
391+
sys.stderr.write(
392+
"Error: Please specify IP address or host name of ESP device "
393+
"using `upload_port` for build environment or use "
394+
"global `--upload-port` option.\n"
395+
"See https://docs.platformio.org/page/platforms/"
396+
"espressif8266.html#over-the-air-ota-update\n")
397+
env.Replace(
398+
UPLOADER=join(
399+
platform.get_package_dir("framework-arduinopico") or "",
400+
"tools", "espota.py"),
401+
UPLOADERFLAGS=["--debug", "--progress", "-i", "$UPLOAD_PORT", "-p", "2040"],
402+
UPLOADCMD='"$PYTHONEXE" "$UPLOADER" $UPLOADERFLAGS -f $SOURCE'
403+
)
404+
if "uploadfs" in COMMAND_LINE_TARGETS:
405+
env.Append(UPLOADERFLAGS=["-s"])
406+
else:
407+
# check if we have a .bin.signed file available.
408+
# since the file may not be build yet, we try to predict that we will
409+
# have that file if they private signing key exists.
410+
if isfile(join(env.subst("$PROJECT_SRC_DIR"), "private.key")):
411+
sys.stdout.write("Using signed OTA update file.")
412+
upload_source = target_signed_bin
413+
upload_actions = [env.VerboseAction("$UPLOADCMD", "Uploading $SOURCE")]
295414
elif upload_protocol == "picotool":
296415
env.Replace(
297416
UPLOADER=join(platform.get_package_dir("tool-rp2040tools") or "", "rp2040load"),
@@ -406,4 +525,4 @@ def _jlink_cmd_script(env, source):
406525
# Default targets
407526
#
408527

409-
Default([target_buildprog, target_size])
528+
Default([target_gen_header, target_buildprog, target_size])

0 commit comments

Comments
 (0)