Development Environment
The development environment uses VS Code as the editor. While this documentation only describes the use of VS Code, the project may be developed with any editor.
To maintain toolchains and dependencies, Docker is used.
Python is used as the scripting language, e.g. to interact with Docker.
Installation
To work on this project on a local machine, the following tools need to be installed. The version of the tools is uncritical, as all the critical tools and dependencies are in the Docker containers.
For Debugging there might be some more tools necessary. (see: Debugging)
VS Code
All necessary files can be created and edited with VS Code.

configuration
devcontainer definitions are found in the .devcontainer/ directory
{
"name": "doc",
"dockerComposeFile": "${localWorkspaceFolder}/doc/docker-compose.yml",
"service": "main",
"workspaceFolder": "/home/${localEnv:USER}/project/doc",
"customizations": {
"vscode": {
"settings": {
"terminal.integrated.shell.linux": "/bin/bash"
},
"extensions": [
"ms-azuretools.vscode-containers",
"ms-python.python",
"ybaumes.highlight-trailing-white-spaces"
]
}
},
"remoteUser": "root"
}
{
"name": "software",
"dockerComposeFile": "${localWorkspaceFolder}/software/docker-compose.yml",
"service": "main",
"workspaceFolder": "/home/${localEnv:USER}/project/software",
"customizations": {
"vscode": {
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
"rust-analyzer.check.allTargets": false,
"rust-analyzer.inlayHints.typeHints.enable": false,
"rust-analyzer.inlayHints.parameterHints.enable": false,
"editor.semanticTokenColorCustomizations": {
"enabled": true,
"rules": {
"*.mutable": {
"underline": false
}
}
}
},
"extensions": [
"rust-lang.rust-analyzer",
"fill-labs.dependi",
"tamasfe.even-better-toml",
"ms-azuretools.vscode-containers",
"ybaumes.highlight-trailing-white-spaces",
"probe-rs.probe-rs-debugger",
"vadimcn.vscode-lldb",
"ms-python.python"
]
}
}
}
Devcontainers are Docker containers that VS Code can open into. It guarantiees a consistent development environment while using the benefits of VS Code. See for more information on devcontainers.
.gitignore(s)
There might be multiple .gitignore files. They are placed with reasonable granularity. See File Structure where they are.
reStructuredText
The documentation is created with Sphinx from reStructuredText. It may contain diagrams, which are created with draw.io and stuff from other sources. There may also be PlantUML diagrams directly embedded into code documentation or other documentation files.
draw.io files
Diagrams especially for the documentation are created with draw.io.
workflows
There shall be as much automation as reasonable possible. GitHub Actions with workflows are used for automation.
build scripts
For simple project handling (test, build, download to target, …) Python scripts are used. As the same scripts are used by the GitHub Actions workflows, the build process is consistent locally and remotely. The scripts are powerfull and almost everything can be done with them. See see: Scripts how they work.
Dockerfile(s)
There are multiple Dockerfiles and docker-compose.yml files. They are placed with reasonable granularity. See File Structure where they are. Everything generating output like compilers, flash-tools, unit-test-frameworks, documentation-build-chain, … are in the Docker containers. Docker Compose files control the configuration of the containers (e.g. ports, volumes, …). This makes the development environment consistent, reproducible and documented.
code
Rust has been chosen as the programming language, as it is an upcoming language with a lot of potential and a good community. It might not be the easiest solution for the task, but that is not a criterium here. See File Structure for the code structure.
Local Toolchain

Remote Toolchain

Git
Is used for version control.
github.com
GitHub is used as the repository host.
Python
Python is used to execute the scripts.
Docker
Together with Docker Compose, defines the containers.
Sphinx
Is used to generate the documentation.
Rust tools
The Rust tools are used to build and test the code and to deploy to the target.
actions
GitHub Actions are used to automate the build and test process.
Debugging
This chapter explains how to setup the debugging with SEGGER J-Link EDU Mini and rs-probe.
SEGGER J-Link EDU Mini
The SEGGER J-Link EDU Mini is used as a debugger. As this is not a commercial project its use is permited. Other SEGGER debuggers might work in the same way.
The easiest way to make the debugger work under Linux is to install J-Link Software and Documentation Pack. This will automatically set the necessary udev rules.
On Windows it might just work.
probe-rs
probe-rs is installed in the container and the plugin is used in the devcontainer. So, no installation by hand.
Dockerfile with installation of probe-rs
FROM rust:1.87.0
RUN apt-get update && apt-get install -y \
# tig is great for viewing git history
tig \
# less is needed e.g. for 'git diff' to make the output scrollable
less
ARG USER
ARG UID
RUN useradd -m -s /bin/bash -u ${UID:-2222} $USER
USER ${USER}
RUN curl --proto '=https' --tlsv1.2 -LsSf https://github.com/probe-rs/probe-rs/releases/download/v0.25.0/probe-rs-tools-installer.sh | sh
# run this as sudo on the host machine to make st-link accessible
# curl -o /etc/udev/rules.d/69-probe-rs.rules https://probe.rs/files/69-probe-rs.rules
RUN cargo install \
cargo-tarpaulin@0.32.8 \
cargo-modules@0.24.3
RUN rustup target add thumbv7em-none-eabihf
WORKDIR /home/$USER/dependencies_fetch_project/dummy/l6360
RUN cargo init
COPY ./l6360/Cargo.toml .
RUN cargo fetch
WORKDIR /home/$USER/dependencies_fetch_project/dummy/iol
RUN cargo init
COPY ./iol/Cargo.toml .
RUN cargo fetch
WORKDIR /home/$USER/dependencies_fetch_project/dummy/examples/std
RUN cargo init
COPY ./examples/std/Cargo.toml .
RUN cargo fetch
WORKDIR /home/$USER/dependencies_fetch_project/dummy/examples/stm32f446re
RUN cargo init
COPY ./examples/stm32f446re/Cargo.toml .
RUN cargo fetch
# - For example when used as devcontainer, the UID is set to a default value (see above).
# I wasn't able to pass the UID of the local user to the container in this case.
# So when using the devcontainer, the local user is then used and can't access the fetched dependencies.
# To solve this, the fetched dependencies are made readable and writable by anyone.
RUN chmod -R a+rw /usr/local/cargo/registry
devcontainer with extension probe-rs.probe-rs-debugger
{
"name": "software",
"dockerComposeFile": "${localWorkspaceFolder}/software/docker-compose.yml",
"service": "main",
"workspaceFolder": "/home/${localEnv:USER}/project/software",
"customizations": {
"vscode": {
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
"rust-analyzer.check.allTargets": false,
"rust-analyzer.inlayHints.typeHints.enable": false,
"rust-analyzer.inlayHints.parameterHints.enable": false,
"editor.semanticTokenColorCustomizations": {
"enabled": true,
"rules": {
"*.mutable": {
"underline": false
}
}
}
},
"extensions": [
"rust-lang.rust-analyzer",
"fill-labs.dependi",
"tamasfe.even-better-toml",
"ms-azuretools.vscode-containers",
"ybaumes.highlight-trailing-white-spaces",
"probe-rs.probe-rs-debugger",
"vadimcn.vscode-lldb",
"ms-python.python"
]
}
}
}
Scripts
The scripts help to simplify development workflows like creating documentation, running tests, flashing firmware and more. They are very powerfull and are in most cases the way to interact with the development environment if you want to execute any task.
There is a main script run.py in the project root folder. All the scripts in subfolders can be run from this script. The scripts in the subfolders are also named run.py. So any run.py belongs to the script system described here. Any run.py can be run from the folder it is in. Additionally the main script in the project root folder can run all of them.
The scripts are written in Python as this is widely available, spripts are easy to read and simplifies the parsing of command line arguments. Bash scripts for example have been found to be less readable and less flexible.
The github workflows use the exact same scripts, what leads to even more consistency.
Whenever you feel lost there is help in every script.
./run.py --help
run.py (project root)
This is the main script in the root folder. Everything can be done from here. It acts as a wrapper for the other scripts and forwards the parameters to them.
For example to run unit-tests, you can use the following command.
./run.py --software --test
This forwards the --test parameter to the software script. The local script can be run in the same way but without the --software parameter.
See the help message for more information.
help message
To get this help message run in the project root folder:
./run.py --help_all
usage: run.py [-h] (--software ... | --doc ... | --ha)
Execute common tasks (building, testing, ...)
options:
-h, --help show this help message and exit
--software ... Pass the remaining arguments to software/run.py.
--doc ... Pass the remaining arguments to doc/run.py.
--ha, --help_all Show help for this and all direct subscripts.
*** below are the help messages of the subscripts ***
*** software/run.py ***
usage: Execute feature tests [-h] [-b] [-t] [-d] [-v] [-k] [-p]
options:
-h, --help show this help message and exit
-b, --build Build the software.
-t, --test Test the software.
-d, --doc Document the software.
-v, --verbose Verbose output.
-k, --keep_open Enter the command line of the container.
-p, --pseudo_tty_off Disable colorfull output.
*** doc/run.py ***
usage: Execute unit-tests [-h] [-b] [-a] [-v] [-k] [-p]
options:
-h, --help show this help message and exit
-b, --build Build documentation.
-a, --autobuild Start sphinx-autobuild.
-v, --verbose Verbose output.
-k, --keep_open Enter the command line of the container.
-p, --pseudo_tty_off Disable colorfull output.