16
16
# along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
18
18
import argparse
19
- import subprocess
20
- import sys
21
19
import json
22
20
import hashlib
23
21
import shutil
@@ -35,12 +33,6 @@ def get_firmware_file(module, simple_fqbn, version):
35
33
return firmware_full_path / f"{ module } .bin"
36
34
37
35
38
- # Runs arduino-cli, doesn't handle errors at all because am lazy
39
- def arduino_cli (cli_path , args = []):
40
- res = subprocess .run ([cli_path , * args ], capture_output = True , text = True )
41
- return res .stdout
42
-
43
-
44
36
# Generates file SHA256
45
37
def sha2 (file_path ):
46
38
with open (file_path , "rb" ) as f :
@@ -53,31 +45,6 @@ def split_property_and_drop_first_level(s):
53
45
return (k , v )
54
46
55
47
56
- # Generate and copy precompiled Sketch binary data for specified board
57
- # (sketch type could be either "loader" or "getversion")
58
- def create_precomp_sketch_data (simple_fqbn , sketch_type ):
59
-
60
- sketch_dir = Path (__file__ ).parent / ".." / "firmwares" / sketch_type / simple_fqbn
61
- sketch_files = list (sketch_dir .iterdir ())
62
- if len (sketch_files ) != 1 :
63
- print (f"Invalid loader files found in { sketch_dir } " )
64
- sys .exit (1 )
65
- sketch_file = sketch_files [0 ] # lets assume there's only a single file
66
-
67
- sketch_dest = f"firmwares/{ sketch_type } /{ simple_fqbn } /{ sketch_type } { sketch_file .suffix } "
68
- sketch_dest_path = Path (__file__ ).parent / sketch_dest
69
- sketch_dest_path .parent .mkdir (parents = True , exist_ok = True )
70
- shutil .copyfile (sketch_file , sketch_dest_path )
71
-
72
- file_hash = sha2 (sketch_dest_path )
73
-
74
- return {
75
- "url" : f"{ DOWNLOAD_URL } /{ sketch_dest } " ,
76
- "checksum" : f"SHA-256:{ file_hash } " ,
77
- "size" : f"{ sketch_dest_path .stat ().st_size } " ,
78
- }
79
-
80
-
81
48
# Generate and copy all firmware binary data for specified board
82
49
def create_firmware_data (binary , module , version ):
83
50
binary_name = binary .name
@@ -97,181 +64,6 @@ def create_firmware_data(binary, module, version):
97
64
}
98
65
99
66
100
- def get_uploader_id (tools , tool_name ):
101
- for t in tools :
102
- if t ["name" ] == tool_name :
103
- packager = t ["packager" ]
104
- name = t ["name" ]
105
- version = t ["version" ]
106
- return f"{ packager } :{ name } @{ version } "
107
-
108
-
109
- def create_upload_data (fqbn , installed_cores ): # noqa: C901
110
- upload_data = {}
111
- # Assume we're on Linux
112
- arduino15 = Path .home () / ".arduino15"
113
-
114
- board_id = fqbn .split (":" )[2 ]
115
- core_id = ":" .join (fqbn .split (":" )[:2 ])
116
-
117
- # Get the core install dir
118
- core = installed_cores [core_id ]
119
- (maintainer , arch ) = core_id .split (":" )
120
- core_install_dir = arduino15 / "packages" / maintainer / "hardware" / arch / core ["installed" ]
121
-
122
- with open (core_install_dir / "boards.txt" ) as f :
123
- boards_txt = f .readlines ()
124
-
125
- board_upload_data = {}
126
- for line in boards_txt :
127
- if line .startswith (f"{ board_id } ." ):
128
- (k , v ) = split_property_and_drop_first_level (line )
129
- board_upload_data [k ] = v
130
-
131
- tool = board_upload_data ["upload.tool" ]
132
-
133
- with open (core_install_dir / "platform.txt" ) as f :
134
- platform_txt = f .readlines ()
135
-
136
- platform_upload_data = {}
137
- for line in platform_txt :
138
- if line .startswith (f"tools.{ tool } ." ):
139
- (k , v ) = split_property_and_drop_first_level (line )
140
- platform_upload_data [k ] = v
141
-
142
- # We assume the installed.json exist
143
- with open (core_install_dir / "installed.json" ) as f :
144
- installed_json_data = json .load (f )
145
-
146
- if f"{ tool } .cmd" in platform_upload_data :
147
- tool_executable_generic = platform_upload_data [f"{ tool } .cmd" ]
148
- tool_executable_linux = platform_upload_data .get (f"{ tool } .cmd.linux" , tool_executable_generic )
149
- tool_executable_windows = platform_upload_data .get (f"{ tool } .cmd.windows" , "" )
150
- tool_executable_macosx = platform_upload_data .get (f"{ tool } .cmd.macosx" , "" )
151
- tool_name = tool_executable_generic
152
- elif f"{ tool } .cmd.path" in platform_upload_data :
153
- tool_executable_generic = "/" .join (platform_upload_data [f"{ tool } .cmd.path" ].split ("/" )[1 :])
154
- tool_executable_linux = platform_upload_data .get (f"{ tool } .cmd.path.linux" , tool_executable_generic )
155
- tool_executable_windows = platform_upload_data .get (f"{ tool } .cmd.path.windows" , "" )
156
- tool_executable_macosx = platform_upload_data .get (f"{ tool } .cmd.path.macosx" , "" )
157
- tool_name = tool_executable_generic .split ("/" )[- 1 ]
158
-
159
- tool_config_path = ""
160
- if f"{ tool } .config.path" in platform_upload_data :
161
- tool_config_path = "/" .join (platform_upload_data [f"{ tool } .config.path" ].split ("/" )[1 :])
162
-
163
- if tool_name == "rp2040load" :
164
- tool_name = "rp2040tools"
165
-
166
- tools = installed_json_data ["packages" ][0 ]["platforms" ][0 ]["toolsDependencies" ]
167
- upload_data ["uploader" ] = get_uploader_id (tools , tool_name )
168
-
169
- if "upload.use_1200bps_touch" in board_upload_data :
170
- upload_data ["upload.use_1200bps_touch" ] = bool (board_upload_data ["upload.use_1200bps_touch" ])
171
-
172
- if "upload.wait_for_upload_port" in board_upload_data :
173
- upload_data ["upload.wait_for_upload_port" ] = bool (board_upload_data ["upload.wait_for_upload_port" ])
174
-
175
- # Get the command used to upload and modifies it a bit
176
- command = (
177
- platform_upload_data [f"{ tool } .upload.pattern" ]
178
- .replace ("{path}/{cmd}" , "{uploader}" )
179
- .replace ("{cmd.path}" , "{uploader}" )
180
- .replace ("{build.path}/{build.project_name}" , "{loader.sketch}" )
181
- .replace ("{config.path}" , f"{{tool_dir}}/{ tool_config_path } " )
182
- .replace ('\\ "' , "" )
183
- )
184
-
185
- if fqbn == "arduino:megaavr:uno2018" :
186
- # Long story short if we don't do this we'd have to host also the bootloader
187
- # for the Uno WiFi rev2 and we don't want to, so we just remove this field
188
- # and use a precompiled Loader Sketh binary that includes the bootloader.
189
- command = command .replace ("{upload.extra_files}" , "" )
190
-
191
- # Get the rest of the params
192
- params = {}
193
- for k , v in platform_upload_data .items ():
194
- if f"{ tool } .upload.params." in k :
195
- param = k .split ("." )[- 1 ]
196
- params [f"upload.{ param } " ] = v
197
- elif f"{ tool } .upload." in k :
198
- k = "." .join (k .split ("." )[1 :])
199
- params [k ] = v
200
-
201
- # Prepare the command
202
- for k , v in {** board_upload_data , ** params }.items ():
203
- command = command .replace (f"{{{ k } }}" , v )
204
-
205
- # This is ugly as hell and I don't care
206
- upload_data ["uploader.command" ] = {}
207
- if tool_executable_linux :
208
- upload_data ["uploader.command" ]["linux" ] = command .replace (
209
- "{uploader}" , f"{{tool_dir}}/{ tool_executable_linux } "
210
- )
211
-
212
- if tool_executable_windows :
213
- upload_data ["uploader.command" ]["windows" ] = command .replace (
214
- "{uploader}" , f"{{tool_dir}}\\ { tool_executable_windows } "
215
- )
216
-
217
- if tool_executable_macosx :
218
- upload_data ["uploader.command" ]["macosx" ] = command .replace (
219
- "{uploader}" , f"{{tool_dir}}/{ tool_executable_macosx } "
220
- )
221
-
222
- return upload_data
223
-
224
-
225
- def generate_boards_json (input_data , arduino_cli_path ):
226
- boards = {
227
- "arduino:samd:mkr1000" : {"fqbn" : "arduino:samd:mkr1000" , "firmware" : []},
228
- "arduino:samd:mkrvidor4000" : {
229
- "fqbn" : "arduino:samd:mkrvidor4000" ,
230
- "firmware" : [],
231
- },
232
- }
233
-
234
- # Gets the installed cores
235
- res = arduino_cli (cli_path = arduino_cli_path , args = ["core" , "list" , "--format" , "json" ])
236
- installed_cores = {c ["id" ]: c for c in json .loads (res )}
237
-
238
- # Verify all necessary cores are installed
239
- # TODO: Should we check that the latest version is installed too?
240
- for fqbn , data in input_data .items ():
241
- core_id = ":" .join (fqbn .split (":" )[:2 ])
242
- if core_id not in installed_cores :
243
- print (f"Board { fqbn } is not installed, install its core { core_id } " )
244
- sys .exit (1 )
245
-
246
- simple_fqbn = fqbn .replace (":" , "." )
247
-
248
- # List of old boards that need precompiled sketch data and uploader information obtained through platform.txt.
249
- boards [fqbn ]["loader_sketch" ] = create_precomp_sketch_data (simple_fqbn , "loader" )
250
- boards [fqbn ]["version_sketch" ] = create_precomp_sketch_data (simple_fqbn , "getversion" )
251
- boards [fqbn ].update (create_upload_data (fqbn , installed_cores ))
252
- # Gets the old_board name
253
- res = arduino_cli (
254
- cli_path = arduino_cli_path ,
255
- args = ["board" , "search" , fqbn , "--format" , "json" ],
256
- )
257
- for board in json .loads (res ):
258
- if board ["fqbn" ] == fqbn :
259
- boards [fqbn ]["name" ] = board ["name" ]
260
- break
261
-
262
- for firmware_version in data ["versions" ]:
263
- module = data ["moduleName" ]
264
- firmware_file = get_firmware_file (module , simple_fqbn , firmware_version )
265
- boards [fqbn ]["firmware" ].append (create_firmware_data (firmware_file , module , firmware_version ))
266
- boards [fqbn ]["module" ] = module
267
-
268
- boards_json = []
269
- for _ , b in boards .items ():
270
- boards_json .append (b )
271
-
272
- return boards_json
273
-
274
-
275
67
def generate_new_boards_json (input_data ):
276
68
# init the boards dict
277
69
boards = {}
@@ -300,70 +92,13 @@ def generate_new_boards_json(input_data):
300
92
301
93
if __name__ == "__main__" :
302
94
parser = argparse .ArgumentParser (prog = "generator.py" )
303
- parser .add_argument (
304
- "-a" ,
305
- "--arduino-cli" ,
306
- default = "arduino-cli" ,
307
- help = "Path to arduino-cli executable" ,
308
- required = True ,
309
- )
310
- parser .add_argument (
311
- "--new" ,
312
- action = argparse .BooleanOptionalAction ,
313
- default = True ,
314
- help = "Generate the index for old boards" ,
315
- )
316
- args = parser .parse_args (sys .argv [1 :])
317
95
318
- if args .new :
319
- input_file = "new_boards.json"
320
- output_file = "plugin_firmware_index.json"
321
- else :
322
- input_file = "boards.json"
323
- output_file = "module_firmware_index.json"
324
-
325
- # raw_boards.json has been generated using --get_available_for FirmwareUploader (version 0.1.8) flag.
326
- # It has been edited a bit to better handle parsing.
327
- with open (input_file , "r" ) as f :
96
+ with open ("new_boards.json" , "r" ) as f :
328
97
boards = json .load (f )
329
98
330
- if args .new :
331
- boards_json = generate_new_boards_json (boards )
332
- else :
333
- boards_json = generate_boards_json (boards , args .arduino_cli )
99
+ boards_json = generate_new_boards_json (boards )
334
100
335
101
Path ("boards" ).mkdir (exist_ok = True )
336
102
337
- with open ("boards/" + output_file , "w" ) as f :
103
+ with open ("boards/plugin_firmware_index.json" , "w" ) as f :
338
104
json .dump (boards_json , f , indent = 2 )
339
-
340
- # board_index.json must be formatted like so:
341
- #
342
- # {
343
- # "name": "MKR 1000",
344
- # "fqbn": "arduino:samd:mkr1000",
345
- # "module": "WINC_1500",
346
- # "firmware": [
347
- # {
348
- # "version": "19.6.1",
349
- # "url": "https://downloads.arduino.cc/firmwares/WINC_1500/19.6.1/m2m_aio_3a0.bin",
350
- # "checksum": "SHA-256:de0c6b1621aa15996432559efb5d8a29885f62bde145937eee99883bfa129f97",
351
- # "size": "359356",
352
- # },
353
- # {
354
- # "version": "19.5.4",
355
- # "url": "https://downloads.arduino.cc/firmwares/WINC_1500/19.5.4/m2m_aio_3a0.bin",
356
- # "checksum": "SHA-256:71e5a805e60f96e6968414670d8a414a03cb610fd4b020f47ab53f5e1ff82a13",
357
- # "size": "413604",
358
- # },
359
- # ],
360
- # "loader_sketch": {
361
- # "url": "https://downloads.arduino.cc/firmwares/loader/arduino.samd.mkr1000/loader.bin",
362
- # "checksum": "SHA-256:71e5a805e60f96e6968414670d8a414a03cb610fd4b020f47ab53f5e1ff82a13",
363
- # "size": "39287",
364
- # },
365
- # "uploader": "arduino:[email protected] ",
366
- # "uploader.command": "{uploader} --port={upload.port} -U true -i -e -w -v {loader.sketch} -R",
367
- # "uploader.requires_1200_bps_touch": "true",
368
- # "uploader.requires_port_change": "true",
369
- # }
0 commit comments