14
14
15
15
import sys
16
16
from platform import system
17
- from os import makedirs
17
+ from os import makedirs , remove
18
18
from os .path import isdir , join , isfile
19
19
import re
20
20
import time
@@ -184,6 +184,22 @@ def generate_uf2(target, source, env):
184
184
"$TARGET"
185
185
]), "Building $TARGET" ),
186
186
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"
187
203
)
188
204
)
189
205
)
@@ -209,14 +225,35 @@ def generate_uf2(target, source, env):
209
225
)
210
226
)
211
227
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
+
212
247
#
213
248
# Target: Build executable and linkable firmware
214
249
#
215
250
216
251
target_elf = None
252
+ target_signed_bin = None
217
253
if "nobuild" in COMMAND_LINE_TARGETS :
218
254
target_elf = join ("$BUILD_DIR" , "${PROGNAME}.elf" )
219
255
target_firm = join ("$BUILD_DIR" , "${PROGNAME}.bin" )
256
+ target_firm = join ("$BUILD_DIR" , "${PROGNAME}.bin.signed" )
220
257
else :
221
258
target_elf = env .BuildProgram ()
222
259
if set (["buildfs" , "uploadfs" ]) & set (COMMAND_LINE_TARGETS ):
@@ -225,11 +262,14 @@ def generate_uf2(target, source, env):
225
262
AlwaysBuild (target_firm )
226
263
else :
227
264
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" )
228
268
env .Depends (target_firm , "checkprogsize" )
229
269
230
270
env .AddPlatformTarget ("buildfs" , target_firm , target_firm , "Build Filesystem Image" )
231
271
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 )
233
273
234
274
env .AddPostAction (
235
275
target_elf , env .VerboseAction (generate_uf2 , "Generating UF2 image" )
@@ -284,14 +324,93 @@ def UploadUF2ToDisk(target, source, env):
284
324
copyfile (fpath , join (env .subst ("$UPLOAD_PORT" ), "%s.%s" % (progname , ext )))
285
325
print (
286
326
"Firmware has been successfully uploaded.\n "
287
- "(Some boards may require manual hard reset)"
288
327
)
289
328
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
+
290
383
if upload_protocol == "mbed" :
291
384
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..." ),
293
387
env .VerboseAction (UploadUF2ToDisk , "Uploading $SOURCE" )
294
388
]
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" )]
295
414
elif upload_protocol == "picotool" :
296
415
env .Replace (
297
416
UPLOADER = join (platform .get_package_dir ("tool-rp2040tools" ) or "" , "rp2040load" ),
@@ -406,4 +525,4 @@ def _jlink_cmd_script(env, source):
406
525
# Default targets
407
526
#
408
527
409
- Default ([target_buildprog , target_size ])
528
+ Default ([target_gen_header , target_buildprog , target_size ])
0 commit comments