# How to compile the rnode firmware yourself ## Dependencies Make sure 'git', 'make', 'python' and 'pip' are instaled. Most like;y these are already availble on your system. Otherwise do: $ sudo apt install git $ sudo apt install make $ sudo apt install pip $ sudo apt install python Download arduino-cli $ cd $ curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh Add arduino-cli to path by editing ~/.bashrc $ nano ~/.bashrc add 'export PATH=~/bin:$PATH' to end of file ## Clone git repo $ git clone https://github.com/liberatedsystems/RNode_Firmware_CE.git ## Prepare Install the required BSP and libraries for the ESP32 system. $ cd RNode_Firmware_CE/ $ make prep-esp32 This command stalled. I stopped the command by hiting CTRL-C and restarted it. Add rns software to path: $ nano ~/.bashrc add 'export PATH=~/.local/bin:$PATH' to the end of the file. ## Test To test if you can compile the firmware try it: $ make firmware-heltec32_v3 Fingers crossed! ## Define new board, the theory In order to build custom firmware for a new board it has to be defined in several files. ### Makefile BOARD_MODEL defines the target board. It is a unique 8 bit number. BOARD_VARIANT defines the variant of the board. A board could come with different LoRa transceivers, for example. It is also a unique 8 bit number. Every target board has a section 'firmware-', 'upload-' and 'release-' ### boards.h Both BOARD_MODEL and BOARD_VARIANT are #defines in this file. They are used to define the pinout of the SPI port and if it has certain perifirals such as a screen BLE etc. Let's see an example: #elif BOARD_MODEL == BOARD_HELTEC32_V3 #define IS_ESP32S3 true #define HAS_DISPLAY true #define DISPLAY OLED #define HAS_BLUETOOTH false #define HAS_BLE true #define HAS_PMU true #define HAS_CONSOLE true #define HAS_EEPROM true #define HAS_INPUT true #define HAS_SLEEP true #define PIN_WAKEUP GPIO_NUM_0 #define WAKEUP_LEVEL 0 #define INTERFACE_COUNT 1 #define OCP_TUNED 0x38 const int pin_btn_usr1 = 0; #if defined(EXTERNAL_LEDS) const int pin_led_rx = 13; const int pin_led_tx = 14; #else const int pin_led_rx = 35; const int pin_led_tx = 35; #endif const uint8_t interfaces[INTERFACE_COUNT] = {SX1262}; const bool interface_cfg[INTERFACE_COUNT][3] = { // SX1262 { true, // DEFAULT_SPI true, // HAS_TCXO true // DIO2_AS_RF_SWITCH }, }; const int8_t interface_pins[INTERFACE_COUNT][10] = { // SX1262 { 8, // pin_ss 9, // pin_sclk 10, // pin_mosi 11, // pin_miso 13, // pin_busy 14, // pin_dio 12, // pin_reset -1, // pin_txen -1, // pin_rxen -1 // pin_tcxo_enable } }; If we want to add support for a new board we have to add a new section for this board. Here we define all the features it has or not has. ## Define new board for real Let's say we want to add support for the Waveshare ESP32-S3 Pico with an SX1278 LoRa transceiver. First we have to make define both BOARD_MODEL and BOARD_VARIANT. Let's define BOARD_MODEL as 0x61 and BOARD_VARIANT as 0x31 as these numbers are not used yet. Here the 0x31 indicates the use of a SX1278 LoRa transceiver. In the future we can define more transceivers for this board. Then we make entries in the Makefile. firmware-waveshare-esp32-s3-pico: arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x61\" \"-DBOARD_VARIANT=0x31\"" upload-waveshare-esp32-s3-pico: arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:esp32s3 @sleep 1 rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.waveshare-esp32-s3-pico/RNode_Firmware_CE.ino.bin) @sleep 3 python ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) --chip esp32-s3 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin release-waveshare-esp32-s3-pico: arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x61\" \"-DBOARD_VARIANT=0x31\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_waveshare-esp32-s3-pico.boot_app0 cp build/esp32.esp32.waveshare-esp32-s3-pico/RNode_Firmware_CE.ino.bin build/rnode_firmware_waveshare-esp32-s3-pico.bin cp build/esp32.esp32.waveshare-esp32-s3-pico/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_waveshare-esp32-s3-pico.bootloader cp build/esp32.esp32.waveshare-esp32-s3-pico/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_waveshare-esp32-s3-pico.partitions zip --junk-paths ./Release/rnode_firmware_waveshare-esp32-s3-pico.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_t3s3_sx126xrnode_firmware_waveshare-esp32-s3-pico.boot_app0 build/rnode_firmware_waveshare-esp32-s3-pico.bin build/rnode_firmware_waveshare-esp32-s3-pico.bootloader build/rnode_firmware_waveshare-esp32-s3-pico.partitions rm -r build In the file Boards.h make an entry for the new board within the '#if MCU_VARIANT == MCU_ESP32': #elif BOARD_MODEL == BOARD_WAVESHARE_ESP32_S3_PICO #define HAS_DISPLAY true #define DISPLAY OLED #define HAS_BLUETOOTH true #define HAS_PMU true #define HAS_CONSOLE true #define HAS_EEPROM true #define INTERFACE_COUNT 1 const uint8_t interfaces[INTERFACE_COUNT] = {SX1276}; #if HAS_TCXO == true const bool interface_cfg[INTERFACE_COUNT][3] = { // SX127X { true, // DEFAULT_SPI true, // HAS_TCXO false // DIO2_AS_RF_SWITCH }, }; const int8_t interface_pins[INTERFACE_COUNT][10] = { // SX127X { 18, // pin_ss -1, // pin_sclk -1, // pin_mosi -1, // pin_miso -1, // pin_busy 26, // pin_dio 23, // pin_reset -1, // pin_txen -1, // pin_rxen 33 // pin_tcxo_enable } }; #endif #if defined(EXTERNAL_LEDS) const int pin_led_rx = 15; const int pin_led_tx = 4; #else const int pin_led_rx = 25; const int pin_led_tx = 25; #endif #if HAS_TCXO == false const bool interface_cfg[INTERFACE_COUNT][3] = { // SX127X { true, // DEFAULT_SPI false, // HAS_TCXO false // DIO2_AS_RF_SWITCH }, }; const int8_t interface_pins[INTERFACE_COUNT][10] = { // SX127X { 18, // pin_ss -1, // pin_sclk -1, // pin_mosi -1, // pin_miso -1, // pin_busy 26, // pin_dio 23, // pin_reset -1, // pin_txen -1, // pin_rxen -1 // pin_tcxo_enable } }; #endif Also, in the file Utilities.h add entry. Again, within the '#if MCU_VARIANT == MCU_ESP32'. #elif BOARD_MODEL == BOARD_LORA32_V2_1 void led_rx_on() { digitalWrite(pin_led_rx, HIGH); } void led_rx_off() { digitalWrite(pin_led_rx, LOW); } void led_tx_on() { digitalWrite(pin_led_tx, HIGH); } void led_tx_off() { digitalWrite(pin_led_tx, LOW); } void led_id_on() { } void led_id_off() { } ### Flashing the board Make shure you are in the dialout group. If not: $ sudo usermod -aG dialout If you are flashing a custom board, you will need to generate a signing key in rnodeconf prior to flashing if you do not already have one by running: $ rnodeconf -k Than flash the firmware. $ make upload-waveshare-esp32-s3-pico This will end with error 'This device has not been provisioned yet, cannot set firmware hash'. But fear not. After flashing a custom board, you will also need to provision the EEPROM before use: $ rnodeconf /dev/ttyACM0 -r --platform ESP32 --model a4 --product f0 --hwrev 3 ### Migrating to a other system When the rnode is flashed, it is signed with a key. If you conect the rnode to another system, this key cannot be validated. It is possible to write a new key to the rnode by erasing the eeprom and writing the local key to it. $ rnodeconf /dev/ttyACM0 --eeprom-wipe $ rnodeconf /dev/ttyACM0 -r --platform ESP32 --model a9 --product f0 --hwrev 3