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,30 @@ 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
+ if is_arduino_pico_build :
230
+ pubkey = join (env .subst ("$PROJECT_SRC_DIR" ), "public.key" )
231
+ if isfile (pubkey ):
232
+ header_file = join (env .subst ("$BUILD_DIR" ), "core" , "Updater_Signing.h" )
233
+ env .Prepend (CCFLAGS = ['-I"%s"' % join ("$BUILD_DIR" , "core" )])
234
+ env .Execute (" " .join ([
235
+ '"$PYTHONEXE" "%s"' % join (
236
+ platform .get_package_dir ("framework-arduinopico" ), "tools" , "signing.py" ),
237
+ "--mode" , "header" ,
238
+ "--publickey" , '"%s"' % join ("$PROJECT_SRC_DIR" , "public.key" ),
239
+ "--out" , '"%s"' % join ("$BUILD_DIR" , "core" , "Updater_Signing.h" )
240
+ ]))
241
+
212
242
#
213
243
# Target: Build executable and linkable firmware
214
244
#
215
245
216
246
target_elf = None
247
+ target_signed_bin = None
217
248
if "nobuild" in COMMAND_LINE_TARGETS :
218
249
target_elf = join ("$BUILD_DIR" , "${PROGNAME}.elf" )
219
250
target_firm = join ("$BUILD_DIR" , "${PROGNAME}.bin" )
251
+ target_firm = join ("$BUILD_DIR" , "${PROGNAME}.bin.signed" )
220
252
else :
221
253
target_elf = env .BuildProgram ()
222
254
if set (["buildfs" , "uploadfs" ]) & set (COMMAND_LINE_TARGETS ):
@@ -225,11 +257,14 @@ def generate_uf2(target, source, env):
225
257
AlwaysBuild (target_firm )
226
258
else :
227
259
target_firm = env .ElfToBin (join ("$BUILD_DIR" , "${PROGNAME}" ), target_elf )
260
+ if is_arduino_pico_build :
261
+ target_signed_bin = env .BinToSignedBin (join ("$BUILD_DIR" , "${PROGNAME}" ), target_firm )
262
+ env .Depends (target_signed_bin , "checkprogsize" )
228
263
env .Depends (target_firm , "checkprogsize" )
229
264
230
265
env .AddPlatformTarget ("buildfs" , target_firm , target_firm , "Build Filesystem Image" )
231
266
AlwaysBuild (env .Alias ("nobuild" , target_firm ))
232
- target_buildprog = env .Alias ("buildprog" , target_firm , target_firm )
267
+ target_buildprog = env .Alias ("buildprog" , [ target_firm , target_signed_bin ] , target_firm )
233
268
234
269
env .AddPostAction (
235
270
target_elf , env .VerboseAction (generate_uf2 , "Generating UF2 image" )
@@ -284,14 +319,93 @@ def UploadUF2ToDisk(target, source, env):
284
319
copyfile (fpath , join (env .subst ("$UPLOAD_PORT" ), "%s.%s" % (progname , ext )))
285
320
print (
286
321
"Firmware has been successfully uploaded.\n "
287
- "(Some boards may require manual hard reset)"
288
322
)
289
323
324
+ def TryResetPico (target , source , env ):
325
+ upload_options = {}
326
+ if "BOARD" in env :
327
+ upload_options = env .BoardConfig ().get ("upload" , {})
328
+ ports = list_serial_ports ()
329
+ if len (ports ) != 0 :
330
+ last_port = ports [- 1 ]["port" ]
331
+ if upload_options .get ("use_1200bps_touch" , False ):
332
+ env .TouchSerialPort (last_port , 1200 )
333
+ time .sleep (2.0 )
334
+
335
+ from platformio .device .list .util import list_logical_devices
336
+ from platformio .device .finder import is_pattern_port
337
+ from fnmatch import fnmatch
338
+
339
+ def find_rpi_disk (initial_port ):
340
+ msdlabels = ("RPI-RP2" )
341
+ item :str
342
+ for item in list_logical_devices ():
343
+ if item ["path" ].startswith ("/net" ):
344
+ continue
345
+ if (
346
+ initial_port
347
+ and is_pattern_port (initial_port )
348
+ and not fnmatch (item ["path" ], initial_port )
349
+ ):
350
+ continue
351
+ mbed_pages = [join (item ["path" ], n ) for n in ("INDEX.HTM" , "INFO_UF2.TXT" )]
352
+ if any (isfile (p ) for p in mbed_pages ):
353
+ return item ["path" ]
354
+ if item ["name" ] and any (l in item ["name" ].lower () for l in msdlabels ):
355
+ return item ["path" ]
356
+ return None
357
+
358
+ def AutodetectPicoDisk (target , source , env ):
359
+ initial_port = env .subst ("$UPLOAD_PORT" )
360
+ if initial_port and not is_pattern_port (initial_port ):
361
+ print (env .subst ("Using manually specified: $UPLOAD_PORT" ))
362
+ return
363
+
364
+ if upload_protocol == "mbed" :
365
+ env .Replace (UPLOAD_PORT = find_rpi_disk (initial_port ))
366
+
367
+ if env .subst ("$UPLOAD_PORT" ):
368
+ print (env .subst ("Auto-detected: $UPLOAD_PORT" ))
369
+ else :
370
+ sys .stderr .write (
371
+ "Error: Please specify `upload_port` for environment or use "
372
+ "global `--upload-port` option.\n "
373
+ "For some development platforms it can be a USB flash "
374
+ "drive (i.e. /media/<user>/<device name>)\n "
375
+ )
376
+ env .Exit (1 )
377
+
290
378
if upload_protocol == "mbed" :
291
379
upload_actions = [
292
- env .VerboseAction (env .AutodetectUploadPort , "Looking for upload disk..." ),
380
+ env .VerboseAction (TryResetPico , "Trying to reset Pico into bootloader mode..." ),
381
+ env .VerboseAction (AutodetectPicoDisk , "Looking for upload disk..." ),
293
382
env .VerboseAction (UploadUF2ToDisk , "Uploading $SOURCE" )
294
383
]
384
+ elif upload_protocol == "espota" :
385
+ if not env .subst ("$UPLOAD_PORT" ):
386
+ sys .stderr .write (
387
+ "Error: Please specify IP address or host name of ESP device "
388
+ "using `upload_port` for build environment or use "
389
+ "global `--upload-port` option.\n "
390
+ "See https://docs.platformio.org/page/platforms/"
391
+ "espressif8266.html#over-the-air-ota-update\n " )
392
+ env .Replace (
393
+ UPLOADER = join (
394
+ platform .get_package_dir ("framework-arduinopico" ) or "" ,
395
+ "tools" , "espota.py" ),
396
+ UPLOADERFLAGS = ["--debug" , "--progress" , "-i" , "$UPLOAD_PORT" , "-p" , "2040" ],
397
+ UPLOADCMD = '"$PYTHONEXE" "$UPLOADER" $UPLOADERFLAGS -f $SOURCE'
398
+ )
399
+ if "uploadfs" in COMMAND_LINE_TARGETS :
400
+ env .Append (UPLOADERFLAGS = ["-s" ])
401
+ else :
402
+ # check if we have a .bin.signed file available.
403
+ # since the file may not be build yet, we try to predict that we will
404
+ # have that file if they private signing key exists.
405
+ if isfile (join (env .subst ("$PROJECT_SRC_DIR" ), "private.key" )):
406
+ sys .stdout .write ("Using signed OTA update file." )
407
+ upload_source = target_signed_bin
408
+ upload_actions = [env .VerboseAction ("$UPLOADCMD" , "Uploading $SOURCE" )]
295
409
elif upload_protocol == "picotool" :
296
410
env .Replace (
297
411
UPLOADER = join (platform .get_package_dir ("tool-rp2040tools" ) or "" , "rp2040load" ),
@@ -405,5 +519,4 @@ def _jlink_cmd_script(env, source):
405
519
#
406
520
# Default targets
407
521
#
408
-
409
522
Default ([target_buildprog , target_size ])
0 commit comments