diff --git a/emBODY/eBcode/arch-arm/board/amcbldc/utils/directories.json b/emBODY/eBcode/arch-arm/board/amcbldc/utils/directories.json new file mode 100644 index 0000000000..55de7bc9a5 --- /dev/null +++ b/emBODY/eBcode/arch-arm/board/amcbldc/utils/directories.json @@ -0,0 +1,93 @@ +{ + "subdirectories_to_copy": [ + { + "source_directory": "_sharedutils", + "source_directory_parent": "ert", + "target_directory": "sharedutils", + "files": [ + "*.cpp", + "*.h" + ] + }, + { + "source_directory": "AMC_BLDC_ert_rtw", + "target_directory": "amc-bldc", + "files": [ + "AMC*.cpp", + "AMC*.h" + ] + }, + { + "source_directory": "can_decoder", + "source_directory_parent": "ert", + "target_directory": "can-decoder", + "files": [ + "*.cpp", + "*.h" + ] + }, + { + "source_directory": "can_encoder", + "source_directory_parent": "ert", + "target_directory": "can-encoder", + "files": [ + "*.cpp", + "*.h" + ] + }, + { + "source_directory": "control_foc", + "source_directory_parent": "ert", + "target_directory": "control-foc", + "files": [ + "*.cpp", + "*.h" + ] + }, + { + "source_directory": "control_outer", + "source_directory_parent": "ert", + "target_directory": "control-outer", + "files": [ + "*.cpp", + "*.h" + ] + }, + { + "source_directory": "estimation_velocity", + "source_directory_parent": "ert", + "target_directory": "estimator", + "files": [ + "*.cpp", + "*.h" + ] + }, + { + "source_directory": "filter_current", + "source_directory_parent": "ert", + "target_directory": "filter-current", + "files": [ + "*.cpp", + "*.h" + ] + }, + { + "source_directory": "SupervisorFSM_RX", + "source_directory_parent": "ert", + "target_directory": "supervisor-rx", + "files": [ + "*.cpp", + "*.h" + ] + }, + { + "source_directory": "SupervisorFSM_TX", + "source_directory_parent": "ert", + "target_directory": "supervisor-tx", + "files": [ + "*.cpp", + "*.h" + ] + } + ] +} \ No newline at end of file diff --git a/emBODY/eBcode/arch-arm/mbd/utils/README.md b/emBODY/eBcode/arch-arm/mbd/utils/README.md new file mode 100644 index 0000000000..408b49fdda --- /dev/null +++ b/emBODY/eBcode/arch-arm/mbd/utils/README.md @@ -0,0 +1,101 @@ +## How to use the Copier script + +To use the Copier script, run the following command: + +```bash + Python3 copier.py . +``` + +**Notes:** +- _source_: It's the directory where the generated code by Simulink resides. This should point to the `codegen` directory of the Model repository. + +- _destinantion_: It's the directory where to copy the code. This should point to the `src/model-based-design` directory of `icub-firmware` repo of the respective board. + +- _path_to_directories_json_: It's the path to the `directories.json` file. This file should be placed, and properly configured, for each board that includes parts of `mbd` code. + +- ⚠️ The program is intended to work on **Windows** machines only. + +## `directories.json` + +The json file is verified before running the script. If something is wrong, you will most likely get an error showing the problem. + +The structure of the json goes as follows: + + +It's the directory where to paste the code. This should point to the `src/model-based-design` directory of the respective `icub-firmware` repo. + +You can input the location by pieces in an array. The code will join the strings together. + +#### Subdirectories + +```json +"subdirectories_to_copy": [ + {"..."}, +] +``` + +This holds the information of the subdirectories that will be copied from source to target. + +Each entry in the `subdirectories_to_copy` should be another dictionary following this structure: + +```json +{ + "source_directory": "...", + "source_directory_parent": "...", + "target_directory": "...", + "files": [ + "...", + ] +} +``` + +`source_directory`: name of the subdirectory in the source. This subdirectory can be anywhere in the file structure of the source. The copier will search for it through the entire file hierarchy. + +`source_directory_parent` [optional]: if there are several subdirectories with the same name, you can specify the parent to select which one to choose. + +For example, if inside the source there is a directory called `src/files` and `lib/files`, using `files` as source and `src` in the parent field will select the former of the two. + +`target_directory`: name of the directory in which to paste the files. This directory must exist already in the target. If you are copying into a new directory first create the empty target and then run the script. + +`files`: selectors for the files. The script will only copy files whose names match the given selectors. + +For example, if you only want `.cpp` and `.h` files that begin with `helloworld` you could do the following: + +```json +"files": [ + "helloworld*.cpp", + "helloworld*.h" +] +``` + +Any file that doesn't follow this naming will be excluded from being copied. + + +### Example of `directories.json` + +```json +{ + "subdirectories_to_copy": [ + { + "source_directory": "can_decoder", + "source_directory_parent": "ert", + "target_directory": "can-decoder", + "files": [ + "*.cpp", + "*.h" + ] + }, + { + "source_directory": "can_encoder", + "source_directory_parent": "ert", + "target_directory": "can-encoder", + "files": [ + "*.cpp", + "*.h" + ] + } + ] +} +``` + +[1]: ../../board/amcbldc/utils/directories.json diff --git a/emBODY/eBcode/arch-arm/mbd/utils/copier.py b/emBODY/eBcode/arch-arm/mbd/utils/copier.py new file mode 100644 index 0000000000..42ae9c3a3b --- /dev/null +++ b/emBODY/eBcode/arch-arm/mbd/utils/copier.py @@ -0,0 +1,109 @@ +""" + Copyright (C) 2022 iCub Tech - Istituto Italiano di Tecnologia + Author: Simone Girardi + email: simone.girardi@iit.it +""" + +import os.path +import os +import glob +import shutil +import json +import argparse + +SECTION="-------------------" +BIG_SECTION="*******************" + +# Checking if the directory is empty or not +def is_empty(dir): + try: + if not os.listdir(dir): + print(dir + " is an empty directory.") + print("Aborting...") + return True + else: + return False + except FileNotFoundError: + print(dir + " directory does not exist.") + print("Aborting...") + return True + +def find_subdirectory(main_directory, subdirectory, parent = None): + for root, dirs, files in os.walk(main_directory): + for dir in dirs: + if dir == subdirectory: + dir_parent = root.split('\\')[-1] + if parent is None or dir_parent == parent: + return os.path.join(root, subdirectory) + return "" + +def check_dictionary_type(dictionary, key, type): + if not key in dictionary: + raise Exception(f"No {key} found") + if not isinstance(dictionary[key], type): + raise Exception(f"Invalid {key}") + +def parse_instructions(dictionary, source_directory, target_directory): + check_dictionary_type(dictionary, "subdirectories_to_copy", list) + subdirectories_to_copy = dictionary["subdirectories_to_copy"] + + # loop over the subdirectories + for subdirectory in subdirectories_to_copy: + parent = subdirectory["source_directory_parent"] if "source_directory_parent" in subdirectory else None + source_subdir = find_subdirectory(source_directory, subdirectory["source_directory"], parent) + target_subdir = find_subdirectory(target_directory, subdirectory["target_directory"]) + + copy_files(source_subdir, target_subdir, subdirectory["files"], True) + print(BIG_SECTION) + +def copy_files(source_dir, target_dir, file_selectors, overwrite): + if not (os.path.isdir(source_dir) and os.path.isdir(target_dir)): + raise Exception(f"""Invalid path given (Source: {source_dir}, Target: {target_dir}). + If target is empty, consider creating the empty directory in the desired destination before running the copier.""") + print(BIG_SECTION) + print(f"Copying files from {source_dir} to {target_dir}") + print(SECTION) + files_to_copy = [] + for file_selector in file_selectors: + selected_files = glob.glob(os.path.join(source_dir, file_selector)) + print(f"Selector {file_selector} matched with the following files: {selected_files}") + files_to_copy = files_to_copy + selected_files + files_to_copy = set(files_to_copy) + print(SECTION) + for source_file in files_to_copy: + file_basename = os.path.basename(source_file) + target_file = os.path.join(target_dir, file_basename) + if overwrite or (not os.path.exists(target_file)): + shutil.copy(source_file, target_file) + print(f"Copying {file_basename} from {source_dir} to {target_dir}") + else: + print(f"Skipping {file_basename} from {source_dir} since overwriting is not allowed") + print("\n") + +def main(): + parser = argparse.ArgumentParser(prog='The Copier', + description="The copier has the purpose to copy the code generated from Simulink to the proper board folder in icub-firmware ", + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument('source', help="Absolute path to the codegen directory within icub-firmware-models") + parser.add_argument('destination', help="Absolute path to the model-based-design directory within icub-firmware (for a specific board)") + parser.add_argument('path_to_directories_json', help="Absolute path to the directory containing the directories.json file") + + args = parser.parse_args() + config = vars(args) + + path_to_json = os.path.join(config['path_to_directories_json'], "directories.json") + path_to_src = config['source'] + path_to_dst = config['destination'] + + # check if source and destination directories exist and are not empty + if not (is_empty(path_to_src) or is_empty(path_to_dst)): + + # try to open the json configuration file + with open(path_to_json) as file: + json_instructions = json.load(file) + + # start to parse and (eventually) to copy + parse_instructions(json_instructions, path_to_src, path_to_dst) + +if __name__ == "__main__": + main() \ No newline at end of file