/ ENV_SETUP.md
ENV_SETUP.md
  1  # Bristlemouth Firmware Environment Setup Instructions
  2  
  3  ## Developer Guide (in progress)
  4  If you already have your development environment set up, check out the [DEVELOPER.md](DEVELOPER.md) file for some quick start guides, etc...
  5  
  6  If you're developing on the Bristlemouth Development Kit, see the [BMDK_README.md](./src/apps/bm_devkit/BMDK_README.md)
  7  
  8  After you're finished setting everything up for the command line, if you want to build using VS Code, check out
  9  [`docs/vscode-setup.md`](docs/vscode-setup.md).
 10  
 11  ## Initial setup
 12  ### Install conda
 13  
 14  [Conda](https://docs.conda.io/en/latest/) is used to manage dependencies (compiler, openocd, cmake, python) so that everyone has the same version of all the tools (without affecting the rest of your system).
 15  
 16  (If you're running on a Raspberry Pi with Ubuntu 64-bit, you'll need to use [miniforge](https://github.com/conda-forge/miniforge) instad of miniconda.)
 17  
 18  (If you're on a Mac, you may need to first install the Xcode command-line tools.  One way to do this is to run `xcode-select --install` in a Terminal window.)
 19  
 20  If you don't have conda installed, follow these steps by choosing the proper line for your platform:
 21  
 22  ```
 23  $ cd /tmp
 24  # Download for Mac (Apple Silicon / M1 / M1 Pro / M2 / etc.):
 25  $ curl -O https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh
 26  # or, download for Mac (Intel):
 27  $ curl -O https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh
 28  # or, download for Linux:
 29  $ wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
 30  # install it
 31  $ bash Miniconda3-latest-*.sh
 32  ```
 33  
 34  - Scroll through the instructions using your space bar and accept the license terms.
 35  - Tell the installer that, yes, you do want to initialize miniconda, by pressing ENTER and then entering `yes`
 36  
 37  **NOTE:** You'll have to relaunch your terminal for conda to start working.
 38  
 39  You'll notice that the new terminal will be inside the conda (base) environment, if you don't want this to happen automatically, just run `conda config --set auto_activation_base false` once and relaunch.
 40  
 41  ### Extra Linux Setup
 42  
 43  For now, we have to use gcc that comes with Linux to build the tests
 44  
 45  `sudo apt install gcc g++`
 46  
 47  If you plan on flashing/debugging with linux, you'll also need the following
 48  `sudo apt install libncurses5 libncurses5-dev python2.7 python2.7-dev`
 49  
 50  Don't forget to copy the [udev rules](tools/udev) so the STLink will work!
 51  
 52  ### Set up environment
 53  
 54  This will create a conda environment and download/install all the dependencies.
 55  You will have to activate this specific environment whenever you're working inside this repo.
 56  
 57  ```
 58  $ conda create -n bristlemouth
 59  $ conda activate bristlemouth
 60  $ conda env update -f environment.yml
 61  ```
 62  
 63  Once you're done, you can always deactivate the environment with:
 64  ```
 65  $ conda deactivate
 66  ```
 67  
 68  Whenever you pull new project changes (specifically those that update environment.yml), you should run `conda env update -f environment.yml` again.
 69  
 70  ### Set up Pre-commit
 71  
 72  This is an optional step that will install helpful Pre-commit checks to make your code safer and more "beautiful". Make sure to have your conda env updated and active before running this command.
 73  
 74  ```
 75  pre-commit install
 76  ```
 77  You can also run the checks whenever you want by running:
 78  ```
 79  pre-commit run
 80  ```
 81  
 82  Note that if pre-commit modifies your code, you will need to `git add` the files before you commit them.
 83  If you'd like to force a commit through, use the `git commit --no-verify` flag.
 84  
 85  ### Set up environment variables
 86  The environment variables needed for the project are listed in `.env.example`.
 87  If you want to make use of [Memfault](#memfault) analysis you'll need to gather your credentials and put them in a `.env` file
 88  that is copied from the `.env.example`.
 89  
 90  ### Pull submodules
 91  Bristlemouth uses several submodules to include third party libraries, etc.
 92  These files might not have been downloaded when cloning/pulling. If that's the case, run `git submodule update --init` to download them.
 93  
 94  A couple things to note about submodules:
 95  - The submodule folders do not update SHAs automatically. If we need updated scripts, run `git submodule update --remote path/to/submodule`
 96  
 97  
 98  ## Building/Flashing - Command-line
 99  
100  **🛑 NOTE:** If you came here from the *Bristlemouth Dev Kit Guide*, you do not need to  complete the following sections.  You can now return to the document that brought you here.
101  
102  ### Configure CMake
103  
104  This follows a pretty standard cmake process. First you create a directory for this particular build/configuration. You can either create a top level directory for each build (/cmake-build-debug, /cmake-build-bridge) or one top level directory with individual build subdirectories (/cmake-build/bristlemouth, /cmake-build/bridge). The `cmake-build` prefix is in the .gitignore, so however you structure the different folders they should still begin with that.
105  
106  ```
107  # Sub-directory example
108  $ mkdir -p cmake-build/bridge
109  $ cd cmake-build/bridge
110  ```
111  
112  Then you run cmake and tell it where the toolchain file is located, which BSP(board support package) to use, as well as which application. Pay attention to the `../` relative paths in the args - depending on how your cmake build directories are set up, you might have to replace them with `../..`.
113  
114  
115  ```
116  # If you have individual top-level build directores for each app
117  $  cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/arm-none-eabi-gcc.cmake -DBSP=bridge_v1_0 -DAPP=bridge -DCMAKE_BUILD_TYPE=Debug
118  
119  # If you have one top-level build dir with different sub-dirs for each app
120  $  cmake ../.. -DCMAKE_TOOLCHAIN_FILE=../../cmake/arm-none-eabi-gcc.cmake -DBSP=bridge_v1_0 -DAPP=bridge -DCMAKE_BUILD_TYPE=Debug
121  ```
122  
123  You can optionally set the build type to release (it defaults to Debug) by appending `-DCMAKE_BUILD_TYPE=Release` to the command.
124  
125  ### Building the Project
126  
127  Once inside the build directory you can just run:
128  
129  ```
130  make
131  ```
132  
133  or
134  
135  ```
136  $ cmake --build .
137  ```
138  
139  If you want to enable parallel builds, add `-j` to either of those commands.
140  
141  ### Bootloader
142  Before flashing your application, you **MUST** first build/flash the bootloader. This only needs to happen once per device.
143  
144  To configure:
145  
146  ```
147  $ mkdir -p cmake-build/bootloader
148  $ cd cmake-build/bootloader
149  $ cmake ../.. -DCMAKE_TOOLCHAIN_FILE=../../cmake/arm-none-eabi-gcc.cmake -DBSP=bootloader -DAPP=bootloader -DCMAKE_BUILD_TYPE=Release
150  ```
151  
152  To build and flash the bootloader:
153  
154  If you have an STLink SWD or SWD over USB-C debugger (flashing the bootloader on the first Flash over DFU USB not currently supported):
155  ```
156  make -j flash
157  ```
158  
159  ### Flashing/Debugging
160  To flash using openOCD/STLink (more debugger support to be added later), you can just run:
161  
162  **NOTE: You will need to flash the bootloader before you can use any application. This only has to be done once**
163  
164  ```
165  $ make flash
166  ```
167  
168  To run the GDB debugger, you can use:
169  
170  ```
171  $ make debug
172  ```
173  
174  #### USB dfu-util
175  
176  You can also take advantage of the built-in usb bootloader in the STM32U575 to flash the device. You'll need to have [dfu-util](http://dfu-util.sourceforge.net/) installed. On MacOS just `brew install dfu-util`, on Ubuntu just `apt-get install dfu-util` (I do hope to add it to the conda environment, but it's not a high priority right now.)
177  
178  If over USB (Note - this is currently broken on DevMote + Bristlefin cc @Victor):
179  First need to put system into bootloader mode, by sending the bootloader command over serial.
180  - connect to the serial device ending in `1`, not `3`:
181    ![img_1.png](img_1.png)
182  - send `bootloader` command, and you'll get booted out.
183  - Then can DFU flash from build dir with:
184  ```
185  make -j dfu_flash
186  ```
187  - Note: this is what a fail looks like:
188    ![img.png](img.png)
189  - This is what success looks like:
190    ![img_2.png](img_2.png)
191  
192  Once the device is in DFU mode, you can run `dfu-util -l` to see if the device is detected. To flash it with the latest firmware, just run `make dfu_flash`!
193  
194  `make dfu_flash` can be used with both the bootloader and main applications.
195  
196  
197  #### Flashing with a specific STLink device
198  If you have more than one STLink debugger connected to your computer, you must tell the flashing script which one to use. The way to do this is as follows:
199  
200  ```STLINK_SERIAL=004D00423438510B34313939 make flash```
201  
202  To get the serial number on MacOS, you'll have to go to system information and look in the USB device tree for the STLink device. There should be a Serial Number field for each one.
203  
204  In Linux, use `udevadm info /dev/ttyACM2 | grep ID_SERIAL_SHORT` or `lsusb -v -d 0483:374b | grep iSerial` (on the appropriate device)
205  
206  ## Unit Tests
207  
208  We're using [GoogleTest](https://github.com/google/googletest) to run the unit tests. At the moment, the tests are compiled and run natively on the host machine. The goal, eventually, is to compile them with the ARM compiler and run them on an emulator such as [Renode](https://renode.io/).
209  
210  **Note:** Linux and MacOS aren't using the exact same compiler to run the tests. They're both clang, but MacOS uses the builtin one and Linux the one from the Conda envrionment. It's not a huge issue so I'm not going to spend the time to debug that right now.
211  
212  ### Configure CMake
213  
214  This follows a pretty standard cmake process. First you create a directory for this particular build/configuration.
215  
216  ```
217  $ mkdir test-build
218  $ cd test-build
219  ```
220  
221  Then you run cmake
222  
223  ```
224  $ cmake -DCMAKE_BUILD_TYPE=Test ../
225  ```
226  
227  ### Building the tests
228  
229  Once inside the build directory you can just run:
230  
231  ```
232  $ cmake --build .
233  ```
234  
235  
236  ### Running the tests
237  To run the tests, use the command (make sure you already built the tests before running!):
238  
239  ```
240  $ ctest
241  ```
242  
243  To see fancy colored output with test details, run:
244  ```
245  $ export GTEST_COLOR=1; ctest -V
246  ```
247  
248  ## micropython
249  
250  In order to build with micropython support, you must pass the `-DUSE_MICROPYTHON=1` cmake flag.
251  
252  ### Building mpy-cross on macOS arm64
253  There's currently a bug with building the micropython cross-compiler `mpy-cross` on arm64 MacOS (it works fine while using Rosetta). There are missing include files while trying to build `mpy-cross`. Thankfully, there's a workaround.
254  
255  We can compile mpy-cross separately by providing the correct CPATH for the c/c++ include libraries. (We can't do this for the entire project, since it will break the microcontroller firmware cross-compilation)
256  ```
257  cd src/third_party/micropython/mpy-cross
258  export CPATH="`xcrun --show-sdk-path`/usr/include"
259  make
260  mkdir -p `git rev-parse --show-toplevel`/tools/bin
261  cp build/mpy-cross `git rev-parse --show-toplevel`/tools/bin
262  ```
263  
264  Once mpy-cross is compiled and saved in tools/bin, we can point the build process to it so it doesn't try to re-build it.
265  ```
266  export MICROPY_MPYCROSS=`git rev-parse --show-toplevel`//tools/bin/mpy-cross
267  make -j
268  ```
269  
270  
271  ## Memfault
272  If you're using [Memfault](https://memfault.com/) for crash analysis, this section covers some useful workflows.
273  
274  ### Uploading .elf to Memfault
275  
276  After building the project, run `make memfault_upload`. Make sure your .env file is set up ahead of time!
277  
278  ### Uploading memfault coredump over GDB
279  If you're in GDB and a crash occurs, this is how you capture a coredump to upload to memfault (make sure you already ran `make memfault_upload`!) :
280  
281  In GDB:
282  `source ../../../src/third_party/memfault-firmware-sdk/scripts/memfault_gdb.py`
283  
284  then
285  
286  `memfault login your@email <your memfault API key goes here> -o <your organization> -p <your project>`
287  
288  if you're developing in the Sofar organization:
289  `memfault login your@email <your memfault API key goes here> -o sofar-ocean -p bristlemouth`
290  
291  finally
292  
293  `memfault coredump`