@@ -133,10 +133,23 @@ def server_info_query(self, tvm_version):
133133 )
134134
135135 def _copy_project_files (self , api_server_dir , project_dir , project_type ):
136+ """Copies the files for project_type into project_dir.
137+
138+ Notes
139+ -----
140+ template_dir is NOT a project type, and that directory is never copied
141+ in this function. template_dir only holds this file and its unit tests,
142+ so this file is copied separately in generate_project.
143+
144+ """
136145 project_types_folder = api_server_dir .parents [0 ]
137- shutil .copytree (
138- project_types_folder / project_type / "src" , project_dir / "src" , dirs_exist_ok = True
139- )
146+ for item in (project_types_folder / project_type / "src" ).iterdir ():
147+ dest = project_dir / "src" / item .name
148+ if item .is_dir ():
149+ shutil .copytree (item , dest )
150+ else :
151+ shutil .copy2 (item , dest )
152+
140153 # Arduino requires the .ino file have the same filename as its containing folder
141154 shutil .copy2 (
142155 project_types_folder / project_type / "project.ino" ,
@@ -146,7 +159,6 @@ def _copy_project_files(self, api_server_dir, project_dir, project_type):
146159 CRT_COPY_ITEMS = ("include" , "src" )
147160
148161 def _copy_standalone_crt (self , source_dir , standalone_crt_dir ):
149- # Copy over the standalone_crt directory
150162 output_crt_dir = source_dir / "standalone_crt"
151163 for item in self .CRT_COPY_ITEMS :
152164 src_path = os .path .join (standalone_crt_dir , item )
@@ -200,9 +212,9 @@ def _template_model_header(self, source_dir, metadata):
200212 with open (source_dir / "model.h" , "r" ) as f :
201213 model_h_template = Template (f .read ())
202214
203- # The structure of the "memory" key depends on the style -
204- # only style= "full-model" works with AOT, so we'll check that
205- assert metadata [ "style" ] == " full-model"
215+ assert (
216+ metadata [ " style" ] == "full-model"
217+ ), "when generating AOT, expect only full-model Model Library Format "
206218
207219 template_values = {
208220 "workspace_size_bytes" : metadata ["memory" ]["functions" ]["main" ][0 ][
@@ -225,20 +237,20 @@ def _change_cpp_file_extensions(self, source_dir):
225237 for filename in source_dir .rglob (f"*.inc" ):
226238 filename .rename (filename .with_suffix (".h" ))
227239
228- """Arduino only supports includes relative to the top-level project, so this
229- finds each time we #include a file and changes the path to be relative to the
230- top-level project.ino file. For example, the line:
231-
232- #include <tvm/runtime/crt/platform.h>
233-
234- Might be changed to (depending on the source file's location):
240+ def _convert_includes (self , project_dir , source_dir ):
241+ """Changes all #include statements in project_dir to be relevant to their
242+ containing file's location.
235243
236- #include "../../../../include/tvm/runtime/crt/platform.h"
244+ Arduino only supports includes relative to a file's location, so this
245+ function finds each time we #include a file and changes the path to
246+ be relative to the file location. Does not do this for standard C
247+ libraries. Also changes angle brackets syntax to double quotes syntax.
237248
238- We also need to leave standard library includes as-is.
239- """
249+ See Also
250+ -----
251+ https://www.arduino.cc/reference/en/language/structure/further-syntax/include/
240252
241- def _convert_includes ( self , project_dir , source_dir ):
253+ """
242254 for ext in ("c" , "h" , "cpp" ):
243255 for filename in source_dir .rglob (f"*.{ ext } " ):
244256 with filename .open () as file :
@@ -263,27 +275,19 @@ def _convert_includes(self, project_dir, source_dir):
263275 # be added in the future.
264276 POSSIBLE_BASE_PATHS = ["src/standalone_crt/include/" , "src/standalone_crt/crt_config/" ]
265277
266- """Takes a single #include path, and returns the new location
267- it should point to (as described above). For example, one of the
268- includes for "src/standalone_crt/src/runtime/crt/common/ndarray.c" is:
269-
270- #include <tvm/runtime/crt/platform.h>
271-
272- For that line, _convert_includes might call _find_modified_include_path
273- with the arguments:
274-
275- project_dir = "/path/to/project/dir"
276- file_path = "/path/to/project/dir/src/standalone_crt/src/runtime/crt/common/ndarray.c"
277- include_path = "tvm/runtime/crt/platform.h"
278-
279- Given these arguments, _find_modified_include_path should return:
280-
281- "../../../../../../src/standalone_crt/include/tvm/runtime/crt/platform.h"
282-
283- See unit test in ./tests/test_arduino_microtvm_api_server.py
284- """
285-
286278 def _find_modified_include_path (self , project_dir , file_path , include_path ):
279+ """Takes a single #include path, and returns the location it should point to.
280+
281+ Examples
282+ --------
283+ >>> _find_modified_include_path(
284+ ... "/path/to/project/dir"
285+ ... "/path/to/project/dir/src/standalone_crt/src/runtime/crt/common/ndarray.c"
286+ ... "tvm/runtime/crt/platform.h"
287+ ... )
288+ "../../../../../../src/standalone_crt/include/tvm/runtime/crt/platform.h"
289+
290+ """
287291 if include_path .endswith (".inc" ):
288292 include_path = re .sub (r"\.[a-z]+$" , ".h" , include_path )
289293
@@ -314,8 +318,7 @@ def generate_project(self, model_library_format_path, standalone_crt_dir, projec
314318 source_dir = project_dir / "src"
315319 source_dir .mkdir ()
316320
317- # Copies files from the template folder to project_dir. model.h is copied here,
318- # but will also need to be templated later.
321+ # Copies files from the template folder to project_dir
319322 shutil .copy2 (API_SERVER_DIR / "microtvm_api_server.py" , project_dir )
320323 self ._copy_project_files (API_SERVER_DIR , project_dir , options ["project_type" ])
321324
@@ -359,17 +362,24 @@ def build(self, options):
359362 # Specify project to compile
360363 subprocess .run (compile_cmd )
361364
362- """We run the command `arduino-cli board list`, which produces
363- outputs of the form:
364-
365- Port Type Board Name FQBN Core
366- /dev/ttyS4 Serial Port Unknown
367- /dev/ttyUSB0 Serial Port (USB) Spresense SPRESENSE:spresense:spresense SPRESENSE:spresense
368- """
369-
370365 BOARD_LIST_HEADERS = ("Port" , "Type" , "Board Name" , "FQBN" , "Core" )
371366
372367 def _parse_boards_tabular_str (self , tabular_str ):
368+ """Parses the tabular output from `arduino-cli board list` into a 2D array
369+
370+ Examples
371+ --------
372+ >>> list(_parse_boards_tabular_str(bytes(
373+ ... "Port Type Board Name FQBN Core \n "
374+ ... "/dev/ttyS4 Serial Port Unknown \n "
375+ ... "/dev/ttyUSB0 Serial Port (USB) Spresense SPRESENSE:spresense:spresense SPRESENSE:spresense\n "
376+ ... "\n ",
377+ ... "utf-8")))
378+ [['/dev/ttys4', 'Serial Port', 'Unknown', '', ''], ['/dev/ttyUSB0', 'Serial Port (USB)',
379+ 'Spresense', 'SPRESENSE:spresense:spresense', 'SPRESENSE:spresense']]
380+
381+ """
382+
373383 str_rows = tabular_str .split ("\n " )[:- 2 ]
374384 header = str_rows [0 ]
375385 indices = [header .index (h ) for h in self .BOARD_LIST_HEADERS ] + [len (header )]
@@ -387,7 +397,7 @@ def _parse_boards_tabular_str(self, tabular_str):
387397
388398 def _auto_detect_port (self , options ):
389399 list_cmd = [options ["arduino_cli_cmd" ], "board" , "list" ]
390- list_cmd_output = subprocess .run (list_cmd , capture_output = True ).stdout .decode ("utf-8" )
400+ list_cmd_output = subprocess .run (list_cmd , stdout = subprocess . PIPE ).stdout .decode ("utf-8" )
391401
392402 desired_fqbn = self ._get_fqbn (options )
393403 for line in self ._parse_boards_tabular_str (list_cmd_output ):
0 commit comments