# Build BitBox02 firmware and bootloader
## Reporting issues
For security related issues please see [SECURITY.md](SECURITY.md).
## Development environment
There is a container image with all the build dependencies and there are some
`make` shortcuts to use it.
> [!TIP]
> It is highly recommended to use the container for development.
For automation and editor integrations, use `./scripts/dev_exec.sh ` as the project
entrypoint. It runs commands natively on the host by default and can be switched to container
execution with `BITBOX_FW_EXEC_MODE=docker`.
Accessing USB devices, like the flashing tool and the bitbox, is easier outside
of the container. So it is recommended to install the J-Link Software on your
development machine to follow the instructions below.
### Development Dependencies*
| Dependency | Version** |
| ---------- | -------- |
| [Arm GNU Toolchain](https://developer.arm.com/downloads/-/gnu-rm) | 8-2018-q4 |
| [HIDAPI](https://github.com/signal11/hidapi) | 0.11.2 |
| [cmake](https://cmake.org/download/) | 3.10 |
| [git](https://git-scm.com/downloads) | 2.34 |
| [Protobuf Compiler](https://github.com/protocolbuffers/protobuf/releases) | 21.2 |
| [Python Probobuf Runtime](https://github.com/protocolbuffers/protobuf/tree/master/python#installation) | 5.27.3 |
| [SEGGER J-Link Software and Documentation Pack](https://www.segger.com/downloads/jlink) | 6.34g |
| Graphviz | 2.42.2 |
| Doxygen | 1.9.1 |
| [cmocka](https://cmocka.org/files/1.1/) | 1.1.5 |
* See the complete list of dependences in the Dockerfile.
** The versions here are known to be working. Newer versions should
work.
### Setup containerized environment
Run the following commands to fetch the container image and run it:
```sh
make dockerpull
make dockerdev
```
`dockerpull` will use `docker pull` to fetch the current container image.
`dockerdev` will use `docker run` and `docker exec` to run a container in the
background and enter it. `dockerdev` will mount the project root using the same
path inside the container, which lets you use your preferred editor/IDE outside
the container.
> [!NOTE]
> The current development container is defined in
> [.containerversion](.containerversion). This is the version that is pulled
> with `dockerpull` and built with `dockerinit`.
> [!NOTE]
> `make dockerdev` will enter an already running container if it exists.
Run the following command to build the container:
```sh
make dockerinit
```
`dockerinit` is a shortcut to run `docker build`. Use this if you need to
permanently update the container image ([Dockerfile](Dockerfile)). Don't forget
to update the [container version file](.containerversion).
> [!TIP]
> For temporary changes you should enter the container running `docker exec`
> with user id 0.
### Setup development environment on macOS with brew
> [!CAUTION]
> Brew usually only supports the latest versions of software packages. It is
> not easy to get a working development environment using brew. Any
> discrepancies between your environment and the containerized environment may
> lead to CI build failures, since CI uses the container.
> [!IMPORTANT]
> If you use compiler versions different from CI you will not be able to
> reproducibly build the firmware. Different compilers typically lead to
> slightly different binary outputs.
Make sure you have [Homebrew](https://brew.sh) installed. Install the
dependencies with:
```sh
brew install hidapi cmake protobuf@21
brew install automake libtool
brew tap osx-cross/arm
brew install arm-gcc-bin
```
## Contributor instructions
### Check out the repository
#### 1. Fork the repository on github.
Go to [bitbox02-firmware](https://github.com/bitboxswiss/bitbox02-firmware) and fork the repository.
#### 2. Check out your fork
Run the following commands to check out your fork:
```sh
git clone --recurse-submodules git@github.com:/bitbox02-firmware.git
cd bitbox02-firmware
```
> [!TIP]
> If you have already cloned the repository without the `--recurse-submodules`
> argument, run:
>
> ```sh
> git submodule update --init --recursive
> ```
> [!TIP]
> Add the original repo as a second remote so that you can sync the `master` branch.
> ```
> git remote add upstream https://github.com/bitboxswiss/bitbox02-firmware
> ```
### Build the firmware
Run the following commands to enter the container and build the firmware:
```sh
make dockerdev
make firmware
```
> [!TIP]
> If you have multiple cores you can speed up compilation by passing `-j`, for example `-j8`.
### Build the bootloader
Run the following commands to enter the container and build the bootloader:
```sh
make dockerdev
make bootloader
```
> [!NOTE]
> To create a bootloader for a development or a production device, use `make
> bootloader-devdevice` or `make bootloader-production` respectively.
> [!NOTE]
> To run unsigned firmwares you need a development bootloader.
### Build the simulator
The Multi edition firmware can be built as a simulator for linux and macos. To
build it, run:
```sh
make simulator
```
### Build the graphical simulator
The Multi edition firmware can be built as a graphical simulator for linux and
macos. To build it, run:
```sh
make simulator-graphical
```
### Flash instructions
#### Connect J-Link probe
Connect the J-Link probe to the debug pins on the BitBox02 prototype board. The
pinout of the board and the Arm JTAG/SWD 10-pin connector can be seen in the
table below.
| Signal | Bitbox02 # | Arm JTAG/SWD # |
| ------ | ---------- | -------------- |
| VCC | 1 | 1 |
| CLK | 2 | 4 |
| GND | 3 | 3, 5 |
| DIO | 4 | 2 |
See [bitbox schematics](doc/bb02_v2.10_schematics.pdf) and [Arm JTAG/SWD
interface](https://developer.arm.com/documentation/101636/0100/Debug-and-Trace/JTAG-SWD-Interface)
Plug **both** the J-Link probe and the BitBox02 into the computer using USB. A
USB hub can be used.
#### Flash bootloader using J-Link
Load the bootloader by JLink (requires `JLinkExe` in `$PATH`).
```sh
make jlink-flash-bootloader
```
> [!NOTE]
> To flash a bootloader for a development device
> `make jlink-flash-bootloader-development`.
#### Flash firmware using J-Link
Load the firmware by JLink:
```sh
make jlink-flash-firmware
```
#### Flash firmware using bootloader and python cli client
> [!TIP]
> This method does not require a J-Link probe while developing.
Install the [BitBox02 Python CLI client](#bitbox02-python-cli-client).
Load the firmware through the bootloader:
```sh
make flash-dev-firmware
```
### Build reference documentation (Doxygen)
```sh
make docs
```
To view the results, open `build/docs/html/index.html` in a web browser.
### Debugging
#### Debugging using the simulator
Run it with:
```sh
./build-build-noasan/bin/simulator
```
or the following if you built the graphical one:
```sh
./build-build-noasan/bin/simulator-graphical --preseed
```
This launches a server simulating the firmware. The send_message tool can
connect to it with:
./py/send_message.py --simulator
Both simulators can load the following seed:
boring mistake dish oyster truth pigeon viable emerge sort crash wire
portion cannon couple enact box walk height pull today solid off enable
tide
The graphical simulator does it with the flag `--preseed`. The original
simulator loads it if you restore from mnemonic.
#### Debugging using the J-Link probe and GDB
The *debug firmware* enables pretty printing of panics over [RTT](https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/).
Run the following commands to build the debug firmware.
```sh
make dockerdev
make firmware-debug
```
Run the following command to run the J-Link GDB Server.
```sh
make jlink-gdb-server
```
> [!IMPORTANT]
> The J-Link GDB Server must be left running in the background.
Run the following command to connect with telnet to the J-Link GDB Server to
see the RTT output.
```sh
make rtt-client
```
Run the following command to run GDB. GDB will connect to the J-Link GDB
server, flash the debug firmware and then start execution from the bootloader
(as if the device was just plugged in).
```sh
make run-debug
```
> [!TIP]
> After rebuilding the firmware, exit GDB and rerun `run-debug` to flash and reset the device.
> [!TIP]
> The initial set of GDB commands that are run are specified in the [gdb init
> script](./scripts/jlink.gdb). You may want to modify it if you are debugging
> something specific.
> [!TIP]
> In debug builds you can use the following functions to log:
> ```c
> util_log(fmt, args...)
> ```
> ```rust
> use ::util::log::log!(fmt, args...)
> ```
> in C you can also format with hex using `util_dbg_hex`:
> ```c
> uint8_t arr[] = {1,2};
> util_log("%s", util_dbg_hex(arr, sizeof(arr)));
> ```
> in rust you can format with hex using the built in hex formatter or the hex
> crate:
> ```rust
> let arr = [1, 2];
> log!("{:02x?}", arr)
> log!("{}", hex::encode(arr))
> ```
### Unit tests
CMocka [https://cmocka.org/](https://cmocka.org/) is used for mocking in the
unit tests. To compile the tests, the CMocka library needs to be installed on
your system. CMocka is available through most package managers, like *brew* and
*apt*.
> [!NOTE]
> If you compiled it yourself from souce, the library will, by default, be
> installed into **/usr/local/** directory instead of **/usr/**.
> If the library is not on the library path by default, you might need to export
> the following environment variable:
> ```sh
> export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib64/
> ```
Then you can run the tests by executing
```sh
make run-unit-tests # or make -C build-build test
```
Rust unit tests, if not invoked via `make run-rust-unit-tests`, must be run with
`-- --test-threads 1` due to unsafe concurrent access to `SafeData`, `mock_sd()` and `mock_memory()`.
### Coverage
gcovr or lcov/genhtml can be used to generate HTML coverage reports using the following commands:
```sh
make coverage # or make -C build-build coverage
```
```sh
make -C build-build coverage-lcovr
```
### SCCache / CCache
The build systems supports sccache/ccache, you just need to have it available
in your path. You can install it into your dev container with the following
commands:
```
docker exec -u 0 -it bitbox02-firmware-dev bash -c 'apt update && apt install -y libssl-dev && CARGO_HOME=/opt/cargo cargo install --locked sccache'
```
## BitBox02 Python Library
There is a Python api library in `py/bitbox02`.
> [!IMPORTANT]
> The Python scripts and editable installs require **pip ≥ 25**. Older pip versions will fail.
> For setup and usage instructions, see [`py/README.md`](py/README.md).
### BitBox02 CLI client
Run `pip install -r py/requirements.txt` to install the deps (virtualenv recommended).
`make -C py/bitbox02` to generate the protobuf files.
To kick off some api calls:
```sh
./py/send_message.py
```