diff --git a/.cproject b/.cproject
index 34f11167..2589a7ba 100644
--- a/.cproject
+++ b/.cproject
@@ -403,4 +403,4 @@
-
\ No newline at end of file
+
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
deleted file mode 100644
index dafda299..00000000
--- a/.devcontainer/Dockerfile
+++ /dev/null
@@ -1,15 +0,0 @@
-FROM ubuntu:24.04
-
-# Install git, git-lfs, colorama and build tools
-RUN echo "deb http://security.ubuntu.com/ubuntu focal-security main universe" > /etc/apt/sources.list.d/ubuntu-focal-sources.list && \
- apt-get update && apt-get -y install git git-lfs python3 python3-pip curl python3-colorama cmake g++ build-essential libncurses5 libusb-1.0-0 gdb && \
- git lfs install
-
-# Install cubeclt
-RUN mkdir /temp && cd /temp && git clone https://github.com/HyperloopUPV-H8/cubeclt.git && \
- cd cubeclt && git lfs pull && chmod +x cubeclt_1.16.0_installer.sh && \
- echo | LICENSE_ALREADY_ACCEPTED=1 ./cubeclt_1.16.0_installer.sh
-
-ENV PATH="$PATH:/opt/st/stm32cubeclt_1.16.0/GNU-tools-for-STM32/bin:/opt/st/stm32cubeclt_1.16.0/CMake/bin:/opt/st/stm32cubeclt_1.16.0/Ninja/bin"
-
-ENV PYTHONPATH="/workspaces/template-project/Tests/VirtualMCU/src/:$PYTHONPATH"
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
deleted file mode 100644
index a2acd037..00000000
--- a/.devcontainer/devcontainer.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "name": "Dev Container for Template Project",
- "build": {
- "dockerfile": "Dockerfile",
- "options": [
- "--platform=linux/amd64"
- ]
- },
- "runArgs": [
- "--cap-add=SYS_PTRACE",
- "--security-opt=seccomp=unconfined"
- ],
- "remoteUser": "root",
- "customizations": {
- "vscode": {
- "extensions": [
- "ms-vscode.cpptools-extension-pack",
- "ms-python.python",
- "mcu-debug.debug-tracker-vscode",
- "marus25.cortex-debug"
- ]
- }
- }
-}
\ No newline at end of file
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 196da5a5..1400b512 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -50,7 +50,7 @@ jobs:
run: |
git config --global --add safe.directory '*'
git submodule update --init --depth 1
- ./deps/ST-LIB/tools/init-submodules.sh
+ ./deps/ST-LIB/tools/init-submodules.sh
shell: bash
- name: Setup Python environment
diff --git a/.github/workflows/format-checks.yml b/.github/workflows/format-checks.yml
index a225afb4..bc9db041 100644
--- a/.github/workflows/format-checks.yml
+++ b/.github/workflows/format-checks.yml
@@ -3,6 +3,7 @@ name: Format Checks
on:
workflow_dispatch:
pull_request:
+ branches: [ main ]
paths:
- '**.cpp'
- '**.hpp'
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 00000000..ebf153e4
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,69 @@
+name: Run Simulator Tests
+
+on:
+ workflow_dispatch:
+ pull_request:
+ branches: [ main ]
+
+concurrency:
+ group: tests-${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ tests:
+ runs-on: ubuntu-24.04
+ timeout-minutes: 30
+ permissions:
+ contents: read
+ packages: read
+
+ container:
+ image: ghcr.io/hyperloop-upv/hyperloop-firmware-toolchain:latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ submodules: false
+ fetch-depth: 1
+
+ - name: Init submodules
+ run: |
+ git config --global --add safe.directory '*'
+ git submodule update --init --depth 1
+ ./deps/ST-LIB/tools/init-submodules.sh
+ shell: bash
+
+ - name: Cache simulator deps
+ uses: actions/cache@v4
+ with:
+ path: out/build/simulator/_deps
+ key: template-simulator-deps-${{ runner.os }}-${{ hashFiles('CMakeLists.txt', 'deps/ST-LIB/CMakeLists.txt', 'deps/ST-LIB/Tests/CMakeLists.txt') }}
+ restore-keys: |
+ template-simulator-deps-${{ runner.os }}-
+
+ - name: Configure (CMake)
+ run: |
+ cmake --preset simulator
+ shell: bash
+
+ - name: Build
+ run: |
+ cmake --build --preset simulator
+ shell: bash
+
+ - name: Run tests (ctest)
+ run: |
+ ctest --preset simulator-all
+ shell: bash
+
+ - name: Upload test reports
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: simulator-test-reports
+ path: |
+ out/build/simulator/Testing/Temporary/LastTest.log
+ out/build/simulator/deps/ST-LIB/Testing/Temporary/LastTest.log
+ retention-days: 7
+ if-no-files-found: ignore
diff --git a/.mxproject b/.mxproject
index 4d55e80c..219f971a 100644
--- a/.mxproject
+++ b/.mxproject
@@ -31,4 +31,3 @@ SourcePath#0=..\LWIP\App
SourcePath#1=..\LWIP\Target
SourcePath#2=..\Core\Src
SourceFiles=;
-
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index be8bb296..2b383cc9 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -3,12 +3,18 @@ default_install_hook_types:
- pre-commit
- pre-push
repos:
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v5.0.0
+ hooks:
+ - id: check-merge-conflict
+ - id: end-of-file-fixer
+ - id: trailing-whitespace
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v17.0.6
hooks:
- id: clang-format
files: ^(Core/|tools/).*
+ exclude: ^(Core/Inc/Code_generation/Packet_generation/(DataTemplate\.hpp|OrderTemplate\.hpp)|tools/binary_metadata_template\.cpp)$
types_or:
- c
- c++
- exclude: ^Core/Inc/Code_generation/Packet_generation/.*Template\.hpp$|^tools/binary_metadata_template\.cpp$
diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
index 6a9c6db9..2455be23 100644
--- a/.vscode/c_cpp_properties.json
+++ b/.vscode/c_cpp_properties.json
@@ -9,4 +9,4 @@
}
],
"version": 4
-}
\ No newline at end of file
+}
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 74f0dee8..b04553fd 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -1,176 +1,228 @@
{
- "version": "0.2.0",
- "configurations": [
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "MCU | OpenOCD | Build + Debug (RTT)",
+ "type": "cortex-debug",
+ "request": "launch",
+ "cwd": "${workspaceFolder}",
+ "executable": "${workspaceFolder}/out/build/latest.elf",
+ "servertype": "openocd",
+ "serverpath": "openocd",
+ "configFiles": [
+ ".vscode/stlink.cfg",
+ ".vscode/stm32h7x.cfg"
+ ],
+ "serverArgs": [
+ "-c",
+ "transport select swd",
+ "-c",
+ "gdb_port 3333",
+ "-c",
+ "tcl_port 6666",
+ "-c",
+ "telnet_port 4444"
+ ],
+ "gdbPath": "arm-none-eabi-gdb",
+ "device": "STM32H723ZGTx",
+ "interface": "swd",
+ "runToEntryPoint": "main",
+ "svdFile": "${workspaceFolder}/STM32H723.svd",
+ "showDevDebugOutput": "parsed",
+ "preLaunchCommands": [
+ "monitor reset halt"
+ ],
+ "postLaunchCommands": [
+ "monitor rtt setup 0x24000000 0x24080000 \"SEGGER RTT\"",
+ "monitor rtt start",
+ "monitor rtt server start 9090 0"
+ ],
+ "postRestartCommands": [
+ "monitor halt",
+ "monitor rtt setup 0x24000000 0x24080000 \"SEGGER RTT\"",
+ "monitor rtt start",
+ "monitor rtt server start 9090 0"
+ ],
+ "rttConfig": {
+ "enabled": true,
+ "address": "auto",
+ "decoders": [
+ {
+ "port": 0,
+ "type": "console"
+ }
+ ]
+ },
+ "preLaunchTask": "CMake: build"
+ },
+ {
+ "name": "MCU | OpenOCD | Debug (No Build, RTT)",
+ "type": "cortex-debug",
+ "request": "launch",
+ "cwd": "${workspaceFolder}",
+ "executable": "${workspaceFolder}/out/build/latest.elf",
+ "servertype": "openocd",
+ "serverpath": "openocd",
+ "configFiles": [
+ ".vscode/stlink.cfg",
+ ".vscode/stm32h7x.cfg"
+ ],
+ "serverArgs": [
+ "-c",
+ "transport select swd",
+ "-c",
+ "gdb_port 3333",
+ "-c",
+ "tcl_port 6666",
+ "-c",
+ "telnet_port 4444"
+ ],
+ "gdbPath": "arm-none-eabi-gdb",
+ "device": "STM32H723ZGTx",
+ "interface": "swd",
+ "runToEntryPoint": "main",
+ "svdFile": "${workspaceFolder}/STM32H723.svd",
+ "showDevDebugOutput": "parsed",
+ "preLaunchCommands": [
+ "monitor reset halt"
+ ],
+ "postLaunchCommands": [
+ "monitor rtt setup 0x24000000 0x24080000 \"SEGGER RTT\"",
+ "monitor rtt start",
+ "monitor rtt server start 9090 0"
+ ],
+ "postRestartCommands": [
+ "monitor halt",
+ "monitor rtt setup 0x24000000 0x24080000 \"SEGGER RTT\"",
+ "monitor rtt start",
+ "monitor rtt server start 9090 0"
+ ],
+ "rttConfig": {
+ "enabled": true,
+ "address": "auto",
+ "decoders": [
+ {
+ "port": 0,
+ "type": "console"
+ }
+ ]
+ }
+ },
+ {
+ "name": "MCU | OpenOCD | Attach (External Server, RTT)",
+ "type": "cortex-debug",
+ "request": "attach",
+ "cwd": "${workspaceFolder}",
+ "executable": "${workspaceFolder}/out/build/latest.elf",
+ "servertype": "external",
+ "gdbTarget": "localhost:3333",
+ "gdbPath": "arm-none-eabi-gdb",
+ "device": "STM32H723ZGTx",
+ "interface": "swd",
+ "runToEntryPoint": "main",
+ "svdFile": "${workspaceFolder}/STM32H723.svd",
+ "showDevDebugOutput": "parsed",
+ "postAttachCommands": [
+ "monitor rtt setup 0x24000000 0x24080000 \"SEGGER RTT\"",
+ "monitor rtt start",
+ "monitor rtt server start 9090 0"
+ ],
+ "rttConfig": {
+ "enabled": true,
+ "address": "auto",
+ "decoders": [
+ {
+ "port": 0,
+ "type": "console"
+ }
+ ]
+ }
+ },
+ {
+ "name": "MCU | ST-LINK | Build + Debug",
+ "type": "cortex-debug",
+ "request": "launch",
+ "cwd": "${workspaceFolder}",
+ "executable": "${workspaceFolder}/out/build/latest.elf",
+ "servertype": "stlink",
+ "serverpath": "ST-LINK_gdbserver",
+ "gdbPath": "arm-none-eabi-gdb",
+ "device": "STM32H723ZGTx",
+ "interface": "swd",
+ "runToEntryPoint": "main",
+ "svdFile": "${workspaceFolder}/STM32H723.svd",
+ "showDevDebugOutput": "parsed",
+ "preLaunchCommands": [
+ "monitor reset halt"
+ ],
+ "preLaunchTask": "CMake: build"
+ },
+ {
+ "name": "MCU | ST-LINK | Debug (No Build)",
+ "type": "cortex-debug",
+ "request": "launch",
+ "cwd": "${workspaceFolder}",
+ "executable": "${workspaceFolder}/out/build/latest.elf",
+ "servertype": "stlink",
+ "serverpath": "ST-LINK_gdbserver",
+ "gdbPath": "arm-none-eabi-gdb",
+ "device": "STM32H723ZGTx",
+ "interface": "swd",
+ "runToEntryPoint": "main",
+ "svdFile": "${workspaceFolder}/STM32H723.svd",
+ "showDevDebugOutput": "parsed",
+ "preLaunchCommands": [
+ "monitor reset halt"
+ ]
+ },
+ {
+ "name": "MCU | ST-LINK | Attach (External GDB Server)",
+ "type": "cortex-debug",
+ "request": "attach",
+ "cwd": "${workspaceFolder}",
+ "executable": "${workspaceFolder}/out/build/latest.elf",
+ "servertype": "external",
+ "gdbTarget": "localhost:61234",
+ "gdbPath": "arm-none-eabi-gdb",
+ "device": "STM32H723ZGTx",
+ "interface": "swd",
+ "runToEntryPoint": "main",
+ "svdFile": "${workspaceFolder}/STM32H723.svd",
+ "showDevDebugOutput": "parsed",
+ "postAttachCommands": [
+ "monitor halt"
+ ]
+ },
+ {
+ "name": "SIM | Rosetta | Debug App",
+ "type": "cppdbg",
+ "request": "launch",
+ "program": "out/build/latest.elf",
+ "miDebuggerServerAddress": "localhost:1234",
+ "miDebuggerPath": "/usr/bin/gdb",
+ "MIMode": "gdb",
+ "setupCommands": [
{
- "name": "Build and Debug STM32H723 (OpenOCD + RTT)",
- "type": "cortex-debug",
- "request": "launch",
- "cwd": "${workspaceFolder}",
- "executable": "${workspaceFolder}/out/build/latest.elf",
- "servertype": "openocd",
- "configFiles": [
- "interface/stlink.cfg",
- "target/stm32h7x.cfg"
- ],
- "serverpath": "openocd",
- "device": "STM32H723ZGTx",
- "interface": "swd",
- "runToEntryPoint": "main",
- "svdFile": "./STM32H723.svd",
- "showDevDebugOutput": "parsed",
- "postLaunchCommands": [
- "monitor rtt setup 0x24000000 0x24080000 \"SEGGER RTT\"",
- "monitor rtt start",
- "monitor rtt server start 9090 0"
- ],
- "postRestartCommands": [
- "monitor halt",
- "monitor rtt setup 0x24000000 0x24080000 \"SEGGER RTT\"",
- "monitor rtt start",
- "monitor rtt server start 9090 0"
- ],
- "rttConfig": {
- "enabled": true,
- "address": "auto",
- "decoders": [
- {
- "port": 0,
- "type": "console"
- }
- ]
- },
- "preLaunchTask": "CMake: build"
- },
- {
- "name": "Debug STM32H723 (OpenOCD + RTT) - No Build",
- "type": "cortex-debug",
- "request": "launch",
- "cwd": "${workspaceFolder}",
- "executable": "${workspaceFolder}/out/build/latest.elf",
- "servertype": "openocd",
- "configFiles": [
- "interface/stlink.cfg",
- "target/stm32h7x.cfg"
- ],
- "serverpath": "openocd",
- "device": "STM32H723ZGTx",
- "interface": "swd",
- "runToEntryPoint": "main",
- "svdFile": "./STM32H723.svd",
- "showDevDebugOutput": "parsed",
- "postLaunchCommands": [
- "monitor rtt setup 0x24000000 0x24080000 \"SEGGER RTT\"",
- "monitor rtt start",
- "monitor rtt server start 9090 0"
- ],
- "postRestartCommands": [
- "monitor halt",
- "monitor rtt setup 0x24000000 0x24080000 \"SEGGER RTT\"",
- "monitor rtt start",
- "monitor rtt server start 9090 0"
- ],
- "rttConfig": {
- "enabled": true,
- "address": "auto",
- "decoders": [
- {
- "port": 0,
- "type": "console"
- }
- ]
- },
- // "preLaunchTask": "Pre-flash check"
- },
- {
- "name": "Debug simulator on Rosetta",
- "type": "cppdbg",
- "request": "launch",
- "program": "out/build/latest.elf",
- "miDebuggerServerAddress": "localhost:1234",
- "miDebuggerPath": "/usr/bin/gdb",
- "MIMode": "gdb",
- "setupCommands": [
- {
- "description": "Set architecture to x86-64",
- "text": "set architecture i386:x86-64",
- "ignoreFailures": false
- }
- ],
- "preLaunchTask": "Start Debug Server for Simulator on emulated arch",
- "cwd": "${workspaceFolder}",
- "externalConsole": false
- },
- {
- "name": "Debug ST-LIB tests (simulator)",
- "type": "cppdbg",
- "request": "launch",
- "program": "${workspaceFolder}/out/build/simulator/deps/ST-LIB/Tests/st-lib-test",
- "args": [],
- "cwd": "${workspaceFolder}",
- "externalConsole": false,
- "stopAtEntry": false,
- "MIMode": "lldb",
- "preLaunchTask": "Tests: Build simulator"
- },
- {
- "type": "cortex-debug",
- "request": "launch",
- "name": "Build and Debug Project",
- "servertype": "stlink",
- "cwd": "${workspaceRoot}",
- "runToEntryPoint": "main",
- "showDevDebugOutput": "raw",
- "executable": "out/build/latest.elf",
- "device": "STM32H723ZG",
- "configFiles": [
- ".vscode/stlink.cfg",
- ".vscode/stm32h7x.cfg"
- ],
- "svdFile": ".vscode/STM32H723.svd",
- "swoConfig": {
- "enabled": true,
- "cpuFrequency": 8000000,
- "swoFrequency": 2000000,
- "source": "probe",
- "decoders": [
- {
- "type": "console",
- "label": "ITM",
- "port": 0
- }
- ]
- },
- "preLaunchTask": "CMake: build"
- },
- {
- "type": "cortex-debug",
- "request": "launch",
- "name": "Debug Project",
- "servertype": "stlink",
- "cwd": "${workspaceRoot}",
- "runToEntryPoint": "main",
- "showDevDebugOutput": "raw",
- "executable": "out/build/latest.elf",
- "device": "STM32H723ZG",
- "configFiles": [
- ".vscode/stlink.cfg",
- ".vscode/stm32h7x.cfg"
- ],
- "svdFile": "./STM32H723.svd",
- "swoConfig": {
- "enabled": true,
- "cpuFrequency": 8000000,
- "swoFrequency": 2000000,
- "source": "probe",
- "decoders": [
- {
- "type": "console",
- "label": "ITM",
- "port": 0
- }
- ]
- },
- "stm32cubeprogrammer": "/opt/st/stm32cubeclt_1.16.0/STM32CubeProgrammer/bin"
+ "description": "Set architecture to x86-64",
+ "text": "set architecture i386:x86-64",
+ "ignoreFailures": false
}
- ]
+ ],
+ "preLaunchTask": "SIM | Rosetta | Start Debug Server",
+ "cwd": "${workspaceFolder}",
+ "externalConsole": false
+ },
+ {
+ "name": "SIM | ST-LIB Tests | Debug",
+ "type": "cppdbg",
+ "request": "launch",
+ "program": "${workspaceFolder}/out/build/simulator/deps/ST-LIB/Tests/st-lib-test",
+ "args": [],
+ "cwd": "${workspaceFolder}",
+ "externalConsole": false,
+ "stopAtEntry": false,
+ "MIMode": "lldb",
+ "preLaunchTask": "SIM | Tests | Build"
+ }
+ ]
}
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 05284a38..31213400 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -2,42 +2,112 @@
"version": "2.0.0",
"tasks": [
{
- "label": "Start Debug Server for Simulator on emulated arch",
+ "label": "SIM | Rosetta | Start Debug Server",
"type": "shell",
"command": "ROSETTA_DEBUGSERVER_PORT=1234 ./out/build/latest.elf",
"problemMatcher": [],
"isBackground": true
},
{
- "label": "Tests: Configure simulator",
+ "label": "MCU | OpenOCD | Start Server",
+ "type": "shell",
+ "command": "openocd",
+ "args": [
+ "-f",
+ ".vscode/stlink.cfg",
+ "-f",
+ ".vscode/stm32h7x.cfg",
+ "-c",
+ "transport select swd",
+ "-c",
+ "gdb_port 3333",
+ "-c",
+ "tcl_port 6666",
+ "-c",
+ "telnet_port 4444"
+ ],
+ "isBackground": true,
+ "problemMatcher": {
+ "owner": "custom",
+ "pattern": [
+ {
+ "regexp": ".*",
+ "message": 0
+ }
+ ],
+ "background": {
+ "activeOnStart": true,
+ "beginsPattern": ".*",
+ "endsPattern": "Listening on port 3333 for gdb connections"
+ }
+ },
+ "presentation": {
+ "reveal": "always",
+ "panel": "dedicated",
+ "clear": true
+ }
+ },
+ {
+ "label": "MCU | OpenOCD | RTT Console",
+ "type": "shell",
+ "command": "nc 127.0.0.1 9090",
+ "problemMatcher": [],
+ "presentation": {
+ "reveal": "always",
+ "panel": "new"
+ }
+ },
+ {
+ "label": "MCU | ST-LINK | Start GDB Server",
+ "type": "shell",
+ "command": "ST-LINK_gdbserver",
+ "args": [
+ "-p",
+ "61234",
+ "-d",
+ "-e",
+ "--halt",
+ "--frequency",
+ "4000"
+ ],
+ "problemMatcher": [],
+ "isBackground": true,
+ "presentation": {
+ "reveal": "always",
+ "panel": "dedicated",
+ "clear": true
+ }
+ },
+ {
+ "label": "SIM | Tests | Configure",
"type": "shell",
"command": "cmake --preset simulator",
"problemMatcher": []
},
{
- "label": "Tests: Build simulator",
+ "label": "SIM | Tests | Build",
"type": "shell",
"command": "cmake --build --preset simulator -j8",
"dependsOn": [
- "Tests: Configure simulator"
+ "SIM | Tests | Configure"
],
"problemMatcher": []
},
{
- "label": "Tests: Run all (simulator)",
+ "label": "SIM | Tests | Run All",
"type": "shell",
- "command": "ctest --test-dir out/build/simulator/deps/ST-LIB --output-on-failure",
+ "command": "ctest --preset simulator-all",
"dependsOn": [
- "Tests: Build simulator"
+ "SIM | Tests | Build"
],
"problemMatcher": []
},
{
- "label": "Tests: Run ADC (simulator)",
+ "label": "SIM | Tests | Run ADC",
"type": "shell",
- "command": "ctest --test-dir out/build/simulator/deps/ST-LIB -R ADCTest --output-on-failure",
+ "command": "ctest --preset simulator-adc",
"dependsOn": [
- "Tests: Build simulator"
+ "SIM | Tests | Build"
],
"problemMatcher": []
}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 83570067..c1d122ca 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,9 +1,14 @@
cmake_minimum_required(VERSION 3.14)
project(template-project LANGUAGES ASM C CXX)
+include(CTest)
+enable_testing()
set(EXECUTABLE ${PROJECT_NAME}.elf)
-set(Board "TEST") # User must change the Board name
+set(BOARD_NAME "TEST" CACHE STRING "Board key from Core/Inc/Code_generation/JSON_ADE/boards.json")
+if(BOARD_NAME STREQUAL "")
+ message(FATAL_ERROR "BOARD_NAME cannot be empty")
+endif()
set(STLIB_DIR ${CMAKE_CURRENT_LIST_DIR}/deps/ST-LIB)
set(LD_SCRIPT ${STLIB_DIR}/STM32H723ZGTX_FLASH.ld)
@@ -16,6 +21,11 @@ if(CMAKE_HOST_WIN32)
else()
set(VENV_PYTHON ${CMAKE_SOURCE_DIR}/virtual/bin/python)
endif()
+if(EXISTS "${VENV_PYTHON}")
+ set(PYTHON_FOR_TOOLS "${VENV_PYTHON}")
+else()
+ set(PYTHON_FOR_TOOLS "${Python3_EXECUTABLE}")
+endif()
option(USE_ETHERNET "Enable ethernet peripheral" OFF)
option(TARGET_NUCLEO "Targets the STM32H723 Nucleo development board" OFF)
@@ -39,28 +49,16 @@ if(USE_CCACHE)
endif()
endif()
-if(PROJECT_IS_TOP_LEVEL AND (NOT CMAKE_CROSSCOMPILING))
- include(FetchContent)
- option(BUILD_GMOCK OFF)
- option(INSTALL_GTEST OFF)
- FetchContent_Declare(
- googletest
- GIT_REPOSITORY https://github.com/google/googletest.git
- GIT_TAG v1.15.2
- )
- FetchContent_MakeAvailable(googletest)
- add_library(GTest::GTest INTERFACE IMPORTED)
- target_link_libraries(GTest::GTest INTERFACE gtest_main)
-endif()
-
message(STATUS "Template project: CMAKE_CROSSCOMPILING = ${CMAKE_CROSSCOMPILING}")
message(STATUS "Template project: USE_ETHERNET = ${USE_ETHERNET}")
message(STATUS "Template project: TARGET_NUCLEO = ${TARGET_NUCLEO}")
+message(STATUS "Template project: BOARD_NAME = ${BOARD_NAME}")
add_subdirectory(${STLIB_DIR})
message(STATUS "Using ST-LIB target: ${STLIB_LIBRARY}")
file(GLOB_RECURSE GENERATOR_JSONS
+ CONFIGURE_DEPENDS
${CMAKE_SOURCE_DIR}/Core/Inc/Code_generation/JSON_ADE/*.json
)
@@ -70,8 +68,7 @@ add_custom_command(
OUTPUT
${GENERATED_DATA_PACKETS}
${GENERATED_ORDER_PACKETS}
- ${GENERATED_STATE_MACHINE}
- COMMAND ${VENV_PYTHON} ${GENERATOR_SCRIPT} ${Board}
+ COMMAND ${PYTHON_FOR_TOOLS} ${GENERATOR_SCRIPT} ${BOARD_NAME}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
DEPENDS
${GENERATOR_SCRIPT}
@@ -79,16 +76,17 @@ add_custom_command(
${CMAKE_SOURCE_DIR}/Core/Inc/Code_generation/Packet_generation/DataTemplate.hpp
${CMAKE_SOURCE_DIR}/Core/Inc/Code_generation/Packet_generation/OrderTemplate.hpp
${GENERATOR_JSONS}
- COMMENT "Generating packets for ${Board}"
+ COMMENT "Generating packets for ${BOARD_NAME}"
)
-add_custom_target(run_generator ALL
+add_custom_target(run_generator
DEPENDS
${GENERATED_DATA_PACKETS}
${GENERATED_ORDER_PACKETS}
)
file(GLOB_RECURSE METADATA_SOURCES
+ CONFIGURE_DEPENDS
${CMAKE_SOURCE_DIR}/Core/*.c
${CMAKE_SOURCE_DIR}/Core/*.cpp
${CMAKE_SOURCE_DIR}/Core/*.h
@@ -103,7 +101,7 @@ list(REMOVE_ITEM METADATA_SOURCES ${METADATA_OUTPUT})
add_custom_command(
OUTPUT ${METADATA_OUTPUT}
- COMMAND ${VENV_PYTHON} ${METADATA_SCRIPT}
+ COMMAND ${PYTHON_FOR_TOOLS} ${METADATA_SCRIPT}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
DEPENDS
${METADATA_SCRIPT}
@@ -117,13 +115,13 @@ add_custom_target(generate_binary_metadata
)
if(CMAKE_CROSSCOMPILING)
- file(GLOB_RECURSE SOURCE_C ${CMAKE_SOURCE_DIR}/Core/*.c)
- file(GLOB_RECURSE SOURCE_CPP ${CMAKE_SOURCE_DIR}/Core/*.cpp)
- file(GLOB_RECURSE SOURCE_H ${CMAKE_SOURCE_DIR}/Core/*.h)
- file(GLOB_RECURSE SOURCE_HPP ${CMAKE_SOURCE_DIR}/Core/*.hpp)
+ file(GLOB_RECURSE SOURCE_C CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/Core/*.c)
+ file(GLOB_RECURSE SOURCE_CPP CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/Core/*.cpp)
+ file(GLOB_RECURSE SOURCE_H CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/Core/*.h)
+ file(GLOB_RECURSE SOURCE_HPP CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/Core/*.hpp)
if(NOT BUILD_EXAMPLES)
- file(GLOB_RECURSE EXAMPLE_CPP ${CMAKE_SOURCE_DIR}/Core/Src/Examples/*.cpp)
+ file(GLOB_RECURSE EXAMPLE_CPP CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/Core/Src/Examples/*.cpp)
list(REMOVE_ITEM SOURCE_CPP ${EXAMPLE_CPP})
endif()
diff --git a/CMakePresets.json b/CMakePresets.json
index f59704a4..4e441148 100644
--- a/CMakePresets.json
+++ b/CMakePresets.json
@@ -203,6 +203,17 @@
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
+ },
+ {
+ "name": "simulator-asan",
+ "displayName": "Simulator [ASAN+UBSAN]",
+ "inherits": [
+ "sim"
+ ],
+ "cacheVariables": {
+ "CMAKE_BUILD_TYPE": "Debug",
+ "STLIB_ENABLE_SANITIZERS": "ON"
+ }
}
],
"buildPresets": [
@@ -269,6 +280,41 @@
{
"name": "simulator",
"configurePreset": "simulator"
+ },
+ {
+ "name": "simulator-asan",
+ "configurePreset": "simulator-asan"
+ }
+ ],
+ "testPresets": [
+ {
+ "name": "simulator-all",
+ "configurePreset": "simulator",
+ "output": {
+ "outputOnFailure": true
+ },
+ "execution": {
+ "noTestsAction": "error"
+ }
+ },
+ {
+ "name": "simulator-adc",
+ "inherits": "simulator-all",
+ "filter": {
+ "include": {
+ "name": "ADCTest"
+ }
+ }
+ },
+ {
+ "name": "simulator-all-asan",
+ "configurePreset": "simulator-asan",
+ "output": {
+ "outputOnFailure": true
+ },
+ "execution": {
+ "noTestsAction": "error"
+ }
}
]
}
diff --git a/Core/Inc/Code_generation/Generator.py b/Core/Inc/Code_generation/Generator.py
index b308426c..774d9aaf 100644
--- a/Core/Inc/Code_generation/Generator.py
+++ b/Core/Inc/Code_generation/Generator.py
@@ -1,32 +1,28 @@
-import sys
-from Packet_generation.Packet_generation import *
+import argparse
+from Packet_generation.Packet_generation import (
+ Generate_PacketDescription,
+ Generate_DataPackets_hpp,
+ Generate_OrderPackets_hpp,
+)
-if len(sys.argv)<2:
- print("Please enter a board name,exiting...")
- sys.exit()
-
-JSONpath = "Core/Inc/Code_generation/JSON_ADE"
-aux = sys.argv[1]
-filtered = ""
-for char in aux:
- if char.isalpha():
- filtered += char
- else:
- break
-board = filtered
+def parse_args():
+ parser = argparse.ArgumentParser(description="Generate packet headers from JSON_ADE")
+ parser.add_argument("board", help="Board key from Core/Inc/Code_generation/JSON_ADE/boards.json")
+ return parser.parse_args()
-boards = Generate_PacketDescription(JSONpath, board)
-if __name__ == "__main__":
+def main():
+ args = parse_args()
+ json_path = "Core/Inc/Code_generation/JSON_ADE"
+ board = args.board.strip()
+ if not board:
+ raise SystemExit("Board name cannot be empty")
+
+ Generate_PacketDescription(json_path, board)
Generate_DataPackets_hpp(board)
Generate_OrderPackets_hpp(board)
-
-
-
-
-
-
-
\ No newline at end of file
+if __name__ == "__main__":
+ main()
diff --git a/Core/Inc/Code_generation/Packet_generation/DataTemplate.hpp b/Core/Inc/Code_generation/Packet_generation/DataTemplate.hpp
index 23cc3d9f..02030066 100644
--- a/Core/Inc/Code_generation/Packet_generation/DataTemplate.hpp
+++ b/Core/Inc/Code_generation/Packet_generation/DataTemplate.hpp
@@ -1,27 +1,27 @@
#pragma once
#include "ST-LIB.hpp"
-/*Data packets for {{board}}
+/*Data packets for {{board}}
-AUTOGENERATED CODE, DO NOT MODIFY-*/
class DataPackets{
public:
{% for enum in enums -%}
- enum class {{enum.name}} : uint8_t
+ enum class {{enum.name}} : uint8_t
{
{%- for value in enum["values"] %}
{{value}} = {{loop.index0}},
{%- endfor %}
};
{% endfor %}
-
+
{% for packet in packets -%}
static void {{packet.name}}_init({% for variable in packet.variables %}{{variable.type}} &{{variable.name}}{% if not loop.last %}, {% endif %}{% endfor %})
{
{{packet.name}}_packet = new HeapPacket(static_cast({{packet.id}}){% if packet.variables %}, {% for variable in packet.variables %}&{{variable.name}}{% if not loop.last %}, {% endif %}{% endfor %}{% endif %});
}
-
+
{% endfor -%}
-
+
public:
{%for packet in packets -%}
inline static HeapPacket *{{packet.name}}_packet{nullptr};
@@ -29,9 +29,9 @@ class DataPackets{
{% for socket in DatagramSockets -%}
inline static {{socket.type}} *{{socket.name}}{nullptr};
{% endfor %}
-
+
static void start()
- {
+ {
{% for packet in packets -%}
if ({{packet.name}}_packet == nullptr) {
ErrorHandler("Packet {{packet.name}} not initialized");
@@ -41,7 +41,7 @@ class DataPackets{
{% for socket in DatagramSockets -%}
{{socket.name}} = new DatagramSocket("{{socket.board_ip}}",{{socket.port}},"{{socket.remote_ip}}",{{socket.port}});
{% endfor %}
-
+
{%- for group in sending_packets %}
Scheduler::register_task({% if group.period_type == "ms" %}{{ (group.period*1000)|round|int }}{% else %}{{ group.period|round|int }}{% endif %}, +[](){
{% for packet in group.packets -%}
@@ -52,5 +52,5 @@ class DataPackets{
}
-
+
};
diff --git a/Core/Inc/Code_generation/Packet_generation/OrderTemplate.hpp b/Core/Inc/Code_generation/Packet_generation/OrderTemplate.hpp
index 46bdd414..2ac2ced3 100644
--- a/Core/Inc/Code_generation/Packet_generation/OrderTemplate.hpp
+++ b/Core/Inc/Code_generation/Packet_generation/OrderTemplate.hpp
@@ -1,14 +1,14 @@
#pragma once
#include "ST-LIB.hpp"
-/*Order packets for {{board}}
+/*Order packets for {{board}}
-AUTOGENERATED CODE, DO NOT MODIFY- */
class OrderPackets{
public:
{% for enum in enums -%}
- enum class {{enum.name}} : uint8_t
+ enum class {{enum.name}} : uint8_t
{
{%- for value in enum["values"] %}
{{value}} = {{loop.index0}},
@@ -25,7 +25,7 @@ class OrderPackets{
{% for packet in packets -%}
inline static HeapOrder *{{packet.name}}_order{nullptr};
{% endfor %}
-
+
{% for packet in packets -%}
static void {{packet.name}}_init({% for variable in packet.variables %}{{variable.type}} &{{variable.name}}{% if not loop.last %}, {% endif %}{% endfor %})
{
@@ -63,4 +63,4 @@ class OrderPackets{
{{packet.name}}_flag = true;
}
{% endfor %}
-};
\ No newline at end of file
+};
diff --git a/Core/Inc/Code_generation/Packet_generation/Packet_descriptions.py b/Core/Inc/Code_generation/Packet_generation/Packet_descriptions.py
index 5e9b2cb0..6399b6a8 100644
--- a/Core/Inc/Code_generation/Packet_generation/Packet_descriptions.py
+++ b/Core/Inc/Code_generation/Packet_generation/Packet_descriptions.py
@@ -1,4 +1,4 @@
-import re
+import re
import json
class BoardDescription:
@@ -13,7 +13,7 @@ def __init__(self,name:str,board:dict,JSONpath:str):
self.sockets=self.SocketsDescription(socks,self.ip)
except Exception as e:
raise Exception(f"Error in file {JSONpath}/boards/{name}/sockets.json: {e}")
- #Packets:
+ #Packets:
self.sending_packets = []
self.data_size =0
self.order_size =0
@@ -40,15 +40,15 @@ def __init__(self,name:str,board:dict,JSONpath:str):
aux_sending= PacketDescription.check_for_sending(packet)
if aux_sending is not None:
self.sending_packets.append(aux_sending)
-
+
if self.packets[packets_name][i].type != "order":
self.data_size += 1
else:
self.order_size += 1
i += 1
-
+
self.sending_packets = self.fix_sendind_packets(self.sending_packets)
-
+
@staticmethod
def fix_sendind_packets(sending_packets:list):
fixed_packets = []
@@ -72,9 +72,9 @@ def fix_sendind_packets(sending_packets:list):
fixed_packets.append(entry)
return fixed_packets
-
-
-
+
+
+
class SocketsDescription:
def __init__(self,sockets:list,board_ip:str):
self.allSockets=[]
@@ -86,16 +86,16 @@ def __init__(self,sockets:list,board_ip:str):
name = sock["name"].replace(" ", "_").replace("-", "_")
sock_type = sock["type"]
self.allSockets.append({"name": name,"type":sock_type})
-
+
if sock_type == "ServerSocket":
self.ServerSockets.append({"name": name,"type":sock_type,"board_ip":self.board_ip, "port": sock["port"]})
elif sock_type == "Socket":
self.Sockets.append({"name": name,"type":sock_type,"board_ip":self.board_ip, "local_port": sock["local_port"], "remote_ip": sock["remote_ip"], "remote_port": sock["remote_port"]})
elif sock_type == "DatagramSocket":
self.DatagramSockets.append({"name": name,"type":sock_type,"board_ip":self.board_ip, "port": sock["port"],"remote_ip":sock["remote_ip"]})
-
-
+
+
class PacketDescription:
def __init__(self, packet:dict,measurements:list, filename:str="Unknown"):
self.id =packet["id"]
@@ -108,13 +108,13 @@ def __init__(self, packet:dict,measurements:list, filename:str="Unknown"):
for variable in packet["variables"]:
self.variables.append(variable)
self.measurements.append(MeasurmentsDescription(measurements,variable, filename))
-
+
@staticmethod
def check_for_sending(packet:dict):
if "period" in packet and "period_type" in packet and "socket" in packet:
name = packet["name"].replace(" ", "_").replace("-", "_")
return {"name": name,"period": packet["period"],"period_type":packet["period_type"],"socket": packet["socket"]}
-
+
elif "period_ms" in packet and "socket" in packet:
name = packet["name"].replace(" ", "_").replace("-", "_")
return {"name": name,"period": packet["period_ms"],"period_type":"ms","socket": packet["socket"]}
@@ -126,11 +126,11 @@ def __init__(self,measurements:list, variable:str, filename:str="Unknown"):
if not hasattr(self.__class__, 'viewed_measurements'):
self.__class__.viewed_measurements = {}
measurement = self._MeasurementSearch(measurements,variable)
-
+
if measurement is None:
print(f"Measurement not found for variable: {variable} in file: {filename}\n")
raise Exception(f"Measurement not found for variable: {variable} in file: {filename}")
-
+
self.name = measurement["name"]
self.type = (self._unsigned_int_correction(measurement["type"]).replace(" ", "_").replace("-", "_"))
if self.type == "enum":
@@ -145,8 +145,8 @@ def _Enum_values_correction(values:list):
for i in range(len(values)):
values[i] = values[i].replace(" ", "_").replace("-", "_")
return values
-
-
+
+
@staticmethod
def _MeasurementSearch(measurements:list, variable:str):
if variable in MeasurmentsDescription.viewed_measurements:
@@ -157,8 +157,8 @@ def _MeasurementSearch(measurements:list, variable:str):
MeasurmentsDescription.viewed_measurements[variable] = measurment
return measurment
return None
-
-
+
+
@staticmethod
def _unsigned_int_correction(type:str):
aux_type = type[:4]
@@ -166,4 +166,4 @@ def _unsigned_int_correction(type:str):
type += "_t"
elif type == "float32":
type = "float"
- return type
\ No newline at end of file
+ return type
diff --git a/Core/Inc/Code_generation/Packet_generation/Packet_generation.py b/Core/Inc/Code_generation/Packet_generation/Packet_generation.py
index f554949b..d852d367 100644
--- a/Core/Inc/Code_generation/Packet_generation/Packet_generation.py
+++ b/Core/Inc/Code_generation/Packet_generation/Packet_generation.py
@@ -6,7 +6,7 @@
templates_path = "Core/Inc/Code_generation/Packet_generation"
-def Generate_PacketDescription(JSONpath:str,board:str):
+def Generate_PacketDescription(JSONpath:str,board:str):
with open(JSONpath+"/boards.json") as f:
boards = json.load(f)
boards_name = []
@@ -20,9 +20,9 @@ def Generate_PacketDescription(JSONpath:str,board:str):
else:
print(f"Board {board} not found, exiting...")
sys.exit()
-
+
return boards_name
-
+
#--------------DataPackets.hpp generation---------------#
@@ -36,8 +36,8 @@ def GenerateDataEnum(board:BoardDescription):
if hasattr(measurement, "enum")and measurement.enum not in Enums:
Enums.append(measurement.enum)
return Enums
-
-
+
+
def GenerateDataPackets(board:BoardDescription):
Packets =[]
totaldata = []
@@ -50,10 +50,10 @@ def GenerateDataPackets(board:BoardDescription):
tempdata +=(str(variable) +",")
tempdata_but_pointer +=("&"+str(variable) +",")
if tempdata.endswith(","):
- tempdata = tempdata[:-1]
+ tempdata = tempdata[:-1]
if tempdata_but_pointer.endswith(","):
tempdata_but_pointer = tempdata_but_pointer[:-1]
-
+
packet_variables = []
for measurement in packet_instance.measurements:
packet_variables.append({
@@ -67,11 +67,11 @@ def GenerateDataPackets(board:BoardDescription):
aux_data = {"type": measurement.type, "name": measurement.id.replace(" ", "_").replace("-", "_")}
if not any(x["name"] == aux_data["name"] for x in totaldata):
totaldata.append(aux_data)
-
+
return Packets,totaldata
-
+
packets,data = GenerateDataPackets(board)
-
+
def GenerateGroupedSendingPackets(board: BoardDescription):
datagram_sockets = [s["name"] for s in board.sockets.DatagramSockets]
grouped_lookup = {}
@@ -84,17 +84,17 @@ def GenerateGroupedSendingPackets(board: BoardDescription):
period = packet["period"]
period_type = packet["period_type"]
names = packet["name"]
-
+
key = (period, period_type)
if key not in grouped_lookup:
grouped_lookup[key] = []
-
+
if isinstance(names, list):
for name in names:
grouped_lookup[key].append({"socket": socket_name, "name": name})
else:
grouped_lookup[key].append({"socket": socket_name, "name": names})
-
+
grouped_list = []
for (period, period_type), items in grouped_lookup.items():
grouped_list.append({
@@ -123,16 +123,16 @@ def Generate_DataPackets_hpp(board_input:str):
if board_instance.data_size == 0:
if os.path.exists(data_packets_path):
os.remove(data_packets_path)
- return
-
+ return
+
env= jinja2.Environment(loader=jinja2.FileSystemLoader(templates_path))
template = env.get_template("DataTemplate.hpp")
context = Get_data_context(board_instance)
-
+
with open(data_packets_path,"w") as Output:
Output.write(template.render(context))
-
+
#--------------OrderPackets.hpp generation---------------#
def Get_order_context(board:BoardDescription):
@@ -145,8 +145,8 @@ def GenerateOrderEnum(board:BoardDescription):
if hasattr(measurement, "enum") and measurement.enum not in Enums:
Enums.append(measurement.enum)
return Enums
-
-
+
+
def GenerateOrderPackets(board:BoardDescription):
Packets =[]
totaldata = []
@@ -159,8 +159,8 @@ def GenerateOrderPackets(board:BoardDescription):
tempdata +=(str(variable) +",")
tempdata_but_pointer +=("&"+str(variable) +",")
if tempdata.endswith(","):
- tempdata = tempdata[:-1]
- tempdata_but_pointer = tempdata_but_pointer[:-1]
+ tempdata = tempdata[:-1]
+ tempdata_but_pointer = tempdata_but_pointer[:-1]
packet_variables = []
for measurement in packet_instance.measurements:
@@ -175,10 +175,10 @@ def GenerateOrderPackets(board:BoardDescription):
aux_data = {"type": measurement.type, "name": measurement.id}
if not any(x["name"] == aux_data["name"] for x in totaldata):
totaldata.append(aux_data)
-
+
return Packets,totaldata
-
-
+
+
packets,data = GenerateOrderPackets(board)
context = {
"board": board.name,
@@ -197,14 +197,12 @@ def Generate_OrderPackets_hpp(board_input:str):
if board_instance.order_size == 0:
if os.path.exists(order_packets_path):
os.remove(order_packets_path)
- return
-
+ return
+
env= jinja2.Environment(loader=jinja2.FileSystemLoader(templates_path))
template = env.get_template("OrderTemplate.hpp")
context = Get_order_context(board_instance)
-
+
with open(order_packets_path,"w") as Output:
Output.write(template.render(context))
-
-
diff --git a/Core/Inc/Communications/Packets/.gitkeep b/Core/Inc/Communications/Packets/.gitkeep
index d3f5a12f..e69de29b 100644
--- a/Core/Inc/Communications/Packets/.gitkeep
+++ b/Core/Inc/Communications/Packets/.gitkeep
@@ -1 +0,0 @@
-
diff --git a/Core/Src/Examples/ExampleMPU.cpp b/Core/Src/Examples/ExampleMPU.cpp
index 12a70575..f85a8a66 100644
--- a/Core/Src/Examples/ExampleMPU.cpp
+++ b/Core/Src/Examples/ExampleMPU.cpp
@@ -549,4 +549,4 @@ void assert_failed(uint8_t* file, uint32_t line) {
}
}
-#endif
\ No newline at end of file
+#endif
diff --git a/Core/Src/Examples/ExamplesHardFault.cpp b/Core/Src/Examples/ExamplesHardFault.cpp
index 903222ee..0b2eb1f1 100644
--- a/Core/Src/Examples/ExamplesHardFault.cpp
+++ b/Core/Src/Examples/ExamplesHardFault.cpp
@@ -56,4 +56,4 @@ int main(void) {
}
#endif
-#endif
\ No newline at end of file
+#endif
diff --git a/Core/Src/Runes/generated_metadata.cpp b/Core/Src/Runes/generated_metadata.cpp
index fe7c9755..6350bc43 100644
--- a/Core/Src/Runes/generated_metadata.cpp
+++ b/Core/Src/Runes/generated_metadata.cpp
@@ -12,4 +12,4 @@ const char DESCRIPTION[255] __attribute__((section(".metadata_pool"))) =
"4b3d0ec4" // Board commit
// the '=' is used for unparsing
;
-}
\ No newline at end of file
+}
diff --git a/Core/Src/config/leds_hard_fault.cpp b/Core/Src/config/leds_hard_fault.cpp
index be2d3a0e..2494f3ca 100644
--- a/Core/Src/config/leds_hard_fault.cpp
+++ b/Core/Src/config/leds_hard_fault.cpp
@@ -21,4 +21,4 @@ uint8_t hard_fault_leds_count =
? sizeof(pins_hard_fault) / sizeof(uint16_t)
: 0;
#endif
-}
\ No newline at end of file
+}
diff --git a/Core/Src/syscalls.c b/Core/Src/syscalls.c
index 34280458..6b35c655 100644
--- a/Core/Src/syscalls.c
+++ b/Core/Src/syscalls.c
@@ -149,4 +149,4 @@ int _execve(char* name, char** argv, char** env) {
return -1;
}
-int _getentropy(void* buffer, size_t length) { return -ENOSYS; }
\ No newline at end of file
+int _getentropy(void* buffer, size_t length) { return -ENOSYS; }
diff --git a/README.md b/README.md
index 70aa7730..a5f9b940 100644
--- a/README.md
+++ b/README.md
@@ -1,40 +1,52 @@
# Template Project
-HyperloopUPV's Template project for STM32 development with LwIP.
+HyperloopUPV STM32 firmware template based on CMake + VSCode, using `deps/ST-LIB`.
-Designed using CMake with defaults for development with VSCode.
+## Quickstart
-This makes use of the [ST-LIB](https://github.com/HyperloopUPV-H8/ST-LIB) developed by HyperloopUPV's team.
+```sh
+./tools/init.sh
+cmake --preset simulator
+cmake --build --preset simulator
+ctest --preset simulator-all
+```
-## Container Setup
-To use it you must install [Dev Containers extension on VSCode](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) and [Docker](https://www.docker.com). Be careful to use the instructions related to your OS, as docker not works in the same way exactly between them.
-Then, when you open this folder in VSCode, you will have the ability to reopen it inside the container. Don't worry, the first time you do it takes a loong time.
-## SetUp
-Create a virtual environment with
->python3 -m venv virtual
+## Documentation
-at the root of the project
-## Modes
-### Simulator
-The container is fully ready to develop, compile and debug the code in simulator mode, so you don't have to worry about setting your environment
-### MCU
-The container is ready to develop and compile the code in MCU mode, but it couldn't be possible to flash and debug through it, so you should do it in your local machine. To do it, you must install the [STM32CubeCLT](https://www.st.com/en/development-tools/stm32cubeclt.html).
-To flash and debug, you should be outside the container, and use the [Cortex-Debug VSCode extension](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug)
+- Template setup: [`docs/template-project/setup.md`](docs/template-project/setup.md)
+- Build and debug: [`docs/template-project/build-debug.md`](docs/template-project/build-debug.md)
+- Testing and quality: [`docs/template-project/testing.md`](docs/template-project/testing.md)
+- ST-LIB docs (inside this repository): [`deps/ST-LIB/docs/setup.md`](deps/ST-LIB/docs/setup.md)
+## Main Working Modes
-## Notes
-If you are going to develop OUTSIDE the container, you MUST change `template-project.code-workspace` file after project creation if you DON'T have STLIB on ../ST-LIB relative path. This template is intended for you to develop always inside the container, so you should not be concerned about this.
+- `simulator`: fast local development and tests.
+- `nucleo-*` / `board-*`: hardware builds.
-## Automatic formatting (commit/push)
-This repository uses `pre-commit` + `clang-format` to format C/C++ files automatically on `git commit` and `git push`.
+List all presets:
-Install hooks once:
```sh
-pip install pre-commit
-./tools/install-git-hooks.sh
+cmake --list-presets
```
-Run manually on all files:
+## VSCode Debug
+
+`launch.json` and `tasks.json` include debug flows for:
+
+- OpenOCD
+- ST-LINK
+- simulator tests
+
+Detailed guide:
+
+- [`docs/template-project/build-debug.md`](docs/template-project/build-debug.md)
+
+## `BOARD_NAME` (code generation)
+
+Packet code generation uses `BOARD_NAME` (a key from JSON_ADE).
+
+Example:
+
```sh
-pre-commit run --all-files
+cmake --preset board-debug -DBOARD_NAME=TEST
```
diff --git a/STM32H723.svd b/STM32H723.svd
index 97fcec91..78eb25e2 100644
--- a/STM32H723.svd
+++ b/STM32H723.svd
@@ -28,9 +28,9 @@ Copyright (c) 2021 STMicroelectronics.
true
4
false
-
- 8
- 32
+
+ 8
+ 32
0x20
0x0
0xFFFFFFFF
@@ -4340,8 +4340,8 @@ Note: The software is allowed to write these bits only when ADEN=1, ADSTART=0 an
ADC2
- 0x40022100
-
+ 0x40022100
+
ADC12_Common
Analog-to-Digital Converter
@@ -4626,9 +4626,9 @@ Note: The software is allowed to write these bits only when ADEN=1, ADSTART=0 an
-
-
-
+
+
+
ADC3
Analog-to-Digital Converter
ADC
@@ -8435,10 +8435,10 @@ Note: The software is allowed to write these bits only when ADEN = 1, ADSTART =
read-write
-
+
-
+
ADC3_Common
Analog-to-Digital Converter
ADC
@@ -11592,7 +11592,7 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.
-
+
DAC
DAC
@@ -12332,7 +12332,7 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.Allow D1 domain debug in Standby mode
2
1
-
+
DBGSLPD2
Allow D2 domain debug in Sleep mode
@@ -12362,7 +12362,7 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.Allow debug in D3 Standby mode
8
1
-
+
TRACECLKEN
Trace port clock enable
@@ -12386,7 +12386,7 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.External trigger output enable
28
1
-
+
@@ -12403,9 +12403,9 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.WWDG1 stop in debug
6
1
-
+
-
+
APB3FZ2
APB3FZ2
@@ -12420,9 +12420,9 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.WWDG1 stop in debug
6
1
-
+
-
+
APB1LFZ1
APB1LFZ1
@@ -12497,7 +12497,7 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.WWDG2 stop in debug
11
1
-
+
DBG_I2C1
I2C1 SMBUS timeout stop in debug
@@ -12515,9 +12515,9 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register. I2C3 SMBUS timeout stop in debug
23
1
-
+
-
+
APB1LFZ2
APB1LFZ2
@@ -12610,9 +12610,9 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register. I2C3 SMBUS timeout stop in debug
23
1
-
+
-
+
APB2FZ1
APB2FZ1
@@ -12651,9 +12651,9 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register. TIM17 stop in debug
18
1
-
+
-
+
APB2FZ2
APB2FZ2
@@ -12692,9 +12692,9 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.TIM17 stop in debug
18
1
-
+
-
+
APB4FZ1
APB4FZ1
@@ -12751,7 +12751,7 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register. Independent watchdog for D2 stop in debug
19
1
-
+
@@ -12810,9 +12810,9 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register. LS watchdog for D2 stop in debug
19
1
-
+
-
+
@@ -13303,7 +13303,7 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.
-
+
DELAY_Block_SDMMC1
DELAY_Block_SDMMC1
DLYB
@@ -13826,7 +13826,7 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.6
-
+
CH2CFGR1
CH2CFGR1
@@ -14000,7 +14000,7 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.6
-
+
CH3CFGR1
CH3CFGR1
@@ -14174,7 +14174,7 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.6
-
+
CH4CFGR1
CH4CFGR1
@@ -14348,7 +14348,7 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.6
-
+
CH5CFGR1
CH5CFGR1
@@ -14522,7 +14522,7 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.6
-
+
CH6CFGR1
CH6CFGR1
@@ -14696,7 +14696,7 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.6
-
+
CH7CFGR1
CH7CFGR1
@@ -14870,7 +14870,7 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.6
-
+
DFSDM_FLT0CR1
DFSDM_FLT0CR1
@@ -23406,7 +23406,7 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.
Delay_Block_OCTOSPI1
0x52006000
-
+
Delay_Block_OCTOSPI2
0x5200B000
@@ -23461,7 +23461,7 @@ A read from this register resets the RRDY flag in the CORDIC_CSR register.EXTI15_10
EXTI Line[15:10] interrupts
40
-
+
WKUP
WKUP1 to WKUP6 pins
@@ -40618,7 +40618,7 @@ When a read access to this register occurs, the read data are the contents of th
GPIOH
0x58021C00
-
+
GPIOJ
0x58022400
@@ -59503,7 +59503,7 @@ When a read access to this register occurs, the read data are the contents of th
-
+
MPU
Memory protection unit
@@ -61422,12 +61422,12 @@ When a read access to this register occurs, the read data are the contents of th
0x0
0x1000
registers
-
+
OCTOSPI1
OCTOSPI1 global interrupt
92
-
+
CR
@@ -62337,7 +62337,7 @@ When a read access to this register occurs, the read data are the contents of th
- OCTOSPI2
+ OCTOSPI2
0x5200A000
OCTOSPI2
@@ -73654,7 +73654,7 @@ When a read access to this register occurs, the read data are the contents of th
-
+
OTG2_HS_PWRCLK
0x40080E00
@@ -86289,7 +86289,7 @@ Writing this bit to 1 clears the OVR_RIS bit in PSSI_RIS.
SAI4
SAI4 global interrupt
146
-
+
SCB
@@ -87006,7 +87006,7 @@ Writing this bit to 1 clears the OVR_RIS bit in PSSI_RIS.
-
+
SDMMC1
SDMMC1
SDMMC
@@ -88417,7 +88417,7 @@ Writing this bit to 1 clears the OVR_RIS bit in PSSI_RIS.
SDMMC2
- 0x48022400
+ 0x48022400
SDMMC2
SDMMC2 global interrupt
@@ -88816,7 +88816,7 @@ Writing this bit to 1 clears the OVR_RIS bit in PSSI_RIS.
13
-
+
@@ -95890,7 +95890,7 @@ Writing this bit to 1 clears the OVR_RIS bit in PSSI_RIS.
-
+
TIM23
0x4000E000
@@ -95908,7 +95908,7 @@ Writing this bit to 1 clears the OVR_RIS bit in PSSI_RIS.
TIM24 global interrupt
162
-
+
USART1
Universal synchronous asynchronous receiver
@@ -96972,7 +96972,7 @@ Writing this bit to 1 clears the OVR_RIS bit in PSSI_RIS.
UART9
0x40011800
-
+
USART10
0x40011C00
@@ -97171,4 +97171,4 @@ Writing this bit to 1 clears the OVR_RIS bit in PSSI_RIS.
-
\ No newline at end of file
+
diff --git a/deps/ST-LIB b/deps/ST-LIB
index 96abc13c..65d36f43 160000
--- a/deps/ST-LIB
+++ b/deps/ST-LIB
@@ -1 +1 @@
-Subproject commit 96abc13c0d2f657ce658c76b98eff57c44a1aacf
+Subproject commit 65d36f43533e461defac8e84f3e4f7a8ae62a304
diff --git a/docs/template-project/build-debug.md b/docs/template-project/build-debug.md
new file mode 100644
index 00000000..8599bd85
--- /dev/null
+++ b/docs/template-project/build-debug.md
@@ -0,0 +1,59 @@
+# Build and Debug
+
+## 1. Main CMake Presets
+
+- `simulator`
+- `simulator-asan`
+- `nucleo-*`
+- `board-*`
+
+List all presets:
+
+```sh
+cmake --list-presets
+```
+
+## 2. Build for Simulator
+
+```sh
+cmake --preset simulator
+cmake --build --preset simulator
+```
+
+With sanitizers:
+
+```sh
+cmake --preset simulator-asan
+cmake --build --preset simulator-asan
+```
+
+## 3. Build for MCU
+
+Example:
+
+```sh
+cmake --preset board-debug-eth-ksz8041 -DBOARD_NAME=TEST
+cmake --build --preset board-debug-eth-ksz8041
+```
+
+The build output is copied to:
+
+- `out/build/latest.elf`
+
+## 4. Debug from VSCode
+
+Launch configurations available in `.vscode/launch.json`:
+
+- `MCU | OpenOCD | Build + Debug (RTT)`
+- `MCU | OpenOCD | Debug (No Build, RTT)`
+- `MCU | OpenOCD | Attach (External Server, RTT)`
+- `MCU | ST-LINK | Build + Debug`
+- `MCU | ST-LINK | Debug (No Build)`
+- `MCU | ST-LINK | Attach (External GDB Server)`
+- `SIM | ST-LIB Tests | Debug`
+
+Useful tasks in `.vscode/tasks.json`:
+
+- `MCU | OpenOCD | Start Server`
+- `MCU | OpenOCD | RTT Console`
+- `MCU | ST-LINK | Start GDB Server`
diff --git a/docs/template-project/setup.md b/docs/template-project/setup.md
new file mode 100644
index 00000000..530d2933
--- /dev/null
+++ b/docs/template-project/setup.md
@@ -0,0 +1,47 @@
+# Template Project Setup
+
+## 1. Prerequisites
+
+- VSCode (recommended)
+- CMake + Ninja
+- Python 3
+
+For MCU build/flash/debug:
+
+- `STM32CubeCLT`
+- `openocd` or `ST-LINK_gdbserver`
+- `arm-none-eabi-gdb`
+
+## 2. Quick Initialization
+
+From the repository root:
+
+```sh
+./tools/init.sh
+```
+
+This command:
+
+- creates `virtual/`
+- installs Python dependencies from `requirements.txt`
+- initializes template and `deps/ST-LIB` submodules
+
+On Windows:
+
+```bat
+tools\init.bat
+```
+
+## 3. `BOARD_NAME` Configuration (codegen)
+
+Code generation uses `BOARD_NAME` (CMake cache variable), and the value must exist in:
+
+- `Core/Inc/Code_generation/JSON_ADE/boards.json`
+
+Example:
+
+```sh
+cmake --preset board-debug -DBOARD_NAME=TEST
+```
+
+If not set, the default value is `TEST`.
diff --git a/docs/template-project/testing.md b/docs/template-project/testing.md
new file mode 100644
index 00000000..51c7522f
--- /dev/null
+++ b/docs/template-project/testing.md
@@ -0,0 +1,46 @@
+# Testing and Quality
+
+## 1. Local Simulator Tests
+
+```sh
+cmake --preset simulator
+cmake --build --preset simulator
+ctest --preset simulator-all
+```
+
+Run only ADC tests:
+
+```sh
+ctest --preset simulator-adc
+```
+
+## 2. Tests with Sanitizers
+
+```sh
+cmake --preset simulator-asan
+cmake --build --preset simulator-asan
+ctest --preset simulator-all-asan
+```
+
+## 3. Formatting
+
+This repository uses `pre-commit` and `clang-format`.
+
+Install hooks:
+
+```sh
+pip install pre-commit
+pre-commit install --install-hooks --hook-type pre-commit --hook-type pre-push
+```
+
+Run manually:
+
+```sh
+pre-commit run --all-files
+```
+
+## 4. GitHub Actions CI
+
+- `Compile Checks`: builds MCU matrix (no simulator tests)
+- `Run Simulator Tests`: runs tests using `simulator` preset
+- `Format Checks`: validates formatting with `pre-commit`
diff --git a/hard_faullt_analysis.py b/hard_faullt_analysis.py
index 35e6bfc9..233eb2c0 100644
--- a/hard_faullt_analysis.py
+++ b/hard_faullt_analysis.py
@@ -60,7 +60,7 @@ def decode_cfsr_bus(cfsr, fault_addr):
print(f" BFARVALID : Bus fault address valid -> 0x{fault_addr:08X}")
if bus_fault & 0b00000100:
print(f"\033[91m Bus fault address imprecise\033[0m (DON'T LOOK CALL STACK)")
-
+
if bus_fault & 0b00100000:
print(" LSPERR : Floating Point Unit lazy state preservation error")
if bus_fault & 0b00010000:
@@ -97,8 +97,8 @@ def decode_cfsr(cfsr, fault_addr):
error = decode_cfsr_bus(cfsr, fault_addr) + error
error = decode_cfsr_usage(cfsr) + error
return error
-
-
+
+
def addr2line(addr):
cmd = ["arm-none-eabi-addr2line", "-e", ELF_FILE, "-f", "-C", hex(addr)]
try:
@@ -106,7 +106,7 @@ def addr2line(addr):
return output
except Exception as e:
return f"addr2line failed: {e}"
-
+
def analyze_call_stack(calltrace_depth, calltrace_pcs, context=2):
"""
Muestra el call stack, omitiendo frames sin fuente y mostrando snippet de código.
@@ -149,7 +149,7 @@ def print_code_context(lines, context=2):
print("Invalid addr2line output")
return
- file_line = line_list[1].strip()
+ file_line = line_list[1].strip()
split = file_line.rfind(':')
file_path = file_line[:split]
try:
@@ -192,38 +192,38 @@ def hard_fault_analysis(memory_string):
"cfsr": raw[9],
"fault_addr": raw[10],
"calltrace_depth": raw[11],
- "calltrace_pcs": raw[12:28]
+ "calltrace_pcs": raw[12:28]
}
if(hf["HF_Flag"] != 0xFF00FF00):
print("There was no hardfault in your Microcontroller, Kudos for you, I hope...")
return
print("================HARDFAULT DETECTED ===========")
print("Registers:")
-
+
for r in ['r0','r1','r2','r3','r12','lr','pc','psr']:
print(f" {r.upper():<4}: 0x{hf[r]:08X}")
-
+
print(f" CFSR: 0x{hf['cfsr']:08X}")
error = decode_cfsr(hf["cfsr"], hf["fault_addr"])
print("\nSource Location:")
pc_loc = addr2line(hf["pc"])
lr_loc = addr2line(hf["lr"])
print(f" Linker Register : 0x{hf['lr']:08X} -> {lr_loc}")
-
+
print(f" Program Counter : 0x{hf['pc']:08X} -> {pc_loc}")
print_code_context(pc_loc)
-
+
analyze_call_stack(hf["calltrace_depth"],hf["calltrace_pcs"])
-
+
print("======================================================")
-
-
+
+
print("Note: In Release builds (-O2/-O3) the PC may not point exactly to the failing instruction.")
print(" During interrupts, bus faults, or stack corruption, the PC can be imprecise.")
print("\nIn case of Imprecise error is dificult to find due to is asynchronous fault")
print("The error has to be before PC. But not possible to know exactly when.")
print("Check this link to know more : https://interrupt.memfault.com/blog/cortex-m-hardfault-debug#fn:8")
-
+
if __name__ == '__main__':
out = read_flash()
@@ -241,4 +241,3 @@ def hard_fault_analysis(memory_string):
memory_string += mem
memory_string = memory_string.replace(" ","")
hard_fault_analysis(memory_string)
-
diff --git a/requirements.txt b/requirements.txt
index e9218ce9..97547e29 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,2 @@
Jinja2==3.1.5
-GitPython==3.1.43
\ No newline at end of file
+GitPython==3.1.43
diff --git a/state_machine.json b/state_machine.json
index a5740155..3aabd215 100644
--- a/state_machine.json
+++ b/state_machine.json
@@ -1,6 +1,6 @@
{
"name" : "Example",
-
+
"states" : [
"name_1",
{
@@ -119,4 +119,4 @@
}
]
}
-}
\ No newline at end of file
+}
diff --git a/toolchains/stm32.cmake b/toolchains/stm32.cmake
index 9893d325..0c1e0047 100644
--- a/toolchains/stm32.cmake
+++ b/toolchains/stm32.cmake
@@ -29,4 +29,3 @@ set(CMAKE_FIND_ROOT_PATH ${BINUTILS_PATH})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
-
diff --git a/tools/binary_metadata_template.cpp b/tools/binary_metadata_template.cpp
index d8f838da..d038c950 100644
--- a/tools/binary_metadata_template.cpp
+++ b/tools/binary_metadata_template.cpp
@@ -1,9 +1,9 @@
/*
-* AUTOGENERATED FILE
+* AUTOGENERATED FILE
* DO NOT MODIFY MANUALLY!!!
*/
extern "C"{
- const char DESCRIPTION[255] __attribute__((section(".metadata_pool")))=
+ const char DESCRIPTION[255] __attribute__((section(".metadata_pool")))=
"****************" // placeholder for beggining
"{{ DateTimeISO8601 }}" // DateTime using ISO-8601 format
" " // alignment
@@ -12,6 +12,6 @@ extern "C"{
"{{ BOARD_COMMIT }}" // Board commit
// the '=' is used for unparsing
{% for var_pair in variables -%}
- "{{var_pair.name}}={{var_pair.value}}"
+ "{{var_pair.name}}={{var_pair.value}}"
{% endfor %};
-}
\ No newline at end of file
+}
diff --git a/tools/generate_binary_metadata.py b/tools/generate_binary_metadata.py
index 62b4a10d..3350ea36 100644
--- a/tools/generate_binary_metadata.py
+++ b/tools/generate_binary_metadata.py
@@ -1,82 +1,91 @@
-from jinja2 import Environment, FileSystemLoader
+#!/usr/bin/env python3
from datetime import datetime
-from git import Repo
from pathlib import Path
import os
+import re
+
+from git import Repo
+from jinja2 import Environment, FileSystemLoader
+
+MACRO_PATTERN = re.compile(r"ADD_TO_FLASH_INFO\(([^)]+)\)")
+ACCEPTED_EXTENSIONS = {".cpp", ".c", ".h", ".hpp"}
+
-def __get_git_root__():
- # Start at the script's directory and walk up to find the .git folder
+class Variable:
+ def __init__(self, name: str, value: str):
+ self.name = name
+ self.value = value
+
+
+def get_git_root() -> Path:
repo_root = Path(__file__).resolve()
while not (repo_root / ".git").exists() and repo_root != repo_root.parent:
repo_root = repo_root.parent
+ if not (repo_root / ".git").exists():
+ raise RuntimeError("Could not find repository root (.git)")
+ return repo_root
- return str(repo_root) if (repo_root / ".git").exists() else None
-def __get_current_commit__(path):
+def get_current_commit(path: Path) -> str:
try:
repo = Repo(path, search_parent_directories=True)
- return repo.head.commit.hexsha[:8] # Get the current commit hash
+ return repo.head.commit.hexsha[:8]
except Exception:
- return "--------" # not using that repo, return placeholder for commit
-
-class Variable:
- def __init__(self,name,value):
- self.name = name
- self.value = value
-variables = []
+ return "--------"
+
-def parse_file(file_path):
- with open(file_path, 'r') as file:
+def parse_file(file_path: Path, variables: list[Variable]) -> None:
+ with file_path.open("r", encoding="utf-8", errors="ignore") as file:
for line in file:
- # Look for the expression in the line
- if "ADD_TO_FLASH_INFO" in line:
- # Remove the 'ADD_TO_FLASH_INFO(' and ')'
- line = line.strip()[len("ADD_TO_FLASH_INFO("):-1]
- # Split the string by commas
- parts = line.split(',')
- # Ensure that we have exactly three parts (TYPE, VAR_NAME, VALUE)
- if len(parts) == 3:
- var_name = parts[1].strip() # Extract VAR_NAME
- value = parts[2].strip() # Extract VALUE
- if var_name == 'VAR_NAME' and value == 'VALUE)': #make sure to not add the MACRO definition
- #in case it was present in that file
- pass
- else:
- variables.append(Variable(var_name, value))
-print("Starting binary metadata generation")
-
-def search_in_subfolder(root_folder):
- accepted_file_extensions = ['.cpp','.c','.h','.hpp']
- for folder_name, subfolders, filenames in os.walk(root_folder):
+ match = MACRO_PATTERN.search(line)
+ if not match:
+ continue
+
+ parts = [part.strip() for part in match.group(1).split(",")]
+ if len(parts) != 3:
+ continue
+
+ var_name = parts[1]
+ value = parts[2]
+ if var_name == "VAR_NAME" and value == "VALUE":
+ continue
+ variables.append(Variable(var_name, value))
+
+
+def search_core_sources(core_root: Path, variables: list[Variable]) -> None:
+ for folder_name, _subfolders, filenames in os.walk(core_root):
for filename in filenames:
- for extension in accepted_file_extensions:
- if filename.endswith(extension):
- file_path = os.path.join(folder_name, filename)
- parse_file(file_path)
-def main():
- repo_root = __get_git_root__()
- search_in_subfolder(os.path.join(repo_root,"Core/"))
+ path = Path(folder_name) / filename
+ if path.suffix in ACCEPTED_EXTENSIONS:
+ parse_file(path, variables)
- environment = Environment(loader=FileSystemLoader(os.path.join(repo_root,'tools')))
- template = environment.get_template(os.path.join('binary_metadata_template.cpp'))
- iso_time = datetime.now().strftime("%Y%m%dT%H%M%S")
- repo_root = __get_git_root__()
- stlib_commit = __get_current_commit__(os.path.join(repo_root,"deps/ST-LIB"))
- adj_commit = __get_current_commit__(os.path.join(repo_root,"deps/adj")) ## keep an eye on this
- board_commit = __get_current_commit__(repo_root)
+def main() -> None:
+ print("Starting binary metadata generation")
+ repo_root = get_git_root()
+ variables: list[Variable] = []
+ search_core_sources(repo_root / "Core", variables)
- output_file = os.path.join(repo_root,"Core/Src/Runes/generated_metadata.cpp")
+ environment = Environment(loader=FileSystemLoader(str(repo_root / "tools")))
+ template = environment.get_template("binary_metadata_template.cpp")
+
+ iso_time = datetime.now().strftime("%Y%m%dT%H%M%S")
+ stlib_commit = get_current_commit(repo_root / "deps/ST-LIB")
+ adj_commit = get_current_commit(repo_root / "deps/adj")
+ board_commit = get_current_commit(repo_root)
+
+ output_file = repo_root / "Core/Src/Runes/generated_metadata.cpp"
content = template.render(
DateTimeISO8601=iso_time,
- STLIB_COMMIT = stlib_commit,
- ADJ_COMMIT = adj_commit,
- BOARD_COMMIT = board_commit,
- variables=variables)
- with open(output_file, mode="w", encoding="utf-8") as message:
- message.write(content)
-
+ STLIB_COMMIT=stlib_commit,
+ ADJ_COMMIT=adj_commit,
+ BOARD_COMMIT=board_commit,
+ variables=variables,
+ )
+ output_file.write_text(content, encoding="utf-8")
print("Generation completed")
+
+
if __name__ == "__main__":
- main()
\ No newline at end of file
+ main()
diff --git a/tools/init.bat b/tools/init.bat
index a7edc385..59f1e439 100644
--- a/tools/init.bat
+++ b/tools/init.bat
@@ -1,6 +1,6 @@
@echo off
setlocal enabledelayedexpansion
-# This script is supposed to be under ${REPO_PATH}/tools/init.bat
+REM This script is supposed to be under ${REPO_PATH}/tools/init.bat
REM Get the script directory and repo directory
set "SCRIPT_DIR=%~dp0"
@@ -19,9 +19,16 @@ REM Activate virtual environment
call virtual\Scripts\activate.bat
REM Install requirements
+python -m pip install --upgrade pip
pip install -r requirements.txt
REM Update git submodules
git submodule update --init
+where bash >nul 2>&1
+if %errorlevel%==0 (
+ bash -lc "./deps/ST-LIB/tools/init-submodules.sh"
+) else (
+ echo bash was not found in PATH. Run deps/ST-LIB/tools/init-submodules.sh manually.
+)
echo Setup complete!
diff --git a/tools/init.sh b/tools/init.sh
index 872b6705..7bcdb9b0 100755
--- a/tools/init.sh
+++ b/tools/init.sh
@@ -12,6 +12,10 @@ echo "Repository directory: $REPO_DIR"
cd "$REPO_DIR"
python3 -m venv virtual
source ./virtual/bin/activate
+python -m pip install --upgrade pip
pip install -r requirements.txt
git submodule update --init
+./deps/ST-LIB/tools/init-submodules.sh
+
+echo "Setup complete."
diff --git a/tools/preflash_check.py b/tools/preflash_check.py
index 0a4d4639..314125aa 100644
--- a/tools/preflash_check.py
+++ b/tools/preflash_check.py
@@ -1,12 +1,11 @@
#!/usr/bin/env python3
"""
Pre-flash check script.
-Checks for uncommitted changes and commits them if the binary was compiled with BOARD symbol.
+Checks for uncommitted changes when the binary was compiled with BOARD symbol.
"""
import subprocess
import sys
-import os
from pathlib import Path
def get_script_dir() -> Path:
@@ -32,30 +31,30 @@ def has_uncommitted_changes(workspace_dir: Path) -> bool:
def main():
workspace_dir = get_workspace_dir()
-
+
# Default build directory - can be overridden by command line argument
if len(sys.argv) > 1:
build_dir = Path(sys.argv[1])
else:
build_dir = workspace_dir / "out" / "build"
-
+
print(f"Workspace directory: {workspace_dir}")
print(f"Build directory: {build_dir}")
-
+
# Check if this is a BOARD build
if not check_board_symbol(build_dir):
print("Binary was not compiled with BOARD symbol (or marker not found). Skipping pre-flash check.")
sys.exit(0)
-
+
print("Binary was compiled with BOARD symbol. Checking for uncommitted changes...")
-
+
if has_uncommitted_changes(workspace_dir):
print("Uncommitted changes detected. Aborting Flash...")
print("Please before flashing a board make sure all changes are commited");
sys.exit(1)
else:
print("No uncommitted changes. Proceeding with flash.")
-
+
sys.exit(0)
if __name__ == "__main__":
diff --git a/tools/retrieve_flash_data.py b/tools/retrieve_flash_data.py
index 1ebf07d9..902ba80b 100644
--- a/tools/retrieve_flash_data.py
+++ b/tools/retrieve_flash_data.py
@@ -1,77 +1,113 @@
-import subprocess
+#!/usr/bin/env python3
import argparse
-from datetime import datetime
import os
-def main():
- parser = argparse.ArgumentParser(description="Retrieve the binary metadata from flash given an address")
+import subprocess
+from datetime import datetime
+from pathlib import Path
+
+
+DUMP_FILE = Path("dump.bin")
+
+
+def read_metadata(address: str) -> bytes:
+ result = subprocess.run(
+ [
+ "STM32_Programmer_CLI",
+ "-c",
+ "port=swd",
+ "mode=ur",
+ "Freq=4000",
+ "-u",
+ address,
+ "0xFF",
+ str(DUMP_FILE),
+ ],
+ check=False,
+ )
+ if result.returncode != 0:
+ if DUMP_FILE.exists():
+ DUMP_FILE.unlink()
+ raise RuntimeError(
+ "Error running STM32_Programmer_CLI. Ensure board power, cable and ST-LINK availability."
+ )
+ return DUMP_FILE.read_bytes()
+
+
+def validate_checksum(binary_raw: bytes, address: str, checksum_length: int) -> None:
+ if len(binary_raw) < checksum_length:
+ raise RuntimeError(f"Retrieved data is too short (address: {address})")
+ if any(byte != ord("*") for byte in binary_raw[:checksum_length]):
+ raise RuntimeError(
+ f"Retrieved binary did not pass checksum test. Maybe metadata is not at {address}"
+ )
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser(
+ description="Retrieve binary metadata from flash given an address"
+ )
parser.add_argument(
- "--address", # Argument name
- type=str, # Argument type (string)
- default="0x080DFD00", # Default value if no argument is provided
- help="The memory address to retrieve from, if unsure leave empty" # Help text
+ "--address",
+ type=str,
+ default="0x080DFD00",
+ help="Memory address to read from",
)
args = parser.parse_args()
+
try:
- result = subprocess.run(["STM32_Programmer_CLI", "-c", "port=swd", "mode=ur", "Freq=4000", "-u", args.address, "0xFF", "dump.bin"])
- if result.returncode != 0:
- #if we tried to read and it failed, remove the
- # existing file to avoid confussion
- os.remove("dump.bin")
- raise Exception()
- except Exception:
- print("Error when running STM32_Programmer_CLI, make sure the board is powered and the cable connected,\nalso make sure STLINK is not in use by the debugger or STM32CubeProgrammer")
- exit(-1)
-
- binary_raw = None
-
- with open("dump.bin","r") as binary:
- binary_raw = binary.read()
-
- #DEFINITIONS FOR LOCATIONS
+ binary_raw = read_metadata(args.address)
+ except Exception as exc:
+ print(exc)
+ raise SystemExit(1)
+
checksum_length = 16
iso_time_offset = checksum_length
iso_time_length = 15
padding_length = 1
stlib_commit_offset = iso_time_offset + iso_time_length + padding_length
stlib_commit_length = 8
-
adj_commit_offset = stlib_commit_offset + stlib_commit_length
adj_commit_length = 8
-
board_commit_offset = adj_commit_offset + adj_commit_length
- board_commit_legnth = 8
-
- custom_variables_offset = board_commit_offset + board_commit_legnth
+ board_commit_length = 8
+ custom_variables_offset = board_commit_offset + board_commit_length
- def __validate_retrieved_binary():
- for i in range(0,checksum_length):
- if binary_raw[i] != '*':
- raise Exception("Retrieved binary did not pass checksum test\n Maybe the metadata is not at that address? ADDRESS: {}".format(args.address))
- return True
- if __validate_retrieved_binary() == True:
- print("Found binary metadata!")
+ try:
+ validate_checksum(binary_raw, args.address, checksum_length)
+ except Exception as exc:
+ print(exc)
+ raise SystemExit(1)
- iso_time = binary_raw[iso_time_offset:iso_time_offset + iso_time_length]
- stlib_commit = binary_raw[stlib_commit_offset:stlib_commit_offset + stlib_commit_length]
- adj_commit = binary_raw[adj_commit_offset:adj_commit_offset + adj_commit_length]
- board_commit = binary_raw[board_commit_offset:board_commit_offset + board_commit_legnth]
+ print("Found binary metadata!")
+ iso_time = binary_raw[iso_time_offset : iso_time_offset + iso_time_length].decode(
+ errors="ignore"
+ )
+ stlib_commit = binary_raw[
+ stlib_commit_offset : stlib_commit_offset + stlib_commit_length
+ ].decode(errors="ignore")
+ adj_commit = binary_raw[
+ adj_commit_offset : adj_commit_offset + adj_commit_length
+ ].decode(errors="ignore")
+ board_commit = binary_raw[
+ board_commit_offset : board_commit_offset + board_commit_length
+ ].decode(errors="ignore")
dt = datetime.strptime(iso_time, "%Y%m%dT%H%M%S")
- # Format to a readable format (e.g., "March 2, 2025, 1:12:41 PM")
- readable_time = dt.strftime("%d %B %Y, %H:%M:%S") # 24-hour format (%H)
+ readable_time = dt.strftime("%d %B %Y, %H:%M:%S")
+
+ print(f"Code was compiled at: {readable_time}")
+ print(f"STLIB commit {stlib_commit}")
+ print(f"ADJ commit {adj_commit}")
+ print(f"Board commit {board_commit}")
+ custom_payload = binary_raw[custom_variables_offset:255].decode(errors="ignore")
+ print(custom_payload.rstrip("\x00"))
- print("Code was compiled at: {}".format(readable_time))
- print("STLIB commit {}".format(stlib_commit))
- print("ADJ commit {}".format(adj_commit))
- print("Board commit {}".format(board_commit))
+ # Keep compatibility with previous behavior: cleanup temporary dump.
+ if DUMP_FILE.exists():
+ os.remove(DUMP_FILE)
- for i in range(custom_variables_offset, 255):
- if binary_raw[i].isdigit() == True and binary_raw[i+1].isdigit() == False:
- print(binary_raw[i],end="\n")
- else:
- print(binary_raw[i],end="")
if __name__ == "__main__":
- main()
\ No newline at end of file
+ main()