Bluenet uses the
cmake build system,
git as versioning system, and
wget to retrieve other files.
sudo apt install cmake git wget python3 python3-pip
Note: In newer Ubuntu version you might get an unmet dependency issue for libncurses5. To fix this issue simply run the command:
sudo apt --fix-broken install
Getting the Bluenet code
The best way is to first fork the bluenet repository.
Create a workspace folder where all the necessary files and folders will be stored, e.g.
mkdir -p ~/workspace
and download the code:
git clone https://github.com/YOUR_GITHUB_USERNAME/bluenet
and set the correct upstream:
cd bluenet git remote add upstream firstname.lastname@example.org:crownstone/bluenet.git
The installation uses CMake. To start, you can simply use:
cd bluenet mkdir build && cd build cmake .. && make
This will download the required programs and libraries. The installation has been tested on Ubuntu 18.04 (should work on newer ones as well) and assumes you use a J-Link programmer.
By default a
default target will be build. It is possible to build for that target by navigating into its build
cd build/default make
Different commands to write to a board (flashing) use
nrfjprog under the hood.
To clear the target device completely:
cd build make erase
To write the softdevice:
cd build make write_softdevice
This will also erase the pages if there is already code on this.
To check the version of a softdevice:
If you type
make and then TAB there should be tab completion that shows the possible targets.
The softdevice makes use of a so called master boot record (MBR). This provides the softdevice, bootloader, and firmware some functions. It requires a parameter page, which it finds by looking at the UICR. We write the address with:
Before writing the application or bootloader, the board version should be written. It allows Crownstone to run the same binary on all our devices and decide per device what type of hardware is actually present. For example, on a Guidestone there will be no switch functionality available. It has to be written before the application runs, else the application will write a default.
cd build/default make write_board_version
The bootloader is build automatically when you build the firmware, it can also be flashed to the target board. The value of its start address is written to UICR separately.
To write the bootloader and its address:
cd build/default/bootloader make write_bootloader make write_bootloader_address
Then write the application:
cd build/default make write_application
The bootloader requires a bootloader settings page that contains information about the current DFU process. It also contains information about the installed application and its version. The bootloader verifies if the application is correct by checking it against the bootloader settings, so each time the application changes, you the bootloader settings also change.
To build and write the bootloader settings:
cd build/default make build_bootloader_settings make write_bootloader_settings
Now that everything is written, the board has to be reset:
cd build make reset
DFU (over the air updates)
In order to create DFU packages, the firmware has to be signed. For this, pass is used to store the signing keys.
TODO: make target to generate signing key.
Now it becomes possible to create a dfu package to update the application through:
cd build/default make generate_dfu_package_application
Dependencies between these steps might need to be included.
It is possible to set what entry in
pass is used:
The contents of this file when executing on the command-line:
should be something like:
-----BEGIN EC PRIVATE KEY------ ... ... -----END EC PRIVATE KEY------
All build specific commands should be run from the target directory, while non-build specific commands can be run from the build directory. To write everything, for now you will need the following series of commands.
cd build make erase make write_softdevice cd default make write_board_version make write_application make write_bootloader_settings cd bootloader make write_bootloader make write_bootloader_address
If the dust settles we might have one single
make write_all command as well. Keep tight. :-)
You can find more on logs (over UART) in this document.
To start debugging the target, run first in a separate console:
cd build/default make debug_server
Then run the debug session in another console:
In a third console, you can also run an RTT Client
If you want to configure for a different target, go to the
config directory in the workspace and copy the default configuration files to a new directory, say
cd config cp -r default board0
Go to the build
cd build cmake .. -DBOARD_TARGET=board0 make
The other commands are as in the usual setting.
Note, now, if you change a configuration setting you will also need to run
It picks up the configuration settings at configuration time and then passes them as defines to
CMake in the bluenet directory.
cd build cmake .. make
Only after this you can assume that the
make targets in
build/default or any other target are up to date.
Overwrites and runtime configs
The following is convenient if you have multiple boards attached to your system.
It is possible to have a second file in your target directory that overwrites values in your
The file is called
For example to flash to two different boards, both attached to a USB port.
cd build make list_jlinks
Note the serial number of your JLink device and add it to for example
On the moment there is no rebuild triggered when the values in this file change.
Another convenient variable to set there is
GDB_PORT. To have both running in parallel:
cd build cmake .. -DBOARD_TARGET=board0 && make cd build/board0 make debug_server cmake .. -DBOARD_TARGET=board1 && make cd build/board1 make debug_server
For in particular the above information you perhaps do not want to have everything recompiled just because you use
a particular JLINK device. The file that is used for runtime only is
CMakeBuild.runtime.config. If you write
SERIAL_NUM=682450212 in that file this can be altered without causing
cmake to run again.
Information about the MAC address can be obtained through the make system as well:
The address is stored by Nordic as 48 bits in two registers,
DEVICEADDR. Depending on the last two bits, this is a static or a private address (resolvable or non-resolvable). Those bits are normally set to 00, but due to the fact that the Crownstones are static addresses, we set them to 11. This means we can use the result to connect to the Crownstone (for the setup process for instance).
Note that reading out UICR/FICR registers can cause the firmware to halt. Run
make reset afterwards.
It is possible to make use of the
csutil utility which can be sourced through a cmake flag:
cmake .. -DDOWNLOAD_CSUTIL=ON # and other flags
You can prepare the configuration used to set up a Crownstone by
Or individually as
BLUENET_CONFIG=MAC_ADDRESS make write_config BLUENET_CONFIG=IBEACON_MINOR make write_config ...
This will write a
CMakeBuild.dynamic.config file locally. To perform the setup, run
This will generate a
config.json file with the proper information and use the
csutil tool to perform the setup. You can also do a factory reset.
csutil tool uses the Crownstone BLE library under the hood. That means that you can also setup hardware that is not attached to your machine. In that case make sure you have the right config values set (e.g. in
Running in a VM
It is recommended to use a virtual machine (running Ubuntu 18.04 or newer) for compiling/developing bluenet if you're basic operating system is different (e.g. on archlinux).
The user of the host machine has to be added to the vboxusers group. Log out and back in after running this command.
sudo gpasswd -a m vboxusers
Also it is recommended to check if a J-Link programmer is correctly connected on the host machine.
lsusb | grep J-Link
For VirtualBox "guest editions" has to be installed on the Ubuntu virtual machine. Insert the guest editions into the VM by going to the bar menu and pressing "Devices > Insert guest editions". Ubuntu should show a pop up to help you further.
After this setup go to the bar menu to "Devices > USB > ". After selecting the J-link run the following command in the Ubuntu VM to check if the J-link correctly setup.
lsusb | grep J-Link
On older ubuntu versions, python2.7 is the default version. This gives issues with nrfutil.
This can be fixed by installing pip2, removing nrfutil from pip3, and installing nrfutil with pip2.
Not for everyday users, just for maintainers of this code base, there are more options. A few of the options are described in the Build System document.
There are a few other options which can be found as well by typing
make, a space and then TAB. Some examples:
For a linter (cppcheck):
make generate_documentation make view_documentation
By the way, to remove dependency checking,
CMake introduces for each target also a fast variant. For example, the
debug target depends on the
To actually only run
debug, just type:
This option exists for almost all targets.
If there are bugs in the build process, please indicate so.
The default installation procedure is done through continuous integration. If it is successful you will see a proper building button:
In that case, check your system to see if you've done something peculiar. :-)