diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..66f5c2c4 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,53 @@ +name: Build Project + +on: + workflow_call: + inputs: + preset: + description: | + 'CMake preset to build the project, run `cmake --build --list-presets' to see a complete list of options' + required: true + type: string + default: 'nucleo-debug' + outputs: + build-artifact: + description: 'Build result artifact id for later use' + value: ${{ jobs.build.outputs.build-artifact }} + workflow_dispatch: + inputs: + preset: + description: | + 'CMake preset to build the project, run `cmake --build --list-presets' to see a complete list of options' + required: true + type: string + default: 'nucleo-debug' + +jobs: + build: + name: Build Project + runs-on: ubuntu-24.04 + outputs: + build-artifact: ${{ steps.upload-build-artifact.outputs.artifact-id }} + container: + image: jmaralo/hyperloop-upv-firmware:0.3.0 + steps: + - name: Clone Project + uses: actions/checkout@v3 + - name: Prepare submodules + run: | + git submodule init | + git submodule update + - name: Build + run: | + cmake --preset ${{ inputs.preset }} . + cmake --build --preset ${{ inputs.preset }} + - name: Upload Build + id: upload-build-artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.preset }} + path: out/build/latest.elf + retention-days: 7 + compression-level: 0 + if-no-files-found: error + diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml deleted file mode 100644 index 501b14ff..00000000 --- a/.github/workflows/c-cpp.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: C/C++ CI - -on: - push: - branches: [ "main" ,"test_automated_build"] - pull_request: - branches: [ "main" ] - -jobs: - build_template_project: - runs-on: ubuntu-latest - env: - STLIB_PATH: "/opt/ST-LIB" - steps: - - uses: actions/checkout@v3 - with: - repository: HyperloopUPV-H8/ST-LIB - ref: development - - uses: carlosperate/arm-none-eabi-gcc-action@v1 - - run: arm-none-eabi-gcc --version - - name: Install dependencies - run: pip install GitPython colorama - - name: Set up ST-LIB - run: ls && cp -r ../* /opt/ && mv /opt/${{ github.event.repository.name }} /opt/ST-LIB - - name: Print repo data - run: echo ${{ github.event.repository.name }} - - name: Display ST-LIB - run: ls /opt/ST-LIB - - uses: actions/checkout@v3 - with: - repository: ' ' - - name: Invoking python - run: python3 tools/build.py -eth ON -t NUCLEO -bb Debug - diff --git a/.github/workflows/compile-checks.yml b/.github/workflows/compile-checks.yml new file mode 100644 index 00000000..386de6a4 --- /dev/null +++ b/.github/workflows/compile-checks.yml @@ -0,0 +1,30 @@ +name: Compile Checks + +on: + push: + +jobs: + compile-checks: + name: Check project compiles + runs-on: ubuntu-24.04 + strategy: + matrix: + preset: + - nucleo-debug + - nucleo-release + - nucleo-relwithdebinfo + - nucleo-debug-eth + - nucleo-release-eth + - nucleo-relwithdebinfo-eth + - board-debug + - board-release + - board-relwithdebinfo + - board-debug-eth + - board-release-eth + - board-relwithdebinfo-eth + - simulator + steps: + - name: Build + uses: ./.github/workflows/build.yml + with: + preset: ${{ matrix.preset }} diff --git a/CMakePresets.json b/CMakePresets.json index 1a129335..3c341ea8 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -4,7 +4,7 @@ { "name": "mcu", "hidden": true, - "generator": "Unix Makefiles", + "generator": "Ninja", "binaryDir": "${sourceDir}/out/build/${presetName}", "toolchainFile": "${sourceDir}/toolchains/stm32.cmake", "installDir": "${sourceDir}/out/install/${presetName}", @@ -16,7 +16,7 @@ { "name": "sim", "hidden": true, - "generator": "Unix Makefiles", + "generator": "Ninja", "binaryDir": "${sourceDir}/out/build/${presetName}", "installDir": "${sourceDir}/out/install/${presetName}", "cacheVariables": { @@ -165,5 +165,72 @@ "CMAKE_BUILD_TYPE": "Debug" } } + ], + "buildPresets": [ + { + "name": "nucleo-debug", + "displayName": "Nucleo [DBG]", + "configurePreset": "nucleo-debug" + }, + { + "name": "nucleo-release", + "displayName": "Nucleo [REL]", + "configurePreset": "nucleo-release" + }, + { + "name": "nucleo-relwithdebinfo", + "displayName": "Nucleo [RWD]", + "configurePreset": "nucleo-relwithdebinfo" + }, + { + "name": "nucleo-debug-eth", + "displayName": "Nucleo [DBG] [ETH]", + "configurePreset": "nucleo-debug-eth" + }, + { + "name": "nucleo-release-eth", + "displayName": "Nucleo [REL] [ETH]", + "configurePreset": "nucleo-release-eth" + }, + { + "name": "nucleo-relwithdebinfo-eth", + "displayName": "Nucleo [RWD] [ETH]", + "configurePreset": "nucleo-relwithdebinfo-eth" + }, + { + "name": "board-debug", + "displayName": "Board [DBG]", + "configurePreset": "board-debug" + }, + { + "name": "board-release", + "displayName": "Board [REL]", + "configurePreset": "board-release" + }, + { + "name": "board-relwithdebinfo", + "displayName": "Board [RWD]", + "configurePreset": "board-relwithdebinfo" + }, + { + "name": "board-debug-eth", + "displayName": "Board [DBG] [ETH]", + "configurePreset": "board-debug-eth" + }, + { + "name": "board-release-eth", + "displayName": "Board [REL] [ETH]", + "configurePreset": "board-release-eth" + }, + { + "name": "board-relwithdebinfo-eth", + "displayName": "Board [RWD] [ETH]", + "configurePreset": "board-relwithdebinfo-eth" + }, + { + "name": "simulator", + "displayName": "Simulator", + "configurePreset": "simulator" + } ] } \ No newline at end of file diff --git a/deps/ST-LIB b/deps/ST-LIB index 3ead6859..5bbe11c5 160000 --- a/deps/ST-LIB +++ b/deps/ST-LIB @@ -1 +1 @@ -Subproject commit 3ead6859085e60171785f0470c54fc84dd0cc6d6 +Subproject commit 5bbe11c571dc241388c429eecc9b5ac5c326c31e diff --git a/tools/build.py b/tools/build.py deleted file mode 100755 index 38318287..00000000 --- a/tools/build.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/python3 -import importlib.util -import os -import argparse -import shutil -import subprocess -import sys - -# Requirements: -# colorama==0.4.6 -from colorama import Fore - - -parser = argparse.ArgumentParser( - prog="ConfigBuild", - description="Configures and builds the project" -) - -parser.add_argument( - '-bb', - '--build_behaviour', - choices=['Release', 'ReleaseDebug', 'Debug'], - required=True -) -parser.add_argument( - '-target', - '--target', - choices=['NUCLEO', 'BOARD'], - required=True -) -parser.add_argument( - '-eth', - '--ethernet_config', - choices=['ON', 'OFF'], - required=True -) - -stlib_path = os.environ.get('STLIB_PATH') - -PROJECT_NAME = "template-project" - - -def find_project(): - current_path = os.getcwd() - while current_path: - for entry in os.listdir(current_path): - if entry == "CMakeLists.txt": - return current_path - current_path, _ = os.path.split(current_path) - raise "Not inside a project" - -def main(args: argparse.Namespace): - if not stlib_path: - print(Fore.RED + "STLIB_PATH env variable is missing") - print(Fore.RESET, end="") - return 1 - - # This can only be resolved at runtime due to the STLIB_PATH env variable - stlib_build_path = os.path.join(stlib_path, "tools", "build.py") - stlib_build_spec = importlib.util.spec_from_file_location("stlib_build", stlib_build_path) - stlib_build = importlib.util.module_from_spec(stlib_build_spec) - stlib_build_spec.loader.exec_module(stlib_build) - - stlib_build_exit_code = stlib_build.main(argparse.Namespace( - build_behaviour=args.build_behaviour, - target=args.target, - ethernet_config=args.ethernet_config, - )) - - if stlib_build_exit_code != 0: - return stlib_build_exit_code - - print() - - try: - project_dir = find_project() - except Exception as find_error: - print(Fore.RED + f"Could not find project directory: {find_error}") - print(Fore.RESET, end="") - return 1 - - print(Fore.BLUE + f"Building {PROJECT_NAME}:") - print(Fore.BLUE + f"\tST-LIB path: {stlib_path}") - print(Fore.BLUE + f"\tTarget: {args.target}") - print(Fore.BLUE + f"\tBuild Behaviour: {args.build_behaviour}") - print(Fore.BLUE + f"\tEthernet: {args.ethernet_config}") - print(Fore.RESET) - - output_dir = os.path.join(project_dir, "build") - os.makedirs(output_dir, exist_ok=True) - - cmake_exit_code = subprocess.call([ - "cmake", - project_dir, - "-B", output_dir, - f"-DRELEASE={args.build_behaviour}", - f"-DNUCLEO={'TRUE' if args.target == 'NUCLEO' else 'FALSE'}", - f"-DETHERNET={'TRUE' if args.ethernet_config == 'ON' else 'FALSE'}", - "-G", "Unix Makefiles" - ]) - - if (cmake_exit_code != 0): - print(Fore.RED, "\nCMake failed, aborted") - print(Fore.RESET, end="") - return cmake_exit_code - - make_exit_code = subprocess.call([ - "make", - "-j", str(os.cpu_count()), - "-C", output_dir - ]) - - if (make_exit_code != 0): - print(Fore.RED + "\nMake failed, aborted") - print(Fore.RESET, end="") - return make_exit_code - - final_project_location = os.path.join(output_dir, args.build_behaviour) - os.makedirs(final_project_location, exist_ok=True) - shutil.copyfile( - os.path.join(output_dir, f"{PROJECT_NAME}.elf"), - os.path.join(final_project_location, f"{PROJECT_NAME}.elf") - ) - shutil.copyfile( - os.path.join(output_dir, f"{PROJECT_NAME}.elf"), - os.path.join(output_dir, f"latest.elf") - ) - - print() - print(Fore.GREEN + f"{PROJECT_NAME} built successfuly!") - print(Fore.GREEN + f"\tOutput path: {final_project_location}") - print(Fore.GREEN + f"\tTarget: {args.target}") - print(Fore.GREEN + f"\tBuild Behaviour: {args.build_behaviour}") - print(Fore.GREEN + f"\tEthernet: {args.ethernet_config}") - print(Fore.RESET, end="") - - return 0 - -if __name__ == "__main__": - exit(main(parser.parse_args())) \ No newline at end of file diff --git a/tools/create-new-project.py b/tools/create-new-project.py deleted file mode 100755 index 65f7e60b..00000000 --- a/tools/create-new-project.py +++ /dev/null @@ -1,209 +0,0 @@ -#!/usr/bin/python3 -import os -import re -from typing import Union -import argparse -import shutil - -# Requirements: -# git-python==1.0.3 -# tqdm==4.66.5 -# colorama==0.4.6 -from git import Repo, RemoteProgress -from tqdm import tqdm -from colorama import Fore - - -class CloneProgress: - operation_display = { - RemoteProgress.COUNTING: { - "description": "Counting ", - "units": "", - }, - RemoteProgress.COMPRESSING: { - "description": "Compressing ", - "units": "", - }, - RemoteProgress.WRITING: { - "description": "Writing ", - "units": "", - }, - RemoteProgress.RECEIVING: { - "description": "Receiving ", - "units": "", - }, - RemoteProgress.RESOLVING: { - "description": "Resolving ", - "units": "", - }, - RemoteProgress.FINDING_SOURCES: { - "description": "Finding Sources", - "units": "", - }, - RemoteProgress.CHECKING_OUT: { - "description": "Checking Out ", - "units": "", - }, - } - - def __init__(self): - self.progress = None - self.op_code = None - self.prev_count = 0 - - @property - def _description(self): - return self.operation_display[self.op_code]["description"] - - @property - def _units(self): - return self.operation_display[self.op_code]["units"] - - def __call__(self, - op_code: int, - cur_count: Union[str, float], - max_count: Union[str, float, None] = None, - _message: str = "",): - - if (self.op_code and (op_code & self.op_code) == 0): - print("WARNING: Different OP Code received before an end") - - if (op_code & RemoteProgress.BEGIN != 0): - self.op_code = op_code & 0b111111100 - self.current_progress = tqdm( - desc=self._description, - unit=self._units, - total=float(max_count) - ) - self.prev_count = 0 - - self.current_progress.update(cur_count - self.prev_count) - self.prev_count = cur_count - - if (op_code & RemoteProgress.END != 0): - self.current_progress.close() - self.op_code = None - - -# ---------------------- -# Create argument parser -# ---------------------- - -parser = argparse.ArgumentParser( - prog="Create New Project", - description="Configures a new project from a template" -) - -parser.add_argument( - "project_name" -) -parser.add_argument( - "-t", - "--template", - default="git@github.com:HyperloopUPV-H8/template-project.git", - help="Original template project", -) -parser.add_argument( - "-o", - "--output_dir", - default=os.getcwd(), - help="Directory where the project will be created" -) -parser.add_argument( - "--ioc", - default="template-project.ioc", - help="Name of the original template IOC file" -) - -def main(args: argparse.Namespace): - project_path = os.path.join(args.output_dir, args.project_name) - if (os.path.isdir(project_path) and len(os.listdir(project_path)) != 0): - print(Fore.RED + f"Output path {project_path} already contains files") - print(Fore.RESET, end="") - return 1 - - # -------------- - # Clone template - # -------------- - - print(Fore.BLUE + f"Cloning template project:") - print(Fore.BLUE + f"\tRepository: {args.template}") - print(Fore.BLUE + f"\tOutput path: {project_path}") - print(Fore.RESET) - - try: - Repo.clone_from(args.template, project_path, progress=CloneProgress()); - print() - except Exception as clone_error: - print() - print(Fore.RED + f"Failed to clone: {clone_error}") - print(Fore.RESET, end="") - return 1 - - # ------------- - # Prepare files - # ------------- - - # IOC configuration - os.rename( - os.path.join(project_path, args.ioc), - os.path.join(project_path, f"{args.project_name}.ioc") - ) - - # CMakeLists configuration - cmake_lists_path = os.path.join(project_path, "CMakeLists.txt") - with open(cmake_lists_path) as cmake_lists: - template_cmake_lists = cmake_lists.read() - - project_cmake_lists = re.sub(r"project *\( *[\w-]+ *ASM *C *CXX *\)", f"project({args.project_name} ASM C CXX)", template_cmake_lists) - - with open(cmake_lists_path, "w") as cmake_lists: - cmake_lists.write(project_cmake_lists) - - # VSCode workspace configuration - vscode_workspace_path = os.path.join(project_path, "template-project.code-workspace") - with open(vscode_workspace_path) as vscode_workspace: - template_vscode_workspace = vscode_workspace.read() - - project_vscode_workspace = re.sub( - r"\"name\"\s*:\s*\"ST-LIB\"\s*,\s*\"path\"\s*:\s*\".*\"", - f"\"name\": \"ST-LIB\",\n\t\t\"path\": \"../ST-LIB\"", - template_vscode_workspace - ) - - with open(os.path.join(project_path, f"{args.project_name}.code-workspace"), "w") as vscode_workspace: - vscode_workspace.write(project_vscode_workspace) - os.remove(vscode_workspace_path) - - # Remove this script from output - os.remove(os.path.join(project_path, "tools", "create-new-project.py")) - - build_script_path = os.path.join(project_path, "tools", "build.py") - with open(build_script_path) as build_script: - template_build_script = build_script.read() - - project_build_script = re.sub( - r"PROJECT_NAME[ \t]*=[ \t]*\"template-project\"", - f"PROJECT_NAME = \"{args.project_name}\"", - template_build_script - ) - - with open(build_script_path, "w") as build_script: - build_script.write(project_build_script) - - # --------------------------- - # Create new project git repo - # --------------------------- - - shutil.rmtree(os.path.join(project_path, ".git")) - new_project = Repo.init(project_path, mkdir=False) - new_project.git.add(project_path, all=True) - new_project.index.commit(f"Create {args.project_name} project") - - print(Fore.GREEN + f"Successfuly created {args.project_name} project") - print(Fore.RESET, end="") - - return 0 - -if __name__ == "__main__": - exit(main(parser.parse_args())) diff --git a/tools/requirements.txt b/tools/requirements.txt deleted file mode 100644 index 01313147..00000000 --- a/tools/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -colorama==0.4.6 -git-python==1.0.3 -tqdm==4.66.5