Compare commits
19 Commits
f143109d66
...
af8647d239
| Author | SHA1 | Date | |
|---|---|---|---|
| af8647d239 | |||
| 91df82b6cf | |||
| d7594dfa03 | |||
| d925afc2f8 | |||
| e1029912e6 | |||
| d31c6f8168 | |||
| 7ae7aa659d | |||
| 94c33be6b4 | |||
| c080295b49 | |||
| 46c04649ca | |||
| 7f5b20d028 | |||
|
|
d39339f8ec | ||
|
|
9b39b6ce59 | ||
|
|
3167a3e679 | ||
|
|
fe594b2048 | ||
|
|
9fd0ae33d2 | ||
|
|
0c07c1b856 | ||
|
|
ae0434726b | ||
|
|
5d2f0b93e3 |
345
Boards.h
345
Boards.h
@@ -61,7 +61,9 @@
|
||||
#define MODEL_D9 0xD9 // LilyGO T-Deck, 868 MHz
|
||||
|
||||
#define PRODUCT_TBEAM_S_V1 0xEA
|
||||
#define PRODUCT_TBEAM_S_V3 0xEC
|
||||
#define BOARD_TBEAM_S_V1 0x3D
|
||||
#define BOARD_TBEAM_S_V3 0x43
|
||||
#define MODEL_DB 0xDB // LilyGO T-Beam Supreme, 433 MHz
|
||||
#define MODEL_DC 0xDC // LilyGO T-Beam Supreme, 868 MHz
|
||||
|
||||
@@ -122,6 +124,13 @@
|
||||
#define MODEL_FE 0xFE // Homebrew board, max 17dBm output power
|
||||
#define MODEL_FF 0xFF // Homebrew board, max 14dBm output power
|
||||
|
||||
#define BOARD_MESHPOE_S3 0xF1 // MeshPoE-S3
|
||||
#define BOARD_MESHADVENTURER_S3 0xF2 // MeshAdventurer-S3
|
||||
#define BOARD_AETHERNODE 0xF3 // Aethernode
|
||||
#define BOARD_MESHADVENTURER 0xF4 // MeshAdventurer
|
||||
#define BOARD_PROMICRO 0xF5 // FakeTec (Promicro)
|
||||
#define BOARD_DIY_V1 0xF6 // DIY-V1
|
||||
|
||||
#if defined(__AVR_ATmega1284P__)
|
||||
#define PLATFORM PLATFORM_AVR
|
||||
#define MCU_VARIANT MCU_1284P
|
||||
@@ -149,6 +158,10 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define LORA_PA_UNKNOWN 0x00
|
||||
#define LORA_PA_GC1109 0x01
|
||||
#define LORA_PA_KCT8103L 0x02
|
||||
|
||||
#define HAS_DISPLAY false
|
||||
#define HAS_BLUETOOTH false
|
||||
#define HAS_BLE false
|
||||
@@ -219,19 +232,212 @@
|
||||
#define PIN_GPS_RX 34
|
||||
|
||||
#if BOARD_MODEL == BOARD_GENERIC_ESP32
|
||||
#define HAS_DISPLAY true
|
||||
#define HAS_BLUETOOTH true
|
||||
#define HAS_WIFI true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
const int pin_cs = 4;
|
||||
const int pin_reset = 33;
|
||||
const int pin_dio = 39;
|
||||
const int pin_led_rx = 14;
|
||||
const int pin_led_tx = 32;
|
||||
#define HAS_BUSY true
|
||||
#define HAS_INPUT true
|
||||
#define HAS_TCXO true
|
||||
#define MODEM SX1262
|
||||
#define DIO2_AS_RF_SWITCH true
|
||||
#define HAS_RF_SWITCH_RX_TX false
|
||||
const int pin_cs = 5;
|
||||
const int pin_sclk = 18;
|
||||
const int pin_miso = 19;
|
||||
const int pin_mosi = 23;
|
||||
const int pin_busy = 32;
|
||||
const int pin_reset = 34;
|
||||
const int pin_dio = 33;
|
||||
const int pin_txen = -1;
|
||||
const int pin_rxen = -1;
|
||||
const int pin_tcxo_enable = -1;
|
||||
|
||||
const int pin_btn_usr1 = 39;
|
||||
const int pin_led_rx = 2;
|
||||
const int pin_led_tx = 4;
|
||||
|
||||
#elif BOARD_MODEL == BOARD_MESHPOE_S3
|
||||
#define IS_ESP32S3 true
|
||||
#define HAS_DISPLAY true
|
||||
#define HAS_NP true
|
||||
#define HAS_BLUETOOTH false
|
||||
#define HAS_BLE true
|
||||
#define HAS_WIFI true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
#define HAS_BUSY true
|
||||
#define HAS_INPUT true
|
||||
#define HAS_TCXO true
|
||||
#define MODEM SX1262
|
||||
#define DIO2_AS_RF_SWITCH true
|
||||
#define HAS_RF_SWITCH_RX_TX false
|
||||
#define HAS_LORA_LNA true
|
||||
#define LORA_LNA_GAIN 30
|
||||
#define LORA_LNA_GVT 14
|
||||
|
||||
const int pin_cs = 39;
|
||||
const int pin_sclk = 38;
|
||||
const int pin_miso = 36;
|
||||
const int pin_mosi = 37;
|
||||
const int pin_busy = 34;
|
||||
const int pin_reset = 35;
|
||||
const int pin_dio = 33;
|
||||
const int pin_txen = 43;
|
||||
const int pin_rxen = 44;
|
||||
const int pin_tcxo_enable = -1;
|
||||
|
||||
const int pin_btn_usr1 = 40;
|
||||
const int pin_np = 48;
|
||||
|
||||
#if HAS_NP == false
|
||||
#if defined(EXTERNAL_LEDS)
|
||||
const int pin_led_rx = 48;
|
||||
const int pin_led_tx = 48;
|
||||
#else
|
||||
const int pin_led_rx = 48;
|
||||
const int pin_led_tx = 48;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif BOARD_MODEL == BOARD_MESHADVENTURER_S3
|
||||
#define IS_ESP32S3 true
|
||||
#define HAS_DISPLAY true
|
||||
#define HAS_NP true
|
||||
#define HAS_BLUETOOTH false
|
||||
#define HAS_BLE true
|
||||
#define HAS_WIFI true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
#define HAS_BUSY true
|
||||
#define HAS_INPUT true
|
||||
#define HAS_TCXO true
|
||||
#define MODEM SX1262
|
||||
#define DIO2_AS_RF_SWITCH false
|
||||
#define HAS_RF_SWITCH_RX_TX true
|
||||
#define HAS_LORA_LNA true
|
||||
#define LORA_LNA_GAIN 30
|
||||
#define LORA_LNA_GVT 14
|
||||
|
||||
const int pin_cs = 39;
|
||||
const int pin_sclk = 38;
|
||||
const int pin_miso = 40;
|
||||
const int pin_mosi = 18;
|
||||
const int pin_busy = 7;
|
||||
const int pin_reset = 43;
|
||||
const int pin_dio = 15;
|
||||
const int pin_txen = 9;
|
||||
const int pin_rxen = 8;
|
||||
const int pin_tcxo_enable = -1;
|
||||
|
||||
const int pin_btn_usr1 = 4;
|
||||
const int pin_np = 48;
|
||||
|
||||
#if HAS_NP == false
|
||||
#if defined(EXTERNAL_LEDS)
|
||||
const int pin_led_rx = 48;
|
||||
const int pin_led_tx = 48;
|
||||
#else
|
||||
const int pin_led_rx = 48;
|
||||
const int pin_led_tx = 48;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif BOARD_MODEL == BOARD_MESHADVENTURER
|
||||
#define HAS_DISPLAY true
|
||||
#define HAS_BLUETOOTH true
|
||||
#define HAS_WIFI true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
#define HAS_BUSY true
|
||||
#define HAS_INPUT true
|
||||
#define HAS_TCXO true
|
||||
#define MODEM SX1262
|
||||
#define DIO2_AS_RF_SWITCH false
|
||||
#define HAS_RF_SWITCH_RX_TX true
|
||||
#define HAS_LORA_LNA true
|
||||
#define LORA_LNA_GAIN 30
|
||||
#define LORA_LNA_GVT 14
|
||||
|
||||
const int pin_cs = 18;
|
||||
const int pin_sclk = 5;
|
||||
const int pin_miso = 19;
|
||||
const int pin_mosi = 27;
|
||||
const int pin_busy = 32;
|
||||
const int pin_reset = 23;
|
||||
const int pin_dio = 33;
|
||||
const int pin_txen = 13;
|
||||
const int pin_rxen = 14;
|
||||
const int pin_tcxo_enable = -1;
|
||||
|
||||
const int pin_btn_usr1 = 39;
|
||||
const int pin_led_rx = 2;
|
||||
const int pin_led_tx = 4;
|
||||
|
||||
#elif BOARD_MODEL == BOARD_DIY_V1
|
||||
#define HAS_DISPLAY true
|
||||
#define HAS_BLUETOOTH true
|
||||
#define HAS_WIFI true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
#define HAS_BUSY true
|
||||
#define HAS_INPUT true
|
||||
#define HAS_TCXO true
|
||||
#define MODEM SX1262
|
||||
#define DIO2_AS_RF_SWITCH false
|
||||
#define HAS_RF_SWITCH_RX_TX true
|
||||
#define HAS_LORA_LNA true
|
||||
#define LORA_LNA_GAIN 17
|
||||
#define LORA_LNA_GVT 12
|
||||
|
||||
const int pin_cs = 18;
|
||||
const int pin_sclk = 5;
|
||||
const int pin_miso = 19;
|
||||
const int pin_mosi = 27;
|
||||
const int pin_busy = 32;
|
||||
const int pin_reset = 23;
|
||||
const int pin_dio = 33;
|
||||
const int pin_txen = 13;
|
||||
const int pin_rxen = 14;
|
||||
const int pin_tcxo_enable = -1;
|
||||
|
||||
const int pin_btn_usr1 = 39;
|
||||
const int pin_led_rx = 2;
|
||||
const int pin_led_tx = 4;
|
||||
|
||||
#elif BOARD_MODEL == BOARD_AETHERNODE
|
||||
#define HAS_DISPLAY true
|
||||
#define HAS_BLUETOOTH true
|
||||
#define HAS_WIFI true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_EEPROM true
|
||||
#define HAS_BUSY true
|
||||
#define HAS_INPUT true
|
||||
#define HAS_TCXO true
|
||||
#define MODEM SX1262
|
||||
#define DIO2_AS_RF_SWITCH false
|
||||
#define HAS_RF_SWITCH_RX_TX true
|
||||
const int pin_cs = 5;
|
||||
const int pin_sclk = 18;
|
||||
const int pin_miso = 19;
|
||||
const int pin_mosi = 23;
|
||||
const int pin_busy = 32;
|
||||
const int pin_reset = 25;
|
||||
const int pin_dio = 33;
|
||||
const int pin_rxen = 16;
|
||||
const int pin_txen = 17;
|
||||
const int pin_tcxo_enable = -1;
|
||||
|
||||
const int pin_btn_usr1 = 39;
|
||||
const int pin_led_rx = 2;
|
||||
const int pin_led_tx = 4;
|
||||
|
||||
#elif BOARD_MODEL == BOARD_TBEAM
|
||||
#define HAS_DISPLAY true
|
||||
#define HAS_PMU true
|
||||
#define HAS_BLUETOOTH true
|
||||
#define HAS_WIFI true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_SD false
|
||||
#define HAS_EEPROM true
|
||||
@@ -251,7 +457,7 @@
|
||||
#define HAS_TCXO true
|
||||
#define HAS_BUSY true
|
||||
#define DIO2_AS_RF_SWITCH true
|
||||
#define OCP_TUNED 0x18
|
||||
#define OCP_TUNED 0x28
|
||||
const int pin_busy = 32;
|
||||
const int pin_dio = 33;
|
||||
const int pin_tcxo_enable = -1;
|
||||
@@ -357,7 +563,7 @@
|
||||
#define HAS_SLEEP true
|
||||
#define PIN_WAKEUP GPIO_NUM_0
|
||||
#define WAKEUP_LEVEL 0
|
||||
#define OCP_TUNED 0x18
|
||||
#define OCP_TUNED 0x28
|
||||
|
||||
const int pin_btn_usr1 = 0;
|
||||
|
||||
@@ -399,8 +605,9 @@
|
||||
#define HAS_LORA_LNA true
|
||||
#define PIN_WAKEUP GPIO_NUM_0
|
||||
#define WAKEUP_LEVEL 0
|
||||
#define OCP_TUNED 0x18
|
||||
#define OCP_TUNED 0x28
|
||||
#define Vext GPIO_NUM_36
|
||||
#define LORA_PA_MODEL LORA_PA_UNKNOWN;
|
||||
|
||||
const int pin_btn_usr1 = 0;
|
||||
|
||||
@@ -422,14 +629,17 @@
|
||||
|
||||
#define LORA_LNA_GAIN 17
|
||||
#define LORA_LNA_GVT 12
|
||||
#define LORA_PA_GC1109 true
|
||||
#define LORA_PA_PWR_EN 7
|
||||
#define LORA_PA_CSD 2
|
||||
#define LORA_PA_CPS 46
|
||||
#define LORA_PA_CSD 2 // Same pin on GC1109
|
||||
#define LORA_PA_CPS 46 // Same pin on GC1109
|
||||
#define LORA_PA_CTX 5 // Only used on KCT8103
|
||||
|
||||
#define PA_MAX_OUTPUT 28
|
||||
#define PA_GAIN_POINTS 22
|
||||
#define PA_GAIN_VALUES 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 9, 8, 7
|
||||
|
||||
#define LORA_LNA_KCT8103L_GAIN 21
|
||||
const int PA_GC1109_VALUES[PA_GAIN_POINTS] = {11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 9, 8, 7};
|
||||
const int PA_KCT8103L_VALUES[PA_GAIN_POINTS] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 11, 11, 10, 9, 8, 7};
|
||||
|
||||
const int pin_cs = 8;
|
||||
const int pin_busy = 13;
|
||||
@@ -613,6 +823,59 @@
|
||||
#endif
|
||||
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
|
||||
#define IS_ESP32S3 true
|
||||
#define MODEM SX1262
|
||||
#define DIO2_AS_RF_SWITCH true
|
||||
#define HAS_BUSY true
|
||||
#define HAS_TCXO true
|
||||
#define OCP_TUNED 0x28
|
||||
|
||||
#define HAS_DISPLAY true
|
||||
#define HAS_CONSOLE true
|
||||
#define HAS_WIFI true
|
||||
#define HAS_BLUETOOTH false
|
||||
#define HAS_BLE true
|
||||
#define HAS_PMU true
|
||||
#define HAS_NP false
|
||||
#define HAS_SD false
|
||||
#define HAS_EEPROM true
|
||||
|
||||
#define HAS_INPUT true
|
||||
#define HAS_SLEEP false
|
||||
|
||||
#define PMU_IRQ 40
|
||||
#define I2C_SCL 41
|
||||
#define I2C_SDA 42
|
||||
|
||||
const int pin_btn_usr1 = 0;
|
||||
|
||||
const int pin_cs = 10;
|
||||
const int pin_reset = 5;
|
||||
const int pin_sclk = 12;
|
||||
const int pin_mosi = 11;
|
||||
const int pin_miso = 13;
|
||||
const int pin_tcxo_enable = -1;
|
||||
const int pin_dio = 1;
|
||||
const int pin_busy = 4;
|
||||
|
||||
const int SD_MISO = 37;
|
||||
const int SD_MOSI = 35;
|
||||
const int SD_CLK = 36;
|
||||
const int SD_CS = 47;
|
||||
|
||||
const int IMU_CS = 34;
|
||||
|
||||
#if HAS_NP == false
|
||||
#if defined(EXTERNAL_LEDS)
|
||||
const int pin_led_rx = 43;
|
||||
const int pin_led_tx = 43;
|
||||
#else
|
||||
const int pin_led_rx = 43;
|
||||
const int pin_led_tx = 43;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V3
|
||||
#define IS_ESP32S3 true
|
||||
#define MODEM SX1262
|
||||
#define DIO2_AS_RF_SWITCH true
|
||||
@@ -887,6 +1150,62 @@
|
||||
const int DISPLAY_BL_PIN = PIN_T114_TFT_BLGT;
|
||||
const int DISPLAY_RST = PIN_T114_TFT_RST;
|
||||
|
||||
#elif BOARD_MODEL == BOARD_PROMICRO
|
||||
//TODO:
|
||||
// - Fix low output power
|
||||
// - Make compatible with non-TCXO radios
|
||||
// - Add PMU
|
||||
#define MODEM SX1262
|
||||
#define HAS_EEPROM false
|
||||
#define HAS_BLUETOOTH false
|
||||
#define HAS_BLE true
|
||||
#define HAS_CONSOLE false
|
||||
#define HAS_PMU true
|
||||
#define HAS_NP false
|
||||
#define HAS_SD false
|
||||
#define HAS_TCXO true
|
||||
#define HAS_BUSY true
|
||||
#define HAS_RF_SWITCH_RX_TX true
|
||||
#define DIO2_AS_RF_SWITCH true
|
||||
#define OCP_TUNED 0x38
|
||||
#define HAS_SLEEP false
|
||||
#define BLE_MANUFACTURER "DIY"
|
||||
#define BLE_MODEL "ProMicro"
|
||||
|
||||
#define HAS_INPUT true
|
||||
#define EEPROM_SIZE 296
|
||||
#define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
|
||||
|
||||
#define CONFIG_UART_BUFFER_SIZE 6144
|
||||
#define CONFIG_QUEUE_SIZE 6144
|
||||
#define CONFIG_QUEUE_MAX_LENGTH 200
|
||||
|
||||
//Confused with the pin numbers??
|
||||
//https://github.com/pdcook/nRFMicro-Arduino-Core/blob/a83161e619da8668f726b52578a3dd89c1ef5956/variants/nice_nano/variant.h#L59
|
||||
|
||||
#define HAS_DISPLAY true
|
||||
#define I2C_SDA 8 //P1.04
|
||||
#define I2C_SCL 7 //P0.11
|
||||
|
||||
#define PIN_LED_RED 22 //P0.15
|
||||
const int pin_led_rx = PIN_LED_RED;
|
||||
const int pin_led_tx = PIN_LED_RED;
|
||||
|
||||
#define PIN_VEXT_EN 21 //P0.13
|
||||
|
||||
const int pin_btn_usr1 = 6; //P1.00
|
||||
|
||||
const int pin_reset = 10; //P0.09
|
||||
const int pin_cs = 13; //P1.13
|
||||
const int pin_sclk = 12; //P1.11
|
||||
const int pin_mosi = 14; //P1.15
|
||||
const int pin_miso = 15; //P0.02
|
||||
const int pin_busy = 16; //P0.29
|
||||
const int pin_dio = 11; //P0.10
|
||||
const int pin_rxen = 2; //P0.17
|
||||
const int pin_txen = -1;
|
||||
const int pin_tcxo_enable = -1;
|
||||
|
||||
#else
|
||||
#error An unsupported nRF board was selected. Cannot compile RNode firmware.
|
||||
#endif
|
||||
@@ -921,7 +1240,7 @@
|
||||
// Default OCP value if not specified
|
||||
// in board configuration
|
||||
#ifndef OCP_TUNED
|
||||
#define OCP_TUNED 0x18
|
||||
#define OCP_TUNED 0x28
|
||||
#endif
|
||||
|
||||
#ifndef NP_M
|
||||
|
||||
11
Config.h
11
Config.h
@@ -20,7 +20,7 @@
|
||||
#define CONFIG_H
|
||||
|
||||
#define MAJ_VERS 0x01
|
||||
#define MIN_VERS 0x55
|
||||
#define MIN_VERS 0x56
|
||||
|
||||
#define MODE_HOST 0x11
|
||||
#define MODE_TNC 0x12
|
||||
@@ -110,7 +110,16 @@
|
||||
#define CSMA_CW_PER_BAND_WINDOWS 15
|
||||
#define CSMA_BAND_1_MAX_AIRTIME 7
|
||||
#define CSMA_BAND_N_MIN_AIRTIME 85
|
||||
|
||||
// Increase threshold for specific boards
|
||||
#if BOARD_MODEL == BOARD_MESHADVENTURER_S3 || BOARD_MODEL == BOARD_MESHADVENTURER
|
||||
#define CSMA_INFR_THRESHOLD_DB 14
|
||||
#elif BOARD_MODEL == BOARD_PROMICRO
|
||||
#define CSMA_INFR_THRESHOLD_DB 20
|
||||
#else
|
||||
#define CSMA_INFR_THRESHOLD_DB 11
|
||||
#endif
|
||||
|
||||
#define CSMA_RFENV_RECAL_MS 2500
|
||||
#define CSMA_RFENV_RECAL_LIMIT_DB -83
|
||||
bool interference_detected = false;
|
||||
|
||||
@@ -4,10 +4,10 @@ import sys
|
||||
import shutil
|
||||
|
||||
packages = {
|
||||
"rns": "rns-1.0.3-py3-none-any.whl",
|
||||
"nomadnet": "nomadnet-0.9.1-py3-none-any.whl",
|
||||
"lxmf": "lxmf-0.9.3-py3-none-any.whl",
|
||||
"rnsh": "rnsh-0.1.5-py3-none-any.whl",
|
||||
"rns": "rns-1.1.9-py3-none-any.whl",
|
||||
"nomadnet": "nomadnet-0.9.11-py3-none-any.whl",
|
||||
"lxmf": "lxmf-0.9.6-py3-none-any.whl",
|
||||
"rnsh": "rnsh-0.1.9-py3-none-any.whl",
|
||||
}
|
||||
|
||||
DEFAULT_TITLE = "RNode Bootstrap Console"
|
||||
@@ -194,8 +194,29 @@ def optimise_manual(path):
|
||||
("_images/meshchat_1.webp", pm),
|
||||
("_images/radio_is5ac.png", pm),
|
||||
("_images/radio_rblhg5.png", pm),
|
||||
("_images/rbrowser.webp", pm),
|
||||
("_images/rnphone.webp", pm),
|
||||
("_images/retibbs.webp", pm),
|
||||
("_images/meshchatx.webp", pm),
|
||||
("_images/lxst_phone.webp", pm),
|
||||
("_images/columba.webp", pm),
|
||||
("_static/rns_logo_512.png", 256),
|
||||
("../images/bg_h_1.webp", pm),
|
||||
|
||||
("../../images/3_conv.webp", pm/2),
|
||||
("../../images/an1.webp", pm/2),
|
||||
("../../images/bg1ds1.webp", pm/2),
|
||||
("../../images/bg1ds2.webp", pm/2),
|
||||
("../../images/bg_h_1.webp", pm/2),
|
||||
("../../images/bg_h_2.webp", pm/2),
|
||||
("../../images/g1p.webp", pm/2),
|
||||
("../../images/g2p.webp", pm/2),
|
||||
("../../images/g3p.webp", pm/2),
|
||||
("../../images/g4p.webp", pm/2),
|
||||
("../../images/lora_rnodes.webp", pm/2),
|
||||
("../../images/nn_an.webp", pm/2),
|
||||
("../../images/nn_conv.webp", pm/2),
|
||||
("../../images/nn_init.webp", pm/2),
|
||||
]
|
||||
|
||||
import subprocess
|
||||
|
||||
79
Display.h
79
Display.h
@@ -22,7 +22,7 @@
|
||||
#elif BOARD_MODEL == BOARD_HELTEC_T114
|
||||
#include "ST7789.h"
|
||||
#define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V1 || BOARD_MODEL == BOARD_TBEAM_S_V3
|
||||
#include <Adafruit_SH110X.h>
|
||||
#else
|
||||
#include <Wire.h>
|
||||
@@ -65,6 +65,41 @@
|
||||
#define DISP_ADDR 0x3C
|
||||
#define SCL_OLED 18
|
||||
#define SDA_OLED 17
|
||||
#elif BOARD_MODEL == BOARD_GENERIC_ESP32
|
||||
#define DISP_RST -1
|
||||
#define DISP_ADDR 0x3C
|
||||
#define SCL_OLED 22
|
||||
#define SDA_OLED 11
|
||||
#elif BOARD_MODEL == BOARD_MESHPOE_S3
|
||||
#define DISP_RST -1
|
||||
#define DISP_ADDR 0x3C
|
||||
#define SCL_OLED 1
|
||||
#define SDA_OLED 0
|
||||
#elif BOARD_MODEL == BOARD_MESHADVENTURER_S3
|
||||
#define DISP_RST -1
|
||||
#define DISP_ADDR 0x3C
|
||||
#define SCL_OLED 0
|
||||
#define SDA_OLED 42
|
||||
#elif BOARD_MODEL == BOARD_MESHADVENTURER
|
||||
#define DISP_RST -1
|
||||
#define DISP_ADDR 0x3C
|
||||
#define SCL_OLED 22
|
||||
#define SDA_OLED 21
|
||||
#elif BOARD_MODEL == BOARD_DIY_V1
|
||||
#define DISP_RST -1
|
||||
#define DISP_ADDR 0x3C
|
||||
#define SCL_OLED 22
|
||||
#define SDA_OLED 21
|
||||
#elif BOARD_MODEL == BOARD_AETHERNODE
|
||||
#define DISP_RST -1
|
||||
#define DISP_ADDR 0x3C
|
||||
#define SCL_OLED 22
|
||||
#define SDA_OLED 21
|
||||
#elif BOARD_MODEL == BOARD_PROMICRO
|
||||
#define DISP_RST -1
|
||||
#define DISP_ADDR 0x3C
|
||||
#define SCL_OLED 7
|
||||
#define SDA_OLED 8
|
||||
#elif BOARD_MODEL == BOARD_RAK4631
|
||||
// RAK1921/SSD1306
|
||||
#define DISP_RST -1
|
||||
@@ -90,6 +125,12 @@
|
||||
#define SCL_OLED 18
|
||||
#define SDA_OLED 17
|
||||
#define DISP_CUSTOM_ADDR false
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V3
|
||||
#define DISP_RST -1
|
||||
#define DISP_ADDR 0x3D
|
||||
#define SCL_OLED 18
|
||||
#define SDA_OLED 17
|
||||
#define DISP_CUSTOM_ADDR false
|
||||
#elif BOARD_MODEL == BOARD_XIAO_S3
|
||||
#define DISP_RST -1
|
||||
#define DISP_ADDR 0x3C
|
||||
@@ -112,7 +153,7 @@
|
||||
ST7789Spi display(&SPI1, DISPLAY_RST, DISPLAY_DC, DISPLAY_CS);
|
||||
#define SSD1306_WHITE ST77XX_WHITE
|
||||
#define SSD1306_BLACK ST77XX_BLACK
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V1 || BOARD_MODEL == BOARD_TBEAM_S_V3
|
||||
Adafruit_SH1106G display = Adafruit_SH1106G(128, 64, &Wire, -1);
|
||||
#define SSD1306_WHITE SH110X_WHITE
|
||||
#define SSD1306_BLACK SH110X_BLACK
|
||||
@@ -225,7 +266,7 @@ void update_area_positions() {
|
||||
}
|
||||
|
||||
uint8_t display_contrast = 0x00;
|
||||
#if BOARD_MODEL == BOARD_TBEAM_S_V1
|
||||
#if BOARD_MODEL == BOARD_TBEAM_S_V1 || BOARD_MODEL == BOARD_TBEAM_S_V3
|
||||
void set_contrast(Adafruit_SH1106G *display, uint8_t value) {
|
||||
}
|
||||
#elif BOARD_MODEL == BOARD_HELTEC_T114
|
||||
@@ -311,6 +352,12 @@ bool display_init() {
|
||||
#elif BOARD_MODEL == BOARD_HELTEC_T114
|
||||
pinMode(PIN_T114_TFT_EN, OUTPUT);
|
||||
digitalWrite(PIN_T114_TFT_EN, LOW);
|
||||
#elif BOARD_MODEL == BOARD_MESHADVENTURER_S3
|
||||
Wire.setPins(SDA_OLED, SCL_OLED);
|
||||
Wire.begin();
|
||||
#elif BOARD_MODEL == BOARD_PROMICRO
|
||||
Wire.setPins(SDA_OLED, SCL_OLED);
|
||||
Wire.begin();
|
||||
#elif BOARD_MODEL == BOARD_TECHO
|
||||
display.init(0, true, 10, false, displaySPI, SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
display.setPartialWindow(0, 0, DISP_W, DISP_H);
|
||||
@@ -319,7 +366,7 @@ bool display_init() {
|
||||
pinMode(pin_backlight, OUTPUT);
|
||||
analogWrite(pin_backlight, 0);
|
||||
#endif
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V1 || BOARD_MODEL == BOARD_TBEAM_S_V3
|
||||
Wire.begin(SDA_OLED, SCL_OLED);
|
||||
#elif BOARD_MODEL == BOARD_XIAO_S3
|
||||
Wire.begin(SDA_OLED, SCL_OLED);
|
||||
@@ -376,7 +423,7 @@ bool display_init() {
|
||||
// set white as default pixel colour for Heltec T114
|
||||
display.setRGB(COLOR565(0xFF, 0xFF, 0xFF));
|
||||
if (false) {
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V1 || BOARD_MODEL == BOARD_TBEAM_S_V3
|
||||
if (!display.begin(display_address, true)) {
|
||||
#else
|
||||
if (!display.begin(SSD1306_SWITCHCAPVCC, display_address)) {
|
||||
@@ -410,7 +457,7 @@ bool display_init() {
|
||||
#elif BOARD_MODEL == BOARD_TBEAM
|
||||
disp_mode = DISP_MODE_LANDSCAPE;
|
||||
display.setRotation(0);
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V1 || BOARD_MODEL == BOARD_TBEAM_S_V3
|
||||
disp_mode = DISP_MODE_PORTRAIT;
|
||||
display.setRotation(1);
|
||||
#elif BOARD_MODEL == BOARD_HELTEC32_V2
|
||||
@@ -434,6 +481,21 @@ bool display_init() {
|
||||
#elif BOARD_MODEL == BOARD_TECHO
|
||||
disp_mode = DISP_MODE_PORTRAIT;
|
||||
display.setRotation(3);
|
||||
#elif BOARD_MODEL == BOARD_MESHADVENTURER_S3
|
||||
disp_mode = DISP_MODE_LANDSCAPE;
|
||||
display.setRotation(0);
|
||||
#elif BOARD_MODEL == BOARD_MESHADVENTURER
|
||||
disp_mode = DISP_MODE_LANDSCAPE;
|
||||
display.setRotation(0);
|
||||
#elif BOARD_MODEL == BOARD_DIY_V1
|
||||
disp_mode = DISP_MODE_LANDSCAPE;
|
||||
display.setRotation(0);
|
||||
#elif BOARD_MODEL == BOARD_AETHERNODE
|
||||
disp_mode = DISP_MODE_LANDSCAPE;
|
||||
display.setRotation(0);
|
||||
#elif BOARD_MODEL == BOARD_PROMICRO
|
||||
disp_mode = DISP_MODE_LANDSCAPE;
|
||||
display.setRotation(0);
|
||||
#else
|
||||
disp_mode = DISP_MODE_PORTRAIT;
|
||||
display.setRotation(3);
|
||||
@@ -1071,6 +1133,7 @@ void update_display(bool blank = false) {
|
||||
#if BOARD_MODEL == BOARD_HELTEC_T114
|
||||
display.clear();
|
||||
display.display();
|
||||
digitalWrite(PIN_T114_TFT_BLGT, HIGH);
|
||||
#elif BOARD_MODEL != BOARD_TDECK && BOARD_MODEL != BOARD_TECHO
|
||||
display.clearDisplay();
|
||||
display.display();
|
||||
@@ -1091,6 +1154,7 @@ void update_display(bool blank = false) {
|
||||
|
||||
#if BOARD_MODEL == BOARD_HELTEC_T114
|
||||
display.clear();
|
||||
digitalWrite(PIN_T114_TFT_BLGT, LOW);
|
||||
#elif BOARD_MODEL != BOARD_TDECK && BOARD_MODEL != BOARD_TECHO
|
||||
display.clearDisplay();
|
||||
#endif
|
||||
@@ -1128,6 +1192,9 @@ void update_display(bool blank = false) {
|
||||
|
||||
void display_unblank() {
|
||||
last_unblank_event = millis();
|
||||
#if BOARD_MODEL == BOARD_HELTEC_T114
|
||||
digitalWrite(PIN_T114_TFT_BLGT, LOW);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ext_fb_enable() {
|
||||
|
||||
245
Makefile
245
Makefile
@@ -17,7 +17,7 @@
|
||||
ARDUINO_ESP_CORE_VER = 2.0.17
|
||||
|
||||
# Version 3.2.0 of the Arduino ESP core is based on ESP-IDF v5.4.1
|
||||
# ARDUINO_ESP_CORE_VER = 3.2.0
|
||||
#ARDUINO_ESP_CORE_VER = 3.3.7
|
||||
|
||||
all: release
|
||||
|
||||
@@ -30,7 +30,6 @@ prep: prep-avr prep-esp32 prep-samd
|
||||
prep-avr:
|
||||
arduino-cli core update-index --config-file arduino-cli.yaml
|
||||
arduino-cli core install arduino:avr --config-file arduino-cli.yaml
|
||||
arduino-cli core install unsignedio:avr --config-file arduino-cli.yaml
|
||||
|
||||
prep-esp32:
|
||||
arduino-cli core update-index --config-file arduino-cli.yaml
|
||||
@@ -51,10 +50,12 @@ prep-nrf:
|
||||
arduino-cli core install rakwireless:nrf52 --config-file arduino-cli.yaml
|
||||
arduino-cli core install Heltec_nRF52:Heltec_nRF52 --config-file arduino-cli.yaml
|
||||
arduino-cli core install adafruit:nrf52 --config-file arduino-cli.yaml
|
||||
arduino-cli core install "promicro:nrf52" --config-file arduino-cli.yaml
|
||||
sed -i.bak 's/nicenanov2\.build\.ldscript=nrf52840_s140_v7\.ld/nicenanov2.build.ldscript=nrf52840_s140_v6.ld/' ~/.arduino15/packages/promicro/hardware/nrf52/1.0.2/boards.txt
|
||||
arduino-cli lib install "GxEPD2"
|
||||
arduino-cli config set library.enable_unsafe_install true
|
||||
arduino-cli lib install --git-url https://github.com/liamcottle/esp8266-oled-ssd1306#e16cee124fe26490cb14880c679321ad8ac89c95
|
||||
pip install adafruit-nrfutil --upgrade
|
||||
pip install adafruit-nrfutil --upgrade --break-system-packages
|
||||
|
||||
console-site:
|
||||
make -C Console clean site
|
||||
@@ -74,29 +75,29 @@ check_bt_buffers:
|
||||
firmware:
|
||||
arduino-cli compile --log --fqbn unsignedio:avr:rnode
|
||||
|
||||
firmware-mega2560:
|
||||
arduino-cli compile --log --fqbn arduino:avr:mega
|
||||
firmware-aethernode: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:esp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x35\""
|
||||
|
||||
firmware-tbeam: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:t-beam -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\""
|
||||
firmware-diy_v1: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:esp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0xF6\""
|
||||
|
||||
firmware-tbeam_sx126x: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:t-beam -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DMODEM=0x03\""
|
||||
firmware-featheresp32: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:featheresp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x34\""
|
||||
|
||||
firmware-t3s3:
|
||||
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DMODEM=0x03\""
|
||||
firmware-heltec32_v2: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:heltec_wifi_lora_32_V2 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x38\""
|
||||
|
||||
firmware-t3s3_sx127x:
|
||||
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DMODEM=0x01\""
|
||||
firmware-heltec32_v2_extled: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:heltec_wifi_lora_32_V2 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x38\" \"-DEXTERNAL_LEDS=true\""
|
||||
|
||||
firmware-t3s3_sx1280_pa:
|
||||
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DMODEM=0x04\""
|
||||
firmware-heltec32_v3:
|
||||
arduino-cli compile --log --fqbn esp32:esp32:heltec_wifi_lora_32_V3 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3A\""
|
||||
|
||||
firmware-tdeck:
|
||||
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3B\""
|
||||
firmware-heltec32_v4:
|
||||
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3F\""
|
||||
|
||||
firmware-tbeam_supreme:
|
||||
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=-DBOARD_MODEL=0x3D"
|
||||
firmware-heltec_t114:
|
||||
arduino-cli compile --log --fqbn Heltec_nRF52:Heltec_nRF52:HT-n5262 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3C\""
|
||||
|
||||
firmware-lora32_v10: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x39\""
|
||||
@@ -116,17 +117,17 @@ firmware-lora32_v21_extled: check_bt_buffers
|
||||
firmware-lora32_v21_tcxo: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\" \"-DENABLE_TCXO=true\""
|
||||
|
||||
firmware-heltec32_v2: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:heltec_wifi_lora_32_V2 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x38\""
|
||||
firmware-meshadventurer: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:esp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0xF4\""
|
||||
|
||||
firmware-heltec32_v2_extled: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:heltec_wifi_lora_32_V2 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x38\" \"-DEXTERNAL_LEDS=true\""
|
||||
firmware-meshpoe_s3: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0xF1\""
|
||||
|
||||
firmware-heltec32_v3:
|
||||
arduino-cli compile --log --fqbn esp32:esp32:heltec_wifi_lora_32_V3 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3A\""
|
||||
firmware-meshadventurer_s3: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0xF2\""
|
||||
|
||||
firmware-heltec32_v4:
|
||||
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3F\""
|
||||
firmware-meshadventurer_s3_nocdc: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0xF2\""
|
||||
|
||||
firmware-rnode_ng_20: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x40\""
|
||||
@@ -134,17 +135,35 @@ firmware-rnode_ng_20: check_bt_buffers
|
||||
firmware-rnode_ng_21: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x41\""
|
||||
|
||||
firmware-featheresp32: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:featheresp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x34\""
|
||||
|
||||
firmware-genericesp32: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:esp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x35\""
|
||||
firmware-promicro:
|
||||
arduino-cli compile --log --fqbn promicro:nrf52:nicenanov2:softdevice=s140v6 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0xF5\""
|
||||
|
||||
firmware-rak4631:
|
||||
arduino-cli compile --log --fqbn rakwireless:nrf52:WisCoreRAK4631Board -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\""
|
||||
|
||||
firmware-heltec_t114:
|
||||
arduino-cli compile --log --fqbn Heltec_nRF52:Heltec_nRF52:HT-n5262 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3C\""
|
||||
firmware-t3s3:
|
||||
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DMODEM=0x03\""
|
||||
|
||||
firmware-t3s3_sx127x:
|
||||
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DMODEM=0x01\""
|
||||
|
||||
firmware-t3s3_sx1280_pa:
|
||||
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DMODEM=0x04\""
|
||||
|
||||
firmware-tbeam: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:t-beam -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\""
|
||||
|
||||
firmware-tbeam_supreme:
|
||||
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=-DBOARD_MODEL=0x3D"
|
||||
|
||||
firmware-tbeam_supreme_v3:
|
||||
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=-DBOARD_MODEL=0x43"
|
||||
|
||||
firmware-tbeam_sx126x: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:t-beam -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DMODEM=0x03\""
|
||||
|
||||
firmware-tdeck:
|
||||
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3B\""
|
||||
|
||||
firmware-techo:
|
||||
arduino-cli compile --log --fqbn adafruit:nrf52:pca10056 -e --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\""
|
||||
@@ -152,9 +171,64 @@ firmware-techo:
|
||||
firmware-xiao_s3:
|
||||
arduino-cli compile --log --fqbn "esp32:esp32:XIAO_ESP32S3" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3E\""
|
||||
|
||||
firmware-genericesp32: check_bt_buffers
|
||||
arduino-cli compile --log --fqbn esp32:esp32:esp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x35\""
|
||||
|
||||
firmware-mega2560:
|
||||
arduino-cli compile --log --fqbn arduino:avr:mega
|
||||
|
||||
upload:
|
||||
arduino-cli upload -p /dev/ttyUSB0 --fqbn unsignedio:avr:rnode
|
||||
|
||||
upload-genericesp32:
|
||||
arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:esp32
|
||||
@sleep 1
|
||||
rnodeconf /dev/ttyUSB0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32/RNode_Firmware.ino.bin)
|
||||
@sleep 3
|
||||
python ./Release/esptool/esptool.py --chip esp32 --port /dev/ttyACM0 --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
|
||||
|
||||
upload-meshpoe_s3:
|
||||
arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:esp32s3
|
||||
# @sleep 1
|
||||
# rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin)
|
||||
@sleep 3
|
||||
python ./Release/esptool/esptool.py --chip esp32s3 --port /dev/ttyACM0 --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
|
||||
|
||||
upload-meshadventurer_s3:
|
||||
arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:esp32s3
|
||||
# @sleep 1
|
||||
# rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin)
|
||||
@sleep 3
|
||||
python ./Release/esptool/esptool.py --chip esp32s3 --port /dev/ttyACM0 --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
|
||||
|
||||
upload-meshadventurer_s3_usb:
|
||||
arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:esp32s3
|
||||
# @sleep 1
|
||||
# rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin)
|
||||
@sleep 3
|
||||
python ./Release/esptool/esptool.py --chip esp32s3 --port /dev/ttyUSB0 --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
|
||||
|
||||
upload-meshadventurer:
|
||||
arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:esp32
|
||||
@sleep 1
|
||||
rnodeconf /dev/ttyUSB0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32/RNode_Firmware.ino.bin)
|
||||
@sleep 3
|
||||
python ./Release/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --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
|
||||
|
||||
upload-diy_v1:
|
||||
arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:esp32
|
||||
@sleep 1
|
||||
rnodeconf /dev/ttyUSB0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32/RNode_Firmware.ino.bin)
|
||||
@sleep 3
|
||||
python ./Release/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --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
|
||||
|
||||
upload-aethernode:
|
||||
arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:esp32
|
||||
@sleep 1
|
||||
rnodeconf /dev/ttyUSB0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32/RNode_Firmware.ino.bin)
|
||||
@sleep 3
|
||||
python ./Release/esptool/esptool.py --chip esp32 --port /dev/ttyACM0 --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
|
||||
|
||||
upload-mega2560:
|
||||
arduino-cli upload -p /dev/ttyACM0 --fqbn arduino:avr:mega
|
||||
|
||||
@@ -198,35 +272,42 @@ upload-heltec32_v2:
|
||||
@sleep 1
|
||||
rnodeconf /dev/ttyUSB0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware.ino.bin)
|
||||
@sleep 3
|
||||
python ./Release/esptool/esptool.py --chip esp32 --port /dev/ttyUSB1 --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
|
||||
python ./Release/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --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
|
||||
|
||||
upload-heltec32_v3:
|
||||
arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:heltec_wifi_lora_32_V3
|
||||
@sleep 1
|
||||
rnodeconf /dev/ttyUSB0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware.ino.bin)
|
||||
@sleep 3
|
||||
python ./Release/esptool/esptool.py --chip esp32-s3 --port /dev/ttyUSB0 --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
|
||||
python ./Release/esptool/esptool.py --chip esp32s3 --port /dev/ttyUSB0 --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
|
||||
|
||||
upload-heltec32_v4:
|
||||
arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:esp32s3
|
||||
@sleep 1
|
||||
rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin)
|
||||
@sleep 3
|
||||
python ./Release/esptool/esptool.py --chip esp32-s3 --port /dev/ttyACM0 --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
|
||||
python ./Release/esptool/esptool.py --chip esp32s3 --port /dev/ttyACM0 --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
|
||||
|
||||
upload-tdeck:
|
||||
arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:esp32s3
|
||||
@sleep 1
|
||||
rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin)
|
||||
@sleep 3
|
||||
python ./Release/esptool/esptool.py --chip esp32-s3 --port /dev/ttyACM0 --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
|
||||
python ./Release/esptool/esptool.py --chip esp32s3 --port /dev/ttyACM0 --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
|
||||
|
||||
upload-tbeam_supreme:
|
||||
arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:esp32s3
|
||||
@sleep 1
|
||||
rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin)
|
||||
@sleep 3
|
||||
python ./Release/esptool/esptool.py --chip esp32-s3 --port /dev/ttyACM0 --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
|
||||
python ./Release/esptool/esptool.py --chip esp32s3 --port /dev/ttyACM0 --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
|
||||
|
||||
upload-tbeam_supreme_v3:
|
||||
arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:esp32s3
|
||||
@sleep 1
|
||||
rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin)
|
||||
@sleep 3
|
||||
python ./Release/esptool/esptool.py --chip esp32s3 --port /dev/ttyACM0 --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
|
||||
|
||||
upload-rnode_ng_20:
|
||||
arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:ttgo-lora32
|
||||
@@ -266,6 +347,11 @@ upload-heltec_t114:
|
||||
@sleep 1
|
||||
rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes from_device /dev/ttyACM0)
|
||||
|
||||
upload-promicro:
|
||||
arduino-cli upload -p /dev/ttyACM0 --fqbn promicro:nrf52:nicenanov2:softdevice=s140v6
|
||||
@sleep 6
|
||||
rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes from_device /dev/ttyACM0)
|
||||
|
||||
upload-techo:
|
||||
arduino-cli upload -p /dev/ttyACM0 --fqbn adafruit:nrf52:pca10056
|
||||
@sleep 6
|
||||
@@ -280,7 +366,7 @@ upload-xiao_s3:
|
||||
|
||||
release: release-all
|
||||
|
||||
release-all: console-site spiffs-image release-tbeam release-tbeam_sx1262 release-lora32_v10 release-lora32_v20 release-lora32_v21 release-lora32_v10_extled release-lora32_v20_extled release-lora32_v21_extled release-lora32_v21_tcxo release-featheresp32 release-genericesp32 release-heltec32_v2 release-heltec32_v3 release-heltec32_v4 release-heltec32_v2_extled release-heltec_t114 release-techo release-rnode_ng_20 release-rnode_ng_21 release-t3s3 release-t3s3_sx127x release-t3s3_sx1280_pa release-tdeck release-tbeam_supreme release-rak4631 release-xiao_s3 release-hashes
|
||||
release-all: console-site spiffs-image release-tbeam release-tbeam_sx1262 release-lora32_v10 release-lora32_v20 release-lora32_v21 release-lora32_v10_extled release-lora32_v20_extled release-lora32_v21_extled release-lora32_v21_tcxo release-featheresp32 release-genericesp32 release-heltec32_v2 release-heltec32_v3 release-heltec32_v4 release-heltec32_v2_extled release-heltec_t114 release-techo release-rnode_ng_20 release-rnode_ng_21 release-t3s3 release-t3s3_sx127x release-t3s3_sx1280_pa release-tdeck release-tbeam_supreme release-tbeam_supreme_v3 release-rak4631 release-xiao_s3 release-hashes
|
||||
|
||||
release-hashes:
|
||||
python ./release_hashes.py > ./Release/release.json
|
||||
@@ -470,6 +556,15 @@ release-tbeam_supreme:
|
||||
zip --junk-paths ./Release/rnode_firmware_tbeam_supreme.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_tbeam_supreme.boot_app0 build/rnode_firmware_tbeam_supreme.bin build/rnode_firmware_tbeam_supreme.bootloader build/rnode_firmware_tbeam_supreme.partitions
|
||||
rm -r build
|
||||
|
||||
release-tbeam_supreme_v3:
|
||||
arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x43\""
|
||||
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_tbeam_supreme_v3.boot_app0
|
||||
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin build/rnode_firmware_tbeam_supreme_v3.bin
|
||||
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_tbeam_supreme_v3.bootloader
|
||||
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_tbeam_supreme_v3.partitions
|
||||
zip --junk-paths ./Release/rnode_firmware_tbeam_supreme_v3.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_tbeam_supreme_v3.boot_app0 build/rnode_firmware_tbeam_supreme_v3.bin build/rnode_firmware_tbeam_supreme_v3.bootloader build/rnode_firmware_tbeam_supreme_v3.partitions
|
||||
rm -r build
|
||||
|
||||
release-featheresp32: check_bt_buffers
|
||||
arduino-cli compile --fqbn esp32:esp32:featheresp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x34\""
|
||||
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_featheresp32.boot_app0
|
||||
@@ -488,6 +583,71 @@ release-genericesp32: check_bt_buffers
|
||||
zip --junk-paths ./Release/rnode_firmware_esp32_generic.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_esp32_generic.boot_app0 build/rnode_firmware_esp32_generic.bin build/rnode_firmware_esp32_generic.bootloader build/rnode_firmware_esp32_generic.partitions
|
||||
rm -r build
|
||||
|
||||
release-meshpoe_s3: check_bt_buffers
|
||||
arduino-cli compile --fqbn esp32:esp32:esp32s3 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0xF1\""
|
||||
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_meshpoe_s3.boot_app0
|
||||
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin build/rnode_firmware_meshpoe_s3.bin
|
||||
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_meshpoe_s3.bootloader
|
||||
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_meshpoe_s3.partitions
|
||||
zip --junk-paths ./Release/rnode_firmware_meshpoe_s3.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_meshpoe_s3.boot_app0 build/rnode_firmware_meshpoe_s3.bin build/rnode_firmware_meshpoe_s3.bootloader build/rnode_firmware_meshpoe_s3.partitions
|
||||
rm -r build
|
||||
|
||||
release-meshadventurer_s3: check_bt_buffers
|
||||
arduino-cli compile --fqbn esp32:esp32:esp32s3 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0xF2\""
|
||||
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_meshadventurer_s3.boot_app0
|
||||
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin build/rnode_firmware_meshadventurer_s3.bin
|
||||
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_meshadventurer_s3.bootloader
|
||||
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_meshadventurer_s3.partitions
|
||||
zip --junk-paths ./Release/rnode_firmware_meshadventurer_s3.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_meshadventurer_s3.boot_app0 build/rnode_firmware_meshadventurer_s3.bin build/rnode_firmware_meshadventurer_s3.bootloader build/rnode_firmware_meshadventurer_s3.partitions
|
||||
rm -r build
|
||||
|
||||
release-meshadventurer: check_bt_buffers
|
||||
arduino-cli compile --fqbn esp32:esp32:esp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0xF4\""
|
||||
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_meshadventurer.boot_app0
|
||||
cp build/esp32.esp32.esp32/RNode_Firmware.ino.bin build/rnode_firmware_meshadventurer.bin
|
||||
cp build/esp32.esp32.esp32/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_meshadventurer.bootloader
|
||||
cp build/esp32.esp32.esp32/RNode_Firmware.ino.partitions.bin build/rnode_firmware_meshadventurer.partitions
|
||||
zip --junk-paths ./Release/rnode_firmware_meshadventurer.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_meshadventurer.boot_app0 build/rnode_firmware_meshadventurer.bin build/rnode_firmware_meshadventurer.bootloader build/rnode_firmware_meshadventurer.partitions
|
||||
rm -r build
|
||||
|
||||
release-diy_v1: check_bt_buffers
|
||||
arduino-cli compile --fqbn esp32:esp32:esp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0xF6\""
|
||||
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_diy_v1.boot_app0
|
||||
cp build/esp32.esp32.esp32/RNode_Firmware.ino.bin build/rnode_firmware_diy_v1.bin
|
||||
cp build/esp32.esp32.esp32/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_diy_v1.bootloader
|
||||
cp build/esp32.esp32.esp32/RNode_Firmware.ino.partitions.bin build/rnode_firmware_diy_v1.partitions
|
||||
zip --junk-paths ./Release/rnode_firmware_diy_v1.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_diy_v1.boot_app0 build/rnode_firmware_diy_v1.bin build/rnode_firmware_diy_v1.bootloader build/rnode_firmware_diy_v1.partitions
|
||||
rm -r build
|
||||
|
||||
release-merged-diy_v1: check_bt_buffers
|
||||
arduino-cli compile --fqbn esp32:esp32:esp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0xF6\""
|
||||
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_diy_v1.boot_app0
|
||||
cp build/esp32.esp32.esp32/RNode_Firmware.ino.bin build/rnode_firmware_diy_v1.bin
|
||||
cp build/esp32.esp32.esp32/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_diy_v1.bootloader
|
||||
cp build/esp32.esp32.esp32/RNode_Firmware.ino.partitions.bin build/rnode_firmware_diy_v1.partitions
|
||||
python ./Release/esptool/esptool.py --chip esp32 merge_bin -o build/rnode_firmware_diy_v1.merged.bin --flash_mode dio --flash_freq 40m --flash_size 4MB 0x1000 build/rnode_firmware_diy_v1.bootloader 0x8000 build/rnode_firmware_diy_v1.partitions 0xe000 build/rnode_firmware_diy_v1.boot_app0 0x10000 build/rnode_firmware_diy_v1.bin
|
||||
cp build/rnode_firmware_diy_v1.merged.bin ./Release/rnode_firmware_diy_v1.merged.bin
|
||||
rm -r build
|
||||
|
||||
release-merged-meshadventurer: check_bt_buffers
|
||||
arduino-cli compile --fqbn esp32:esp32:esp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0xF4\""
|
||||
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_meshadventurer.boot_app0
|
||||
cp build/esp32.esp32.esp32/RNode_Firmware.ino.bin build/rnode_firmware_meshadventurer.bin
|
||||
cp build/esp32.esp32.esp32/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_meshadventurer.bootloader
|
||||
cp build/esp32.esp32.esp32/RNode_Firmware.ino.partitions.bin build/rnode_firmware_meshadventurer.partitions
|
||||
python ./Release/esptool/esptool.py --chip esp32 merge_bin -o build/rnode_firmware_meshadventurer.merged.bin --flash_mode dio --flash_freq 40m --flash_size 4MB 0x1000 build/rnode_firmware_meshadventurer.bootloader 0x8000 build/rnode_firmware_meshadventurer.partitions 0xe000 build/rnode_firmware_meshadventurer.boot_app0 0x10000 build/rnode_firmware_meshadventurer.bin
|
||||
cp build/rnode_firmware_meshadventurer.merged.bin ./Release/rnode_firmware_meshadventurer.merged.bin
|
||||
rm -r build
|
||||
|
||||
release-aethernode: check_bt_buffers
|
||||
arduino-cli compile --fqbn esp32:esp32:esp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x35\""
|
||||
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_aethernode.boot_app0
|
||||
cp build/esp32.esp32.esp32/RNode_Firmware.ino.bin build/rnode_firmware_aethernode.bin
|
||||
cp build/esp32.esp32.esp32/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_aethernode.bootloader
|
||||
cp build/esp32.esp32.esp32/RNode_Firmware.ino.partitions.bin build/rnode_firmware_aethernode.partitions
|
||||
zip --junk-paths ./Release/rnode_firmware_aethernode.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_aethernode.boot_app0 build/rnode_firmware_aethernode.bin build/rnode_firmware_aethernode.bootloader build/rnode_firmware_aethernode.partitions
|
||||
rm -r build
|
||||
|
||||
release-mega2560:
|
||||
arduino-cli compile --fqbn arduino:avr:mega -e --build-property "compiler.cpp.extra_flags=\"-DMODEM=0x01\""
|
||||
cp build/arduino.avr.mega/RNode_Firmware.ino.hex Release/rnode_firmware_m2560.hex
|
||||
@@ -503,6 +663,11 @@ release-heltec_t114:
|
||||
cp build/Heltec_nRF52.Heltec_nRF52.HT-n5262/RNode_Firmware.ino.hex build/rnode_firmware_heltec_t114.hex
|
||||
adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_heltec_t114.hex Release/rnode_firmware_heltec_t114.zip
|
||||
|
||||
release-promicro:
|
||||
arduino-cli compile --log --fqbn promicro:nrf52:nicenanov2:softdevice=s140v6 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0xF5\""
|
||||
cp build/promicro.nrf52.nicenanov2/RNode_Firmware.ino.hex build/rnode_firmware_promicro.hex
|
||||
adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_promicro.hex Release/rnode_firmware_promicro.zip
|
||||
|
||||
release-techo:
|
||||
arduino-cli compile --log --fqbn adafruit:nrf52:pca10056 -e --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\""
|
||||
cp build/adafruit.nrf52.pca10056/RNode_Firmware.ino.hex build/rnode_firmware_techo.hex
|
||||
|
||||
31
Power.h
31
Power.h
@@ -19,12 +19,12 @@
|
||||
bool pmu_temp_sensor_ready = false;
|
||||
float pmu_temperature = PMU_TEMP_MIN-1;
|
||||
|
||||
#if BOARD_MODEL == BOARD_TBEAM || BOARD_MODEL == BOARD_TBEAM_S_V1
|
||||
#if BOARD_MODEL == BOARD_TBEAM || BOARD_MODEL == BOARD_TBEAM_S_V1 || BOARD_MODEL == BOARD_TBEAM_S_V3
|
||||
#include <XPowersLib.h>
|
||||
XPowersLibInterface* PMU = NULL;
|
||||
|
||||
#ifndef PMU_WIRE_PORT
|
||||
#if BOARD_MODEL == BOARD_TBEAM_S_V1
|
||||
#if BOARD_MODEL == BOARD_TBEAM_S_V1 || BOARD_MODEL == BOARD_TBEAM_S_V3
|
||||
#define PMU_WIRE_PORT Wire1
|
||||
#else
|
||||
#define PMU_WIRE_PORT Wire
|
||||
@@ -164,6 +164,22 @@ float pmu_temperature = PMU_TEMP_MIN-1;
|
||||
bool bat_voltage_dropping = false;
|
||||
float bat_delay_v = 0;
|
||||
float bat_state_change_v = 0;
|
||||
#elif BOARD_MODEL == BOARD_PROMICRO
|
||||
#define BAT_V_MIN 3.15
|
||||
#define BAT_V_MAX 4.165
|
||||
#define BAT_V_CHG 4.48
|
||||
#define BAT_V_FLOAT 4.33
|
||||
#define BAT_SAMPLES 7
|
||||
const uint8_t pin_vbat = 17;
|
||||
float bat_p_samples[BAT_SAMPLES];
|
||||
float bat_v_samples[BAT_SAMPLES];
|
||||
uint8_t bat_samples_count = 0;
|
||||
int bat_discharging_samples = 0;
|
||||
int bat_charging_samples = 0;
|
||||
int bat_charged_samples = 0;
|
||||
bool bat_voltage_dropping = false;
|
||||
float bat_delay_v = 0;
|
||||
float bat_state_change_v = 0;
|
||||
#elif BOARD_MODEL == BOARD_TECHO
|
||||
#define BAT_V_MIN 3.15
|
||||
#define BAT_V_MAX 4.16
|
||||
@@ -202,7 +218,7 @@ void measure_temperature() {
|
||||
}
|
||||
|
||||
void measure_battery() {
|
||||
#if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_HELTEC32_V4 || BOARD_MODEL == BOARD_TDECK || BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_HELTEC_T114 || BOARD_MODEL == BOARD_TECHO
|
||||
#if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_HELTEC32_V4 || BOARD_MODEL == BOARD_TDECK || BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_HELTEC_T114 || BOARD_MODEL == BOARD_PROMICRO || BOARD_MODEL == BOARD_TECHO
|
||||
battery_installed = true;
|
||||
#if BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_HELTEC32_V4
|
||||
battery_indeterminate = false;
|
||||
@@ -218,6 +234,8 @@ void measure_battery() {
|
||||
float battery_measurement = (float)(analogRead(pin_vbat)) / 4095.0*6.7828;
|
||||
#elif BOARD_MODEL == BOARD_HELTEC_T114
|
||||
float battery_measurement = (float)(analogRead(pin_vbat)) * 0.017165;
|
||||
#elif BOARD_MODEL == BOARD_PROMICRO
|
||||
float battery_measurement = (float)(analogRead(pin_vbat)) * 0.006263;
|
||||
#elif BOARD_MODEL == BOARD_TECHO
|
||||
float battery_measurement = (float)(analogRead(pin_vbat)) * 0.007067;
|
||||
#else
|
||||
@@ -225,6 +243,7 @@ void measure_battery() {
|
||||
#endif
|
||||
|
||||
bat_v_samples[bat_samples_count%BAT_SAMPLES] = battery_measurement;
|
||||
|
||||
bat_p_samples[bat_samples_count%BAT_SAMPLES] = ((battery_voltage-BAT_V_MIN) / (BAT_V_MAX-BAT_V_MIN))*100.0;
|
||||
|
||||
bat_samples_count++;
|
||||
@@ -308,7 +327,7 @@ void measure_battery() {
|
||||
// }
|
||||
}
|
||||
|
||||
#elif BOARD_MODEL == BOARD_TBEAM || BOARD_MODEL == BOARD_TBEAM_S_V1
|
||||
#elif BOARD_MODEL == BOARD_TBEAM || BOARD_MODEL == BOARD_TBEAM_S_V1 || BOARD_MODEL == BOARD_TBEAM_S_V3
|
||||
if (PMU) {
|
||||
float discharge_current = 0;
|
||||
float charge_current = 0;
|
||||
@@ -411,7 +430,7 @@ bool init_pmu() {
|
||||
pmu_temp_sensor_ready = true;
|
||||
#endif
|
||||
|
||||
#if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_TDECK || BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_TECHO
|
||||
#if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_TDECK || BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_TECHO || BOARD_MODEL == BOARD_PROMICRO
|
||||
pinMode(pin_vbat, INPUT);
|
||||
return true;
|
||||
#elif BOARD_MODEL == BOARD_HELTEC32_V3
|
||||
@@ -564,7 +583,7 @@ bool init_pmu() {
|
||||
PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S);
|
||||
|
||||
return true;
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V1 || BOARD_MODEL == BOARD_TBEAM_S_V3
|
||||
Wire1.begin(I2C_SDA, I2C_SCL);
|
||||
|
||||
if (!PMU) {
|
||||
|
||||
156
README.md
156
README.md
@@ -1,150 +1,20 @@
|
||||
*This repository is [a public mirror](./MIRROR.md). All development is happening elsewhere.*
|
||||
|
||||
***Important!** This repository is currently functioning as a stable reference for the default RNode Firmware, and only receives bugfix and security updates. Further development, new features and expanded board support is now happening at the [RNode Firmware Community Edition](https://github.com/liberatedsystems/RNode_Firmware_CE) repository, and is maintained by [Liberated Embedded Systems](https://github.com/liberatedsystems). Thanks for all contributions so far!*
|
||||
|
||||
# RNode Firmware
|
||||
|
||||
This is the open firmware that powers RNode devices.
|
||||
This is a fork of [RNode_Firmware](https://github.com/markqvist/RNode_Firmware) by Mark Qvist
|
||||
|
||||
An RNode is an open, free and unrestricted digital radio transceiver. It enables anyone to send and receive any kind of data over both short and very long distances. RNodes can be used with many different kinds of programs and systems, but they are especially well suited for use with [Reticulum](https://reticulum.network).
|
||||
As Mark no longer accepts PRs and RNode_Firmware_CE is inactive, it was decided to make a private fork to fix issues and add additional hardware.
|
||||
The fork contains several DIY devices by me and other developers and has a few small tweaks to the firmware like interference thresholds.
|
||||
|
||||
RNode is not a product, and not any *one* specific device in particular. It is a system that is easy to replicate across space and time, that produces highly functional communications tools, which respects user autonomy and empowers individuals and communities to protect their sovereignty, privacy and ability to communicate and exchange data and ideas freely.
|
||||
---
|
||||
|
||||
<img src="Documentation/images/rnv21_bgp.webp" width="100%">
|
||||
## Added devices
|
||||
|
||||
<center><i>An RNode made from readily available and cheap parts, in a durable 3D printed case</i></center><br/><br/>
|
||||
- [Aethernode](https://github.com/ahedproductions/aethernode) by aetherlab LZ1SWE
|
||||
- [MeshAdventurer-S3](https://git.rns.moscow/deuxyeux/MeshAdventurer-S3) by Nickie Deuxyeux
|
||||
- [MeshAdventurer](https://github.com/chrismyers2000/MeshAdventurer) by Frequency Labs
|
||||
- [DIY-V1](https://github.com/NanoVHF/Meshtastic-DIY/) by NanoVHF
|
||||
- [Faketec (ProMicro)](https://github.com/gargomoma/fakeTec_pcb) by gargomoma, ShimonHoranek, lupusworax
|
||||
|
||||
The RNode system is primarily software, which *transforms* different kinds of available hardware devices into functional, physical RNodes, which can then be used to solve a wide range of communications tasks. Such RNodes can be modified and built to suit the specific time, locale and environment they need to exist in.
|
||||
|
||||
## Latest Release
|
||||
|
||||
The latest release, installable through `rnodeconf`, is version `1.82`. You must have at least version `2.4.1` of `rnodeconf` installed to update the RNode Firmware to version `1.82`. Get it by updating the `rns` package to at least version `0.9.4`.
|
||||
|
||||
## A Self-Replicating System
|
||||
|
||||
If you notice the presence of a circularity in the naming of the system as a whole, and the physical devices, it is no coincidence. Every RNode contains the seeds necessary to reproduce the system, the [RNode Bootstrap Console](https://unsigned.io/rnode_bootstrap_console), which is hosted locally on every RNode, and can be activated and accesses at any time - no Internet required.
|
||||
|
||||
The designs, guides and software stored within allows users to create more RNodes, and even to bootstrap entire communications networks, completely independently of existing infrastructure, or in situations where infrastructure has become unreliable or is broken.
|
||||
|
||||
<img src="Documentation/images/126dcfe92fb7.webp" width="100%"/>
|
||||
|
||||
<center><i>Where there is no Internet, RNodes will still communicate</i></center><br/><br/>
|
||||
|
||||
The production of one particular RNode device is not an end, but the potential starting point of a new branch of devices on the tree of the RNode system as a whole.
|
||||
|
||||
This tree fits into the larger biome of Free & Open Communications Systems, which I hope that you - by using communications tools like RNode - will help grow and prosper.
|
||||
|
||||
## One Tool, Many Uses
|
||||
|
||||
The RNode design is meant to flexible and hackable. At it's core, it is a low-power, but extremely long-range digital radio transceiver. Coupled with Reticulum, it provides encrypted and secure communications.
|
||||
|
||||
Depending on configuration, it can be used for local networking purposes, or to send data over very long distances. Once you have an RNode, there is a wide variety of possible uses:
|
||||
|
||||
- As a network adapter for [Reticulum](https://reticulum.network)
|
||||
- Messaging using [Sideband](https://unsigned.io/software/Sideband.html)
|
||||
- Information sharing and communication using [Nomad Network](https://unsigned.io/software/Nomad_Network.html)
|
||||
- LoRa-based [KISS-compatible amateur radio TNC](https://unsigned.io/guides/2020_05_03_using_rnodes_with_amateur_radio_software.html)
|
||||
- LoRa development platform
|
||||
- [Packet sniffer](https://unsigned.io/software/LoRaMon.html) for LoRa networks
|
||||
- Long range [Ethernet and IP network interface](https://unsigned.io/guides/2020_05_27_ethernet-and-ip-over-packet-radio-tncs.html) on Linux
|
||||
- As a general-purpose long-range data radio
|
||||
|
||||
## Types & Performance
|
||||
|
||||
RNodes can be made in many different configurations, and can use many different radio bands, but they will generally operate in the **433 MHz**, **868 MHz**, **915 MHZ** and **2.4 GHz** bands. They will usually offer configurable on-air data speeds between just a **few hundred bits per second**, up to **a couple of megabits per second**. Maximum output power will depend on the transceiver and PA setup used, but will generally lie between **17 dbm** and **27 dBm**.
|
||||
|
||||
The RNode system has been designed to allow reliable systems for basic human communications, over very wide areas, while using very little power, being cheap to build, free to operate, and near impossible to censor.
|
||||
|
||||
While **speeds are lower** than WiFi, typical communication **ranges are many times higher**. Several kilometers can be acheived with usable bitrates, even in urban areas, and over **100 kilometers** can be achieved in line-of-sight conditions.
|
||||
|
||||
## Supported Boards & Devices
|
||||
It's easy to create your own RNodes from one of the supported development boards and devices. If a device or board you want to use is not yet supported, you are welcome to join the effort and help creating a board definition and pin mapping for it!
|
||||
|
||||
<img src="Documentation/images/devboards_1.webp" width="100%"/>
|
||||
|
||||
The RNode Firmware supports the following boards:
|
||||
|
||||
- LilyGO T-Beam v1.1 devices with SX1276/8 LoRa chips
|
||||
- LilyGO T-Beam v1.1 devices with SX1262/8 LoRa chips
|
||||
- LilyGO T-Beam Supreme devices
|
||||
- LilyGO T-Deck devices (currently display is disabled)
|
||||
- LilyGO LoRa32 v1.0 devices
|
||||
- LilyGO LoRa32 v2.0 devices
|
||||
- LilyGO LoRa32 v2.1 devices (with and without TCXO)
|
||||
- LilyGO T3S3 devices with SX1276/8 LoRa chips
|
||||
- LilyGO T3S3 devices with SX1262/8 LoRa chips
|
||||
- LilyGO T3S3 devices with SX1280 LoRa chips
|
||||
- LilyGO T-Echo devices
|
||||
- Heltec LoRa32 v2 devices
|
||||
- Heltec LoRa32 v3 devices
|
||||
- Heltec LoRa32 v4 devices
|
||||
- Heltec T114 devices
|
||||
- RAK4631 devices
|
||||
- SeeedStudio XIAO ESP32S3 devices (with Wio-SX1262)
|
||||
- Homebrew RNodes based on ATmega1284p boards
|
||||
- Homebrew RNodes based on ATmega2560 boards
|
||||
- Homebrew RNodes based on Adafruit Feather ESP32 boards
|
||||
- Homebrew RNodes based on generic ESP32 boards
|
||||
|
||||
## Supported Transceiver Modules
|
||||
The RNode Firmware supports all transceiver modules based on Semtech **SX1276**, **SX1278**, **SX1262**, **SX1268** and **SX1280** chips, that have an **SPI interface** and expose the relevant **DIO** interrupt pins from the chip.
|
||||
|
||||
## Getting Started Fast
|
||||
You can download and flash the firmware to all the supported boards using the [RNode Config Utility](https://github.com/markqvist/rnodeconfigutil). All firmware releases are now handled and installed directly through the `rnodeconf` utility, which is included in the `rns` package. It can be installed via `pip`:
|
||||
|
||||
```
|
||||
# Install rnodeconf via rns package
|
||||
pip install rns --upgrade
|
||||
|
||||
# Install the firmware on a board with the install guide
|
||||
rnodeconf --autoinstall
|
||||
```
|
||||
|
||||
For most of the supported device types, it is also possible to use [Liam Cottle's Web-based RNode Flasher](https://liamcottle.github.io/rnode-flasher/). This option may be easier if you're not familiar with using a command line interface.
|
||||
|
||||
For more detailed instruction and in-depth guides, you can have a look at some of these resources:
|
||||
|
||||
- Create a [basic RNode from readily available development boards](https://unsigned.io/guides/2022_01_25_installing-rnode-firmware-on-supported-devices.html)
|
||||
- Follow a complete build recipe for [making a handheld RNode](https://unsigned.io/guides/2023_01_14_Making_A_Handheld_RNode.html), like the one pictured above
|
||||
- Learn the basics on how to [create and build your own RNode designs](https://unsigned.io/guides/2022_01_26_how-to-make-your-own-rnodes.html) from scratch
|
||||
- Once you've got the hang of it, start building RNodes for your community, or [even for selling them](https://unsigned.io/sell_rnodes.html)
|
||||
|
||||
If you would rather just buy a pre-made unit, you can visit one of the community vendors that produce and sell RNodes:
|
||||
|
||||
- [Liberated Embedded Systems](https://store.liberatedsystems.co.uk/)
|
||||
- [Simply Equipped](https://simplyequipped.com/)
|
||||
|
||||
If you'd like to have your shop added to this list, let me know.
|
||||
|
||||
## Support RNode Development
|
||||
You can help support the continued development of open, free and private communications systems by donating via one of the following channels:
|
||||
|
||||
- Monero:
|
||||
```
|
||||
84FpY1QbxHcgdseePYNmhTHcrgMX4nFfBYtz2GKYToqHVVhJp8Eaw1Z1EedRnKD19b3B8NiLCGVxzKV17UMmmeEsCrPyA5w
|
||||
```
|
||||
- Bitcoin
|
||||
```
|
||||
bc1pgqgu8h8xvj4jtafslq396v7ju7hkgymyrzyqft4llfslz5vp99psqfk3a6
|
||||
```
|
||||
- Ethereum
|
||||
```
|
||||
0x91C421DdfB8a30a49A71d63447ddb54cEBe3465E
|
||||
```
|
||||
- Liberapay: https://liberapay.com/Reticulum/
|
||||
|
||||
- Ko-Fi: https://ko-fi.com/markqvist
|
||||
|
||||
|
||||
## License & Use
|
||||
The RNode Firmware is Copyright © 2024 Mark Qvist / [unsigned.io](https://unsigned.io), and is made available under the **GNU General Public License v3.0**. The source code includes an SX1276 driver that is released under MIT License, and Copyright © 2018 Sandeep Mistry / Mark Qvist.
|
||||
|
||||
You can obtain the source code from [git.unsigned.io](https://git.unsigned.io/markqvist/RNode_Firmware) or [GitHub](https://github.com/markqvist/rnode_firmware).
|
||||
|
||||
Every RNode also includes an internal copy of it's own firmware source code, that can be downloaded through the [RNode Bootstrap Console](https://unsigned.io/rnode_bootstrap_console), by putting the RNode into Console Mode (which can be activated by pressing the reset button two times within two seconds).
|
||||
|
||||
The RNode Ecosystem is free and non-proprietary, and actively seeks to distribute it's ownership and control. If you want to build RNodes for commercial purposes, including selling them, you must do so adhering to the Open Source licenses that the various parts of the RNode project is released under, and under your own responsibility.
|
||||
|
||||
If you distribute or modify this work, you **must** adhere to the terms of the GPLv3, including, but not limited to, providing up-to-date source code upon distribution, displaying appropriate copyright and license notices in prominent positions of all conveyed works, and making users aware of their rights to the software under the GPLv3.
|
||||
|
||||
In practice, this means that you can use the firmware commercially, but you must understand your obligation to provide all future users of the system with the same rights, that you have been provided by the GPLv3. If you intend using the RNode Firmware commercially, it is worth reading [this page](https://unsigned.io/sell_rnodes.html).
|
||||
## Improvements
|
||||
- Heltec T114 LCD backlight powers off when screen blanks
|
||||
- LNA-equipped boards have interference detection threshold increased from 11 to 14dB
|
||||
|
||||
@@ -89,6 +89,12 @@ void setup() {
|
||||
pinMode(PIN_LED_BLUE, OUTPUT);
|
||||
delay(200);
|
||||
#endif
|
||||
#if BOARD_MODEL == BOARD_PROMICRO
|
||||
delay(200);
|
||||
pinMode(PIN_VEXT_EN, OUTPUT);
|
||||
digitalWrite(PIN_VEXT_EN, HIGH);
|
||||
delay(200);
|
||||
#endif
|
||||
|
||||
if (!eeprom_begin()) { Serial.write("EEPROM initialisation failed.\r\n"); }
|
||||
#endif
|
||||
@@ -129,7 +135,7 @@ void setup() {
|
||||
boot_seq();
|
||||
#endif
|
||||
|
||||
#if BOARD_MODEL != BOARD_RAK4631 && BOARD_MODEL != BOARD_HELTEC_T114 && BOARD_MODEL != BOARD_TECHO && BOARD_MODEL != BOARD_T3S3 && BOARD_MODEL != BOARD_TBEAM_S_V1 && BOARD_MODEL != BOARD_HELTEC32_V4
|
||||
#if BOARD_MODEL != BOARD_RAK4631 && BOARD_MODEL != BOARD_HELTEC_T114 && BOARD_MODEL != BOARD_MESHPOE_S3 && BOARD_MODEL != BOARD_MESHADVENTURER_S3 && BOARD_MODEL != BOARD_PROMICRO && BOARD_MODEL != BOARD_TECHO && BOARD_MODEL != BOARD_T3S3 && BOARD_MODEL != BOARD_TBEAM_S_V1 && BOARD_MODEL != BOARD_TBEAM_S_V3 && BOARD_MODEL != BOARD_HELTEC32_V4
|
||||
// Some boards need to wait until the hardware UART is set up before booting
|
||||
// the full firmware. In the case of the RAK4631 and Heltec T114, the line below will wait
|
||||
// until a serial connection is actually established with a master. Thus, it
|
||||
@@ -177,7 +183,7 @@ void setup() {
|
||||
#if MODEM == SX1276 || MODEM == SX1278
|
||||
LoRa->setPins(pin_cs, pin_reset, pin_dio, pin_busy);
|
||||
#elif MODEM == SX1262
|
||||
LoRa->setPins(pin_cs, pin_reset, pin_dio, pin_busy, pin_rxen);
|
||||
LoRa->setPins(pin_cs, pin_reset, pin_dio, pin_busy, pin_rxen, pin_txen);
|
||||
#elif MODEM == SX1280
|
||||
LoRa->setPins(pin_cs, pin_reset, pin_dio, pin_busy, pin_rxen, pin_txen);
|
||||
#endif
|
||||
@@ -535,7 +541,9 @@ bool startRadio() {
|
||||
// Flash an info pattern to indicate
|
||||
// that the radio is now on
|
||||
kiss_indicate_radiostate();
|
||||
if (!display_blanked) {
|
||||
led_indicate_info(3);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -575,7 +583,7 @@ volatile bool queue_flushing = false;
|
||||
void flush_queue(void) {
|
||||
if (!queue_flushing) {
|
||||
queue_flushing = true;
|
||||
led_tx_on();
|
||||
if (!display_blanked) { led_tx_on(); }
|
||||
|
||||
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
|
||||
while (!fifo16_isempty(&packet_starts)) {
|
||||
@@ -596,7 +604,7 @@ void flush_queue(void) {
|
||||
}
|
||||
}
|
||||
|
||||
lora_receive(); led_tx_off();
|
||||
lora_receive(); if (!display_blanked) { led_tx_off(); }
|
||||
}
|
||||
|
||||
queue_height = 0;
|
||||
@@ -615,7 +623,8 @@ void flush_queue(void) {
|
||||
|
||||
void pop_queue() {
|
||||
if (!queue_flushing) {
|
||||
queue_flushing = true; led_tx_on();
|
||||
queue_flushing = true;
|
||||
if (!display_blanked) { led_tx_on(); }
|
||||
|
||||
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
|
||||
if (!fifo16_isempty(&packet_starts)) {
|
||||
@@ -637,7 +646,8 @@ void pop_queue() {
|
||||
queued_bytes -= length;
|
||||
}
|
||||
|
||||
lora_receive(); led_tx_off();
|
||||
lora_receive();
|
||||
if (!display_blanked) { led_tx_off(); }
|
||||
}
|
||||
|
||||
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
|
||||
@@ -751,7 +761,7 @@ void transmit(uint16_t size) {
|
||||
add_airtime(written);
|
||||
|
||||
} else {
|
||||
led_tx_on(); uint16_t written = 0;
|
||||
if (!display_blanked) { led_tx_on(); } uint16_t written = 0;
|
||||
if (size > SINGLE_MTU) { size = SINGLE_MTU; }
|
||||
if (!implicit) { LoRa->beginPacket(); }
|
||||
else { LoRa->beginPacket(size); }
|
||||
@@ -872,7 +882,7 @@ void serial_callback(uint8_t sbyte) {
|
||||
if (txp > 13) txp = 13;
|
||||
#endif
|
||||
#else
|
||||
if (txp > 17) txp = 17;
|
||||
if (txp > 20) txp = 20;
|
||||
#endif
|
||||
|
||||
lora_txp = txp;
|
||||
@@ -984,7 +994,7 @@ void serial_callback(uint8_t sbyte) {
|
||||
} else if (command == CMD_RADIO_LOCK) {
|
||||
update_radio_lock();
|
||||
kiss_indicate_radio_lock();
|
||||
} else if (command == CMD_BLINK) {
|
||||
} else if (command == CMD_BLINK && !display_blanked) {
|
||||
led_indicate_info(sbyte);
|
||||
} else if (command == CMD_RANDOM) {
|
||||
kiss_indicate_random(getRandom());
|
||||
@@ -1431,13 +1441,15 @@ void update_modem_status() {
|
||||
if (carrier_detected) { dcd = true; } else { dcd = false; }
|
||||
|
||||
dcd_led = dcd;
|
||||
if (dcd_led) { led_rx_on(); }
|
||||
if (!display_blanked && dcd_led) { led_rx_on(); }
|
||||
else {
|
||||
if (interference_detected) {
|
||||
if (led_id_filter >= LED_ID_TRIG && noise_floor_sampled) { led_id_on(); }
|
||||
if (led_id_filter >= LED_ID_TRIG && noise_floor_sampled && !display_blanked) { led_id_on(); }
|
||||
} else {
|
||||
if (airtime_lock) { led_indicate_airtime_lock(); }
|
||||
else { led_rx_off(); led_id_off(); }
|
||||
if (airtime_lock && !display_blanked) { led_indicate_airtime_lock(); }
|
||||
else {
|
||||
if (!display_blanked) { led_rx_off(); led_id_off(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1707,8 +1719,10 @@ void loop() {
|
||||
console_loop();
|
||||
#endif
|
||||
} else {
|
||||
if (!display_blanked) {
|
||||
led_indicate_standby();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
led_indicate_not_ready();
|
||||
@@ -1767,7 +1781,13 @@ void sleep_now() {
|
||||
#endif
|
||||
#endif
|
||||
#if BOARD_MODEL == BOARD_HELTEC32_V4
|
||||
#if LORA_PA_AUTO_DETECT
|
||||
if (sx126x_modem.isKCT8103L()) {
|
||||
digitalWrite(LORA_PA_CTX, LOW);
|
||||
} else {
|
||||
digitalWrite(LORA_PA_CPS, LOW);
|
||||
}
|
||||
#endif
|
||||
digitalWrite(LORA_PA_CSD, LOW);
|
||||
digitalWrite(LORA_PA_PWR_EN, LOW);
|
||||
digitalWrite(Vext, HIGH);
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# Precompiled Firmware
|
||||
You can download and flash the firmware to supported boards using the [RNode Config Utility](https://github.com/markqvist/rnodeconfigutil). All firmware releases are now handled and installed directly through `rnodeconf`, which is inclueded in the `rns` package. It can be installed via `pip`:
|
||||
|
||||
```
|
||||
# Install rnodeconf via rns package
|
||||
pip install rns --upgrade
|
||||
|
||||
# Install the firmware on a board with the install guide
|
||||
rnodeconf --autoinstall
|
||||
```
|
||||
Binary file not shown.
@@ -1,595 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# ESP32 partition table generation tool
|
||||
#
|
||||
# Converts partition tables to/from CSV and binary formats.
|
||||
#
|
||||
# See https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/partition-tables.html
|
||||
# for explanation of partition table structure and uses.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import division, print_function, unicode_literals
|
||||
|
||||
import argparse
|
||||
import binascii
|
||||
import errno
|
||||
import hashlib
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
import sys
|
||||
|
||||
MAX_PARTITION_LENGTH = 0xC00 # 3K for partition data (96 entries) leaves 1K in a 4K sector for signature
|
||||
MD5_PARTITION_BEGIN = b'\xEB\xEB' + b'\xFF' * 14 # The first 2 bytes are like magic numbers for MD5 sum
|
||||
PARTITION_TABLE_SIZE = 0x1000 # Size of partition table
|
||||
|
||||
MIN_PARTITION_SUBTYPE_APP_OTA = 0x10
|
||||
NUM_PARTITION_SUBTYPE_APP_OTA = 16
|
||||
|
||||
__version__ = '1.2'
|
||||
|
||||
APP_TYPE = 0x00
|
||||
DATA_TYPE = 0x01
|
||||
|
||||
TYPES = {
|
||||
'app': APP_TYPE,
|
||||
'data': DATA_TYPE,
|
||||
}
|
||||
|
||||
|
||||
def get_ptype_as_int(ptype):
|
||||
""" Convert a string which might be numeric or the name of a partition type to an integer """
|
||||
try:
|
||||
return TYPES[ptype]
|
||||
except KeyError:
|
||||
try:
|
||||
return int(ptype, 0)
|
||||
except TypeError:
|
||||
return ptype
|
||||
|
||||
|
||||
# Keep this map in sync with esp_partition_subtype_t enum in esp_partition.h
|
||||
SUBTYPES = {
|
||||
APP_TYPE: {
|
||||
'factory': 0x00,
|
||||
'test': 0x20,
|
||||
},
|
||||
DATA_TYPE: {
|
||||
'ota': 0x00,
|
||||
'phy': 0x01,
|
||||
'nvs': 0x02,
|
||||
'coredump': 0x03,
|
||||
'nvs_keys': 0x04,
|
||||
'efuse': 0x05,
|
||||
'undefined': 0x06,
|
||||
'esphttpd': 0x80,
|
||||
'fat': 0x81,
|
||||
'spiffs': 0x82,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def get_subtype_as_int(ptype, subtype):
|
||||
""" Convert a string which might be numeric or the name of a partition subtype to an integer """
|
||||
try:
|
||||
return SUBTYPES[get_ptype_as_int(ptype)][subtype]
|
||||
except KeyError:
|
||||
try:
|
||||
return int(subtype, 0)
|
||||
except TypeError:
|
||||
return subtype
|
||||
|
||||
|
||||
ALIGNMENT = {
|
||||
APP_TYPE: 0x10000,
|
||||
DATA_TYPE: 0x1000,
|
||||
}
|
||||
|
||||
|
||||
def get_alignment_for_type(ptype):
|
||||
return ALIGNMENT.get(ptype, ALIGNMENT[DATA_TYPE])
|
||||
|
||||
|
||||
def get_partition_type(ptype):
|
||||
if ptype == 'app':
|
||||
return APP_TYPE
|
||||
if ptype == 'data':
|
||||
return DATA_TYPE
|
||||
raise InputError('Invalid partition type')
|
||||
|
||||
|
||||
def add_extra_subtypes(csv):
|
||||
for line_no in csv:
|
||||
try:
|
||||
fields = [line.strip() for line in line_no.split(',')]
|
||||
for subtype, subtype_values in SUBTYPES.items():
|
||||
if (int(fields[2], 16) in subtype_values.values() and subtype == get_partition_type(fields[0])):
|
||||
raise ValueError('Found duplicate value in partition subtype')
|
||||
SUBTYPES[TYPES[fields[0]]][fields[1]] = int(fields[2], 16)
|
||||
except InputError as err:
|
||||
raise InputError('Error parsing custom subtypes: %s' % err)
|
||||
|
||||
|
||||
quiet = False
|
||||
md5sum = True
|
||||
secure = False
|
||||
offset_part_table = 0
|
||||
|
||||
|
||||
def status(msg):
|
||||
""" Print status message to stderr """
|
||||
if not quiet:
|
||||
critical(msg)
|
||||
|
||||
|
||||
def critical(msg):
|
||||
""" Print critical message to stderr """
|
||||
sys.stderr.write(msg)
|
||||
sys.stderr.write('\n')
|
||||
|
||||
|
||||
class PartitionTable(list):
|
||||
def __init__(self):
|
||||
super(PartitionTable, self).__init__(self)
|
||||
|
||||
@classmethod
|
||||
def from_file(cls, f):
|
||||
data = f.read()
|
||||
data_is_binary = data[0:2] == PartitionDefinition.MAGIC_BYTES
|
||||
if data_is_binary:
|
||||
status('Parsing binary partition input...')
|
||||
return cls.from_binary(data), True
|
||||
|
||||
data = data.decode()
|
||||
status('Parsing CSV input...')
|
||||
return cls.from_csv(data), False
|
||||
|
||||
@classmethod
|
||||
def from_csv(cls, csv_contents):
|
||||
res = PartitionTable()
|
||||
lines = csv_contents.splitlines()
|
||||
|
||||
def expand_vars(f):
|
||||
f = os.path.expandvars(f)
|
||||
m = re.match(r'(?<!\\)\$([A-Za-z_][A-Za-z0-9_]*)', f)
|
||||
if m:
|
||||
raise InputError("unknown variable '%s'" % m.group(1))
|
||||
return f
|
||||
|
||||
for line_no in range(len(lines)):
|
||||
line = expand_vars(lines[line_no]).strip()
|
||||
if line.startswith('#') or len(line) == 0:
|
||||
continue
|
||||
try:
|
||||
res.append(PartitionDefinition.from_csv(line, line_no + 1))
|
||||
except InputError as err:
|
||||
raise InputError('Error at line %d: %s\nPlease check extra_partition_subtypes.inc file in build/config directory' % (line_no + 1, err))
|
||||
except Exception:
|
||||
critical('Unexpected error parsing CSV line %d: %s' % (line_no + 1, line))
|
||||
raise
|
||||
|
||||
# fix up missing offsets & negative sizes
|
||||
last_end = offset_part_table + PARTITION_TABLE_SIZE # first offset after partition table
|
||||
for e in res:
|
||||
if e.offset is not None and e.offset < last_end:
|
||||
if e == res[0]:
|
||||
raise InputError('CSV Error at line %d: Partitions overlap. Partition sets offset 0x%x. '
|
||||
'But partition table occupies the whole sector 0x%x. '
|
||||
'Use a free offset 0x%x or higher.'
|
||||
% (e.line_no, e.offset, offset_part_table, last_end))
|
||||
else:
|
||||
raise InputError('CSV Error at line %d: Partitions overlap. Partition sets offset 0x%x. Previous partition ends 0x%x'
|
||||
% (e.line_no, e.offset, last_end))
|
||||
if e.offset is None:
|
||||
pad_to = get_alignment_for_type(e.type)
|
||||
if last_end % pad_to != 0:
|
||||
last_end += pad_to - (last_end % pad_to)
|
||||
e.offset = last_end
|
||||
if e.size < 0:
|
||||
e.size = -e.size - e.offset
|
||||
last_end = e.offset + e.size
|
||||
|
||||
return res
|
||||
|
||||
def __getitem__(self, item):
|
||||
""" Allow partition table access via name as well as by
|
||||
numeric index. """
|
||||
if isinstance(item, str):
|
||||
for x in self:
|
||||
if x.name == item:
|
||||
return x
|
||||
raise ValueError("No partition entry named '%s'" % item)
|
||||
else:
|
||||
return super(PartitionTable, self).__getitem__(item)
|
||||
|
||||
def find_by_type(self, ptype, subtype):
|
||||
""" Return a partition by type & subtype, returns
|
||||
None if not found """
|
||||
# convert ptype & subtypes names (if supplied this way) to integer values
|
||||
ptype = get_ptype_as_int(ptype)
|
||||
subtype = get_subtype_as_int(ptype, subtype)
|
||||
|
||||
for p in self:
|
||||
if p.type == ptype and p.subtype == subtype:
|
||||
yield p
|
||||
return
|
||||
|
||||
def find_by_name(self, name):
|
||||
for p in self:
|
||||
if p.name == name:
|
||||
return p
|
||||
return None
|
||||
|
||||
def verify(self):
|
||||
# verify each partition individually
|
||||
for p in self:
|
||||
p.verify()
|
||||
|
||||
# check on duplicate name
|
||||
names = [p.name for p in self]
|
||||
duplicates = set(n for n in names if names.count(n) > 1)
|
||||
|
||||
# print sorted duplicate partitions by name
|
||||
if len(duplicates) != 0:
|
||||
critical('A list of partitions that have the same name:')
|
||||
for p in sorted(self, key=lambda x:x.name):
|
||||
if len(duplicates.intersection([p.name])) != 0:
|
||||
critical('%s' % (p.to_csv()))
|
||||
raise InputError('Partition names must be unique')
|
||||
|
||||
# check for overlaps
|
||||
last = None
|
||||
for p in sorted(self, key=lambda x:x.offset):
|
||||
if p.offset < offset_part_table + PARTITION_TABLE_SIZE:
|
||||
raise InputError('Partition offset 0x%x is below 0x%x' % (p.offset, offset_part_table + PARTITION_TABLE_SIZE))
|
||||
if last is not None and p.offset < last.offset + last.size:
|
||||
raise InputError('Partition at 0x%x overlaps 0x%x-0x%x' % (p.offset, last.offset, last.offset + last.size - 1))
|
||||
last = p
|
||||
|
||||
# check that otadata should be unique
|
||||
otadata_duplicates = [p for p in self if p.type == TYPES['data'] and p.subtype == SUBTYPES[DATA_TYPE]['ota']]
|
||||
if len(otadata_duplicates) > 1:
|
||||
for p in otadata_duplicates:
|
||||
critical('%s' % (p.to_csv()))
|
||||
raise InputError('Found multiple otadata partitions. Only one partition can be defined with type="data"(1) and subtype="ota"(0).')
|
||||
|
||||
if len(otadata_duplicates) == 1 and otadata_duplicates[0].size != 0x2000:
|
||||
p = otadata_duplicates[0]
|
||||
critical('%s' % (p.to_csv()))
|
||||
raise InputError('otadata partition must have size = 0x2000')
|
||||
|
||||
def flash_size(self):
|
||||
""" Return the size that partitions will occupy in flash
|
||||
(ie the offset the last partition ends at)
|
||||
"""
|
||||
try:
|
||||
last = sorted(self, reverse=True)[0]
|
||||
except IndexError:
|
||||
return 0 # empty table!
|
||||
return last.offset + last.size
|
||||
|
||||
def verify_size_fits(self, flash_size_bytes: int) -> None:
|
||||
""" Check that partition table fits into the given flash size.
|
||||
Raises InputError otherwise.
|
||||
"""
|
||||
table_size = self.flash_size()
|
||||
if flash_size_bytes < table_size:
|
||||
mb = 1024 * 1024
|
||||
raise InputError('Partitions tables occupies %.1fMB of flash (%d bytes) which does not fit in configured '
|
||||
"flash size %dMB. Change the flash size in menuconfig under the 'Serial Flasher Config' menu." %
|
||||
(table_size / mb, table_size, flash_size_bytes / mb))
|
||||
|
||||
@classmethod
|
||||
def from_binary(cls, b):
|
||||
md5 = hashlib.md5()
|
||||
result = cls()
|
||||
for o in range(0,len(b),32):
|
||||
data = b[o:o + 32]
|
||||
if len(data) != 32:
|
||||
raise InputError('Partition table length must be a multiple of 32 bytes')
|
||||
if data == b'\xFF' * 32:
|
||||
return result # got end marker
|
||||
if md5sum and data[:2] == MD5_PARTITION_BEGIN[:2]: # check only the magic number part
|
||||
if data[16:] == md5.digest():
|
||||
continue # the next iteration will check for the end marker
|
||||
else:
|
||||
raise InputError("MD5 checksums don't match! (computed: 0x%s, parsed: 0x%s)" % (md5.hexdigest(), binascii.hexlify(data[16:])))
|
||||
else:
|
||||
md5.update(data)
|
||||
result.append(PartitionDefinition.from_binary(data))
|
||||
raise InputError('Partition table is missing an end-of-table marker')
|
||||
|
||||
def to_binary(self):
|
||||
result = b''.join(e.to_binary() for e in self)
|
||||
if md5sum:
|
||||
result += MD5_PARTITION_BEGIN + hashlib.md5(result).digest()
|
||||
if len(result) >= MAX_PARTITION_LENGTH:
|
||||
raise InputError('Binary partition table length (%d) longer than max' % len(result))
|
||||
result += b'\xFF' * (MAX_PARTITION_LENGTH - len(result)) # pad the sector, for signing
|
||||
return result
|
||||
|
||||
def to_csv(self, simple_formatting=False):
|
||||
rows = ['# ESP-IDF Partition Table',
|
||||
'# Name, Type, SubType, Offset, Size, Flags']
|
||||
rows += [x.to_csv(simple_formatting) for x in self]
|
||||
return '\n'.join(rows) + '\n'
|
||||
|
||||
|
||||
class PartitionDefinition(object):
|
||||
MAGIC_BYTES = b'\xAA\x50'
|
||||
|
||||
# dictionary maps flag name (as used in CSV flags list, property name)
|
||||
# to bit set in flags words in binary format
|
||||
FLAGS = {
|
||||
'encrypted': 0
|
||||
}
|
||||
|
||||
# add subtypes for the 16 OTA slot values ("ota_XX, etc.")
|
||||
for ota_slot in range(NUM_PARTITION_SUBTYPE_APP_OTA):
|
||||
SUBTYPES[TYPES['app']]['ota_%d' % ota_slot] = MIN_PARTITION_SUBTYPE_APP_OTA + ota_slot
|
||||
|
||||
def __init__(self):
|
||||
self.name = ''
|
||||
self.type = None
|
||||
self.subtype = None
|
||||
self.offset = None
|
||||
self.size = None
|
||||
self.encrypted = False
|
||||
|
||||
@classmethod
|
||||
def from_csv(cls, line, line_no):
|
||||
""" Parse a line from the CSV """
|
||||
line_w_defaults = line + ',,,,' # lazy way to support default fields
|
||||
fields = [f.strip() for f in line_w_defaults.split(',')]
|
||||
|
||||
res = PartitionDefinition()
|
||||
res.line_no = line_no
|
||||
res.name = fields[0]
|
||||
res.type = res.parse_type(fields[1])
|
||||
res.subtype = res.parse_subtype(fields[2])
|
||||
res.offset = res.parse_address(fields[3])
|
||||
res.size = res.parse_address(fields[4])
|
||||
if res.size is None:
|
||||
raise InputError("Size field can't be empty")
|
||||
|
||||
flags = fields[5].split(':')
|
||||
for flag in flags:
|
||||
if flag in cls.FLAGS:
|
||||
setattr(res, flag, True)
|
||||
elif len(flag) > 0:
|
||||
raise InputError("CSV flag column contains unknown flag '%s'" % (flag))
|
||||
|
||||
return res
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.name == other.name and self.type == other.type \
|
||||
and self.subtype == other.subtype and self.offset == other.offset \
|
||||
and self.size == other.size
|
||||
|
||||
def __repr__(self):
|
||||
def maybe_hex(x):
|
||||
return '0x%x' % x if x is not None else 'None'
|
||||
return "PartitionDefinition('%s', 0x%x, 0x%x, %s, %s)" % (self.name, self.type, self.subtype or 0,
|
||||
maybe_hex(self.offset), maybe_hex(self.size))
|
||||
|
||||
def __str__(self):
|
||||
return "Part '%s' %d/%d @ 0x%x size 0x%x" % (self.name, self.type, self.subtype, self.offset or -1, self.size or -1)
|
||||
|
||||
def __cmp__(self, other):
|
||||
return self.offset - other.offset
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.offset < other.offset
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.offset > other.offset
|
||||
|
||||
def __le__(self, other):
|
||||
return self.offset <= other.offset
|
||||
|
||||
def __ge__(self, other):
|
||||
return self.offset >= other.offset
|
||||
|
||||
def parse_type(self, strval):
|
||||
if strval == '':
|
||||
raise InputError("Field 'type' can't be left empty.")
|
||||
return parse_int(strval, TYPES)
|
||||
|
||||
def parse_subtype(self, strval):
|
||||
if strval == '':
|
||||
if self.type == TYPES['app']:
|
||||
raise InputError('App partition cannot have an empty subtype')
|
||||
return SUBTYPES[DATA_TYPE]['undefined']
|
||||
return parse_int(strval, SUBTYPES.get(self.type, {}))
|
||||
|
||||
def parse_address(self, strval):
|
||||
if strval == '':
|
||||
return None # PartitionTable will fill in default
|
||||
return parse_int(strval)
|
||||
|
||||
def verify(self):
|
||||
if self.type is None:
|
||||
raise ValidationError(self, 'Type field is not set')
|
||||
if self.subtype is None:
|
||||
raise ValidationError(self, 'Subtype field is not set')
|
||||
if self.offset is None:
|
||||
raise ValidationError(self, 'Offset field is not set')
|
||||
align = get_alignment_for_type(self.type)
|
||||
if self.offset % align:
|
||||
raise ValidationError(self, 'Offset 0x%x is not aligned to 0x%x' % (self.offset, align))
|
||||
if self.size % align and secure and self.type == APP_TYPE:
|
||||
raise ValidationError(self, 'Size 0x%x is not aligned to 0x%x' % (self.size, align))
|
||||
if self.size is None:
|
||||
raise ValidationError(self, 'Size field is not set')
|
||||
|
||||
if self.name in TYPES and TYPES.get(self.name, '') != self.type:
|
||||
critical("WARNING: Partition has name '%s' which is a partition type, but does not match this partition's "
|
||||
'type (0x%x). Mistake in partition table?' % (self.name, self.type))
|
||||
all_subtype_names = []
|
||||
for names in (t.keys() for t in SUBTYPES.values()):
|
||||
all_subtype_names += names
|
||||
if self.name in all_subtype_names and SUBTYPES.get(self.type, {}).get(self.name, '') != self.subtype:
|
||||
critical("WARNING: Partition has name '%s' which is a partition subtype, but this partition has "
|
||||
'non-matching type 0x%x and subtype 0x%x. Mistake in partition table?' % (self.name, self.type, self.subtype))
|
||||
|
||||
STRUCT_FORMAT = b'<2sBBLL16sL'
|
||||
|
||||
@classmethod
|
||||
def from_binary(cls, b):
|
||||
if len(b) != 32:
|
||||
raise InputError('Partition definition length must be exactly 32 bytes. Got %d bytes.' % len(b))
|
||||
res = cls()
|
||||
(magic, res.type, res.subtype, res.offset,
|
||||
res.size, res.name, flags) = struct.unpack(cls.STRUCT_FORMAT, b)
|
||||
if b'\x00' in res.name: # strip null byte padding from name string
|
||||
res.name = res.name[:res.name.index(b'\x00')]
|
||||
res.name = res.name.decode()
|
||||
if magic != cls.MAGIC_BYTES:
|
||||
raise InputError('Invalid magic bytes (%r) for partition definition' % magic)
|
||||
for flag,bit in cls.FLAGS.items():
|
||||
if flags & (1 << bit):
|
||||
setattr(res, flag, True)
|
||||
flags &= ~(1 << bit)
|
||||
if flags != 0:
|
||||
critical('WARNING: Partition definition had unknown flag(s) 0x%08x. Newer binary format?' % flags)
|
||||
return res
|
||||
|
||||
def get_flags_list(self):
|
||||
return [flag for flag in self.FLAGS.keys() if getattr(self, flag)]
|
||||
|
||||
def to_binary(self):
|
||||
flags = sum((1 << self.FLAGS[flag]) for flag in self.get_flags_list())
|
||||
return struct.pack(self.STRUCT_FORMAT,
|
||||
self.MAGIC_BYTES,
|
||||
self.type, self.subtype,
|
||||
self.offset, self.size,
|
||||
self.name.encode(),
|
||||
flags)
|
||||
|
||||
def to_csv(self, simple_formatting=False):
|
||||
def addr_format(a, include_sizes):
|
||||
if not simple_formatting and include_sizes:
|
||||
for (val, suffix) in [(0x100000, 'M'), (0x400, 'K')]:
|
||||
if a % val == 0:
|
||||
return '%d%s' % (a // val, suffix)
|
||||
return '0x%x' % a
|
||||
|
||||
def lookup_keyword(t, keywords):
|
||||
for k,v in keywords.items():
|
||||
if simple_formatting is False and t == v:
|
||||
return k
|
||||
return '%d' % t
|
||||
|
||||
def generate_text_flags():
|
||||
""" colon-delimited list of flags """
|
||||
return ':'.join(self.get_flags_list())
|
||||
|
||||
return ','.join([self.name,
|
||||
lookup_keyword(self.type, TYPES),
|
||||
lookup_keyword(self.subtype, SUBTYPES.get(self.type, {})),
|
||||
addr_format(self.offset, False),
|
||||
addr_format(self.size, True),
|
||||
generate_text_flags()])
|
||||
|
||||
|
||||
def parse_int(v, keywords={}):
|
||||
"""Generic parser for integer fields - int(x,0) with provision for
|
||||
k/m/K/M suffixes and 'keyword' value lookup.
|
||||
"""
|
||||
try:
|
||||
for letter, multiplier in [('k', 1024), ('m', 1024 * 1024)]:
|
||||
if v.lower().endswith(letter):
|
||||
return parse_int(v[:-1], keywords) * multiplier
|
||||
return int(v, 0)
|
||||
except ValueError:
|
||||
if len(keywords) == 0:
|
||||
raise InputError('Invalid field value %s' % v)
|
||||
try:
|
||||
return keywords[v.lower()]
|
||||
except KeyError:
|
||||
raise InputError("Value '%s' is not valid. Known keywords: %s" % (v, ', '.join(keywords)))
|
||||
|
||||
|
||||
def main():
|
||||
global quiet
|
||||
global md5sum
|
||||
global offset_part_table
|
||||
global secure
|
||||
parser = argparse.ArgumentParser(description='ESP32 partition table utility')
|
||||
|
||||
parser.add_argument('--flash-size', help='Optional flash size limit, checks partition table fits in flash',
|
||||
nargs='?', choices=['1MB', '2MB', '4MB', '8MB', '16MB', '32MB', '64MB', '128MB'])
|
||||
parser.add_argument('--disable-md5sum', help='Disable md5 checksum for the partition table', default=False, action='store_true')
|
||||
parser.add_argument('--no-verify', help="Don't verify partition table fields", action='store_true')
|
||||
parser.add_argument('--verify', '-v', help='Verify partition table fields (deprecated, this behaviour is '
|
||||
'enabled by default and this flag does nothing.', action='store_true')
|
||||
parser.add_argument('--quiet', '-q', help="Don't print non-critical status messages to stderr", action='store_true')
|
||||
parser.add_argument('--offset', '-o', help='Set offset partition table', default='0x8000')
|
||||
parser.add_argument('--secure', help='Require app partitions to be suitable for secure boot', action='store_true')
|
||||
parser.add_argument('--extra-partition-subtypes', help='Extra partition subtype entries', nargs='*')
|
||||
parser.add_argument('input', help='Path to CSV or binary file to parse.', type=argparse.FileType('rb'))
|
||||
parser.add_argument('output', help='Path to output converted binary or CSV file. Will use stdout if omitted.',
|
||||
nargs='?', default='-')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
quiet = args.quiet
|
||||
md5sum = not args.disable_md5sum
|
||||
secure = args.secure
|
||||
offset_part_table = int(args.offset, 0)
|
||||
if args.extra_partition_subtypes:
|
||||
add_extra_subtypes(args.extra_partition_subtypes)
|
||||
|
||||
table, input_is_binary = PartitionTable.from_file(args.input)
|
||||
|
||||
if not args.no_verify:
|
||||
status('Verifying table...')
|
||||
table.verify()
|
||||
|
||||
if args.flash_size:
|
||||
size_mb = int(args.flash_size.replace('MB', ''))
|
||||
table.verify_size_fits(size_mb * 1024 * 1024)
|
||||
|
||||
# Make sure that the output directory is created
|
||||
output_dir = os.path.abspath(os.path.dirname(args.output))
|
||||
|
||||
if not os.path.exists(output_dir):
|
||||
try:
|
||||
os.makedirs(output_dir)
|
||||
except OSError as exc:
|
||||
if exc.errno != errno.EEXIST:
|
||||
raise
|
||||
|
||||
if input_is_binary:
|
||||
output = table.to_csv()
|
||||
with sys.stdout if args.output == '-' else open(args.output, 'w') as f:
|
||||
f.write(output)
|
||||
else:
|
||||
output = table.to_binary()
|
||||
try:
|
||||
stdout_binary = sys.stdout.buffer # Python 3
|
||||
except AttributeError:
|
||||
stdout_binary = sys.stdout
|
||||
with stdout_binary if args.output == '-' else open(args.output, 'wb') as f:
|
||||
f.write(output)
|
||||
|
||||
|
||||
class InputError(RuntimeError):
|
||||
def __init__(self, e):
|
||||
super(InputError, self).__init__(e)
|
||||
|
||||
|
||||
class ValidationError(InputError):
|
||||
def __init__(self, partition, message):
|
||||
super(ValidationError, self).__init__(
|
||||
'Partition %s invalid: %s' % (partition.name, message))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except InputError as e:
|
||||
print(e, file=sys.stderr)
|
||||
sys.exit(2)
|
||||
@@ -1,593 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# spiffsgen is a tool used to generate a spiffs image from a directory
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import division, print_function
|
||||
|
||||
import argparse
|
||||
import io
|
||||
import math
|
||||
import os
|
||||
import struct
|
||||
|
||||
try:
|
||||
import typing
|
||||
|
||||
TSP = typing.TypeVar('TSP', bound='SpiffsObjPageWithIdx')
|
||||
ObjIdsItem = typing.Tuple[int, typing.Type[TSP]]
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
SPIFFS_PH_FLAG_USED_FINAL_INDEX = 0xF8
|
||||
SPIFFS_PH_FLAG_USED_FINAL = 0xFC
|
||||
|
||||
SPIFFS_PH_FLAG_LEN = 1
|
||||
SPIFFS_PH_IX_SIZE_LEN = 4
|
||||
SPIFFS_PH_IX_OBJ_TYPE_LEN = 1
|
||||
SPIFFS_TYPE_FILE = 1
|
||||
|
||||
# Based on typedefs under spiffs_config.h
|
||||
SPIFFS_OBJ_ID_LEN = 2 # spiffs_obj_id
|
||||
SPIFFS_SPAN_IX_LEN = 2 # spiffs_span_ix
|
||||
SPIFFS_PAGE_IX_LEN = 2 # spiffs_page_ix
|
||||
SPIFFS_BLOCK_IX_LEN = 2 # spiffs_block_ix
|
||||
|
||||
|
||||
class SpiffsBuildConfig(object):
|
||||
def __init__(self,
|
||||
page_size, # type: int
|
||||
page_ix_len, # type: int
|
||||
block_size, # type: int
|
||||
block_ix_len, # type: int
|
||||
meta_len, # type: int
|
||||
obj_name_len, # type: int
|
||||
obj_id_len, # type: int
|
||||
span_ix_len, # type: int
|
||||
packed, # type: bool
|
||||
aligned, # type: bool
|
||||
endianness, # type: str
|
||||
use_magic, # type: bool
|
||||
use_magic_len, # type: bool
|
||||
aligned_obj_ix_tables # type: bool
|
||||
):
|
||||
if block_size % page_size != 0:
|
||||
raise RuntimeError('block size should be a multiple of page size')
|
||||
|
||||
self.page_size = page_size
|
||||
self.block_size = block_size
|
||||
self.obj_id_len = obj_id_len
|
||||
self.span_ix_len = span_ix_len
|
||||
self.packed = packed
|
||||
self.aligned = aligned
|
||||
self.obj_name_len = obj_name_len
|
||||
self.meta_len = meta_len
|
||||
self.page_ix_len = page_ix_len
|
||||
self.block_ix_len = block_ix_len
|
||||
self.endianness = endianness
|
||||
self.use_magic = use_magic
|
||||
self.use_magic_len = use_magic_len
|
||||
self.aligned_obj_ix_tables = aligned_obj_ix_tables
|
||||
|
||||
self.PAGES_PER_BLOCK = self.block_size // self.page_size
|
||||
self.OBJ_LU_PAGES_PER_BLOCK = int(math.ceil(self.block_size / self.page_size * self.obj_id_len / self.page_size))
|
||||
self.OBJ_USABLE_PAGES_PER_BLOCK = self.PAGES_PER_BLOCK - self.OBJ_LU_PAGES_PER_BLOCK
|
||||
|
||||
self.OBJ_LU_PAGES_OBJ_IDS_LIM = self.page_size // self.obj_id_len
|
||||
|
||||
self.OBJ_DATA_PAGE_HEADER_LEN = self.obj_id_len + self.span_ix_len + SPIFFS_PH_FLAG_LEN
|
||||
|
||||
pad = 4 - (4 if self.OBJ_DATA_PAGE_HEADER_LEN % 4 == 0 else self.OBJ_DATA_PAGE_HEADER_LEN % 4)
|
||||
|
||||
self.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED = self.OBJ_DATA_PAGE_HEADER_LEN + pad
|
||||
self.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED_PAD = pad
|
||||
self.OBJ_DATA_PAGE_CONTENT_LEN = self.page_size - self.OBJ_DATA_PAGE_HEADER_LEN
|
||||
|
||||
self.OBJ_INDEX_PAGES_HEADER_LEN = (self.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED + SPIFFS_PH_IX_SIZE_LEN +
|
||||
SPIFFS_PH_IX_OBJ_TYPE_LEN + self.obj_name_len + self.meta_len)
|
||||
if aligned_obj_ix_tables:
|
||||
self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED = (self.OBJ_INDEX_PAGES_HEADER_LEN + SPIFFS_PAGE_IX_LEN - 1) & ~(SPIFFS_PAGE_IX_LEN - 1)
|
||||
self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD = self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED - self.OBJ_INDEX_PAGES_HEADER_LEN
|
||||
else:
|
||||
self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED = self.OBJ_INDEX_PAGES_HEADER_LEN
|
||||
self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD = 0
|
||||
|
||||
self.OBJ_INDEX_PAGES_OBJ_IDS_HEAD_LIM = (self.page_size - self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED) // self.block_ix_len
|
||||
self.OBJ_INDEX_PAGES_OBJ_IDS_LIM = (self.page_size - self.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED) // self.block_ix_len
|
||||
|
||||
|
||||
class SpiffsFullError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class SpiffsPage(object):
|
||||
_endianness_dict = {
|
||||
'little': '<',
|
||||
'big': '>'
|
||||
}
|
||||
|
||||
_len_dict = {
|
||||
1: 'B',
|
||||
2: 'H',
|
||||
4: 'I',
|
||||
8: 'Q'
|
||||
}
|
||||
|
||||
def __init__(self, bix, build_config): # type: (int, SpiffsBuildConfig) -> None
|
||||
self.build_config = build_config
|
||||
self.bix = bix
|
||||
|
||||
def to_binary(self): # type: () -> bytes
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class SpiffsObjPageWithIdx(SpiffsPage):
|
||||
def __init__(self, obj_id, build_config): # type: (int, SpiffsBuildConfig) -> None
|
||||
super(SpiffsObjPageWithIdx, self).__init__(0, build_config)
|
||||
self.obj_id = obj_id
|
||||
|
||||
def to_binary(self): # type: () -> bytes
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class SpiffsObjLuPage(SpiffsPage):
|
||||
def __init__(self, bix, build_config): # type: (int, SpiffsBuildConfig) -> None
|
||||
SpiffsPage.__init__(self, bix, build_config)
|
||||
|
||||
self.obj_ids_limit = self.build_config.OBJ_LU_PAGES_OBJ_IDS_LIM
|
||||
self.obj_ids = list() # type: typing.List[ObjIdsItem]
|
||||
|
||||
def _calc_magic(self, blocks_lim): # type: (int) -> int
|
||||
# Calculate the magic value mirroring computation done by the macro SPIFFS_MAGIC defined in
|
||||
# spiffs_nucleus.h
|
||||
magic = 0x20140529 ^ self.build_config.page_size
|
||||
if self.build_config.use_magic_len:
|
||||
magic = magic ^ (blocks_lim - self.bix)
|
||||
# narrow the result to build_config.obj_id_len bytes
|
||||
mask = (2 << (8 * self.build_config.obj_id_len)) - 1
|
||||
return magic & mask
|
||||
|
||||
def register_page(self, page): # type: (TSP) -> None
|
||||
if not self.obj_ids_limit > 0:
|
||||
raise SpiffsFullError()
|
||||
|
||||
obj_id = (page.obj_id, page.__class__)
|
||||
self.obj_ids.append(obj_id)
|
||||
self.obj_ids_limit -= 1
|
||||
|
||||
def to_binary(self): # type: () -> bytes
|
||||
img = b''
|
||||
|
||||
for (obj_id, page_type) in self.obj_ids:
|
||||
if page_type == SpiffsObjIndexPage:
|
||||
obj_id ^= (1 << ((self.build_config.obj_id_len * 8) - 1))
|
||||
img += struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] +
|
||||
SpiffsPage._len_dict[self.build_config.obj_id_len], obj_id)
|
||||
|
||||
assert len(img) <= self.build_config.page_size
|
||||
|
||||
img += b'\xFF' * (self.build_config.page_size - len(img))
|
||||
|
||||
return img
|
||||
|
||||
def magicfy(self, blocks_lim): # type: (int) -> None
|
||||
# Only use magic value if no valid obj id has been written to the spot, which is the
|
||||
# spot taken up by the last obj id on last lookup page. The parent is responsible
|
||||
# for determining which is the last lookup page and calling this function.
|
||||
remaining = self.obj_ids_limit
|
||||
empty_obj_id_dict = {
|
||||
1: 0xFF,
|
||||
2: 0xFFFF,
|
||||
4: 0xFFFFFFFF,
|
||||
8: 0xFFFFFFFFFFFFFFFF
|
||||
}
|
||||
if remaining >= 2:
|
||||
for i in range(remaining):
|
||||
if i == remaining - 2:
|
||||
self.obj_ids.append((self._calc_magic(blocks_lim), SpiffsObjDataPage))
|
||||
break
|
||||
else:
|
||||
self.obj_ids.append((empty_obj_id_dict[self.build_config.obj_id_len], SpiffsObjDataPage))
|
||||
self.obj_ids_limit -= 1
|
||||
|
||||
|
||||
class SpiffsObjIndexPage(SpiffsObjPageWithIdx):
|
||||
def __init__(self, obj_id, span_ix, size, name, build_config
|
||||
): # type: (int, int, int, str, SpiffsBuildConfig) -> None
|
||||
super(SpiffsObjIndexPage, self).__init__(obj_id, build_config)
|
||||
self.span_ix = span_ix
|
||||
self.name = name
|
||||
self.size = size
|
||||
|
||||
if self.span_ix == 0:
|
||||
self.pages_lim = self.build_config.OBJ_INDEX_PAGES_OBJ_IDS_HEAD_LIM
|
||||
else:
|
||||
self.pages_lim = self.build_config.OBJ_INDEX_PAGES_OBJ_IDS_LIM
|
||||
|
||||
self.pages = list() # type: typing.List[int]
|
||||
|
||||
def register_page(self, page): # type: (SpiffsObjDataPage) -> None
|
||||
if not self.pages_lim > 0:
|
||||
raise SpiffsFullError
|
||||
|
||||
self.pages.append(page.offset)
|
||||
self.pages_lim -= 1
|
||||
|
||||
def to_binary(self): # type: () -> bytes
|
||||
obj_id = self.obj_id ^ (1 << ((self.build_config.obj_id_len * 8) - 1))
|
||||
img = struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] +
|
||||
SpiffsPage._len_dict[self.build_config.obj_id_len] +
|
||||
SpiffsPage._len_dict[self.build_config.span_ix_len] +
|
||||
SpiffsPage._len_dict[SPIFFS_PH_FLAG_LEN],
|
||||
obj_id,
|
||||
self.span_ix,
|
||||
SPIFFS_PH_FLAG_USED_FINAL_INDEX)
|
||||
|
||||
# Add padding before the object index page specific information
|
||||
img += b'\xFF' * self.build_config.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED_PAD
|
||||
|
||||
# If this is the first object index page for the object, add filname, type
|
||||
# and size information
|
||||
if self.span_ix == 0:
|
||||
img += struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] +
|
||||
SpiffsPage._len_dict[SPIFFS_PH_IX_SIZE_LEN] +
|
||||
SpiffsPage._len_dict[SPIFFS_PH_FLAG_LEN],
|
||||
self.size,
|
||||
SPIFFS_TYPE_FILE)
|
||||
|
||||
img += self.name.encode() + (b'\x00' * (
|
||||
(self.build_config.obj_name_len - len(self.name))
|
||||
+ self.build_config.meta_len
|
||||
+ self.build_config.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD))
|
||||
|
||||
# Finally, add the page index of daa pages
|
||||
for page in self.pages:
|
||||
page = page >> int(math.log(self.build_config.page_size, 2))
|
||||
img += struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] +
|
||||
SpiffsPage._len_dict[self.build_config.page_ix_len], page)
|
||||
|
||||
assert len(img) <= self.build_config.page_size
|
||||
|
||||
img += b'\xFF' * (self.build_config.page_size - len(img))
|
||||
|
||||
return img
|
||||
|
||||
|
||||
class SpiffsObjDataPage(SpiffsObjPageWithIdx):
|
||||
def __init__(self, offset, obj_id, span_ix, contents, build_config
|
||||
): # type: (int, int, int, bytes, SpiffsBuildConfig) -> None
|
||||
super(SpiffsObjDataPage, self).__init__(obj_id, build_config)
|
||||
self.span_ix = span_ix
|
||||
self.contents = contents
|
||||
self.offset = offset
|
||||
|
||||
def to_binary(self): # type: () -> bytes
|
||||
img = struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] +
|
||||
SpiffsPage._len_dict[self.build_config.obj_id_len] +
|
||||
SpiffsPage._len_dict[self.build_config.span_ix_len] +
|
||||
SpiffsPage._len_dict[SPIFFS_PH_FLAG_LEN],
|
||||
self.obj_id,
|
||||
self.span_ix,
|
||||
SPIFFS_PH_FLAG_USED_FINAL)
|
||||
|
||||
img += self.contents
|
||||
|
||||
assert len(img) <= self.build_config.page_size
|
||||
|
||||
img += b'\xFF' * (self.build_config.page_size - len(img))
|
||||
|
||||
return img
|
||||
|
||||
|
||||
class SpiffsBlock(object):
|
||||
def _reset(self): # type: () -> None
|
||||
self.cur_obj_index_span_ix = 0
|
||||
self.cur_obj_data_span_ix = 0
|
||||
self.cur_obj_id = 0
|
||||
self.cur_obj_idx_page = None # type: typing.Optional[SpiffsObjIndexPage]
|
||||
|
||||
def __init__(self, bix, build_config): # type: (int, SpiffsBuildConfig) -> None
|
||||
self.build_config = build_config
|
||||
self.offset = bix * self.build_config.block_size
|
||||
self.remaining_pages = self.build_config.OBJ_USABLE_PAGES_PER_BLOCK
|
||||
self.pages = list() # type: typing.List[SpiffsPage]
|
||||
self.bix = bix
|
||||
|
||||
lu_pages = list()
|
||||
for i in range(self.build_config.OBJ_LU_PAGES_PER_BLOCK):
|
||||
page = SpiffsObjLuPage(self.bix, self.build_config)
|
||||
lu_pages.append(page)
|
||||
|
||||
self.pages.extend(lu_pages)
|
||||
|
||||
self.lu_page_iter = iter(lu_pages)
|
||||
self.lu_page = next(self.lu_page_iter)
|
||||
|
||||
self._reset()
|
||||
|
||||
def _register_page(self, page): # type: (TSP) -> None
|
||||
if isinstance(page, SpiffsObjDataPage):
|
||||
assert self.cur_obj_idx_page is not None
|
||||
self.cur_obj_idx_page.register_page(page) # can raise SpiffsFullError
|
||||
|
||||
try:
|
||||
self.lu_page.register_page(page)
|
||||
except SpiffsFullError:
|
||||
self.lu_page = next(self.lu_page_iter)
|
||||
try:
|
||||
self.lu_page.register_page(page)
|
||||
except AttributeError: # no next lookup page
|
||||
# Since the amount of lookup pages is pre-computed at every block instance,
|
||||
# this should never occur
|
||||
raise RuntimeError('invalid attempt to add page to a block when there is no more space in lookup')
|
||||
|
||||
self.pages.append(page)
|
||||
|
||||
def begin_obj(self, obj_id, size, name, obj_index_span_ix=0, obj_data_span_ix=0
|
||||
): # type: (int, int, str, int, int) -> None
|
||||
if not self.remaining_pages > 0:
|
||||
raise SpiffsFullError()
|
||||
self._reset()
|
||||
|
||||
self.cur_obj_id = obj_id
|
||||
self.cur_obj_index_span_ix = obj_index_span_ix
|
||||
self.cur_obj_data_span_ix = obj_data_span_ix
|
||||
|
||||
page = SpiffsObjIndexPage(obj_id, self.cur_obj_index_span_ix, size, name, self.build_config)
|
||||
self._register_page(page)
|
||||
|
||||
self.cur_obj_idx_page = page
|
||||
|
||||
self.remaining_pages -= 1
|
||||
self.cur_obj_index_span_ix += 1
|
||||
|
||||
def update_obj(self, contents): # type: (bytes) -> None
|
||||
if not self.remaining_pages > 0:
|
||||
raise SpiffsFullError()
|
||||
page = SpiffsObjDataPage(self.offset + (len(self.pages) * self.build_config.page_size),
|
||||
self.cur_obj_id, self.cur_obj_data_span_ix, contents, self.build_config)
|
||||
|
||||
self._register_page(page)
|
||||
|
||||
self.cur_obj_data_span_ix += 1
|
||||
self.remaining_pages -= 1
|
||||
|
||||
def end_obj(self): # type: () -> None
|
||||
self._reset()
|
||||
|
||||
def is_full(self): # type: () -> bool
|
||||
return self.remaining_pages <= 0
|
||||
|
||||
def to_binary(self, blocks_lim): # type: (int) -> bytes
|
||||
img = b''
|
||||
|
||||
if self.build_config.use_magic:
|
||||
for (idx, page) in enumerate(self.pages):
|
||||
if idx == self.build_config.OBJ_LU_PAGES_PER_BLOCK - 1:
|
||||
assert isinstance(page, SpiffsObjLuPage)
|
||||
page.magicfy(blocks_lim)
|
||||
img += page.to_binary()
|
||||
else:
|
||||
for page in self.pages:
|
||||
img += page.to_binary()
|
||||
|
||||
assert len(img) <= self.build_config.block_size
|
||||
|
||||
img += b'\xFF' * (self.build_config.block_size - len(img))
|
||||
return img
|
||||
|
||||
|
||||
class SpiffsFS(object):
|
||||
def __init__(self, img_size, build_config): # type: (int, SpiffsBuildConfig) -> None
|
||||
if img_size % build_config.block_size != 0:
|
||||
raise RuntimeError('image size should be a multiple of block size')
|
||||
|
||||
self.img_size = img_size
|
||||
self.build_config = build_config
|
||||
|
||||
self.blocks = list() # type: typing.List[SpiffsBlock]
|
||||
self.blocks_lim = self.img_size // self.build_config.block_size
|
||||
self.remaining_blocks = self.blocks_lim
|
||||
self.cur_obj_id = 1 # starting object id
|
||||
|
||||
def _create_block(self): # type: () -> SpiffsBlock
|
||||
if self.is_full():
|
||||
raise SpiffsFullError('the image size has been exceeded')
|
||||
|
||||
block = SpiffsBlock(len(self.blocks), self.build_config)
|
||||
self.blocks.append(block)
|
||||
self.remaining_blocks -= 1
|
||||
return block
|
||||
|
||||
def is_full(self): # type: () -> bool
|
||||
return self.remaining_blocks <= 0
|
||||
|
||||
def create_file(self, img_path, file_path): # type: (str, str) -> None
|
||||
if len(img_path) > self.build_config.obj_name_len:
|
||||
raise RuntimeError("object name '%s' too long" % img_path)
|
||||
|
||||
name = img_path
|
||||
|
||||
with open(file_path, 'rb') as obj:
|
||||
contents = obj.read()
|
||||
|
||||
stream = io.BytesIO(contents)
|
||||
|
||||
try:
|
||||
block = self.blocks[-1]
|
||||
block.begin_obj(self.cur_obj_id, len(contents), name)
|
||||
except (IndexError, SpiffsFullError):
|
||||
block = self._create_block()
|
||||
block.begin_obj(self.cur_obj_id, len(contents), name)
|
||||
|
||||
contents_chunk = stream.read(self.build_config.OBJ_DATA_PAGE_CONTENT_LEN)
|
||||
|
||||
while contents_chunk:
|
||||
try:
|
||||
block = self.blocks[-1]
|
||||
try:
|
||||
# This can fail because either (1) all the pages in block have been
|
||||
# used or (2) object index has been exhausted.
|
||||
block.update_obj(contents_chunk)
|
||||
except SpiffsFullError:
|
||||
# If its (1), use the outer exception handler
|
||||
if block.is_full():
|
||||
raise SpiffsFullError
|
||||
# If its (2), write another object index page
|
||||
block.begin_obj(self.cur_obj_id, len(contents), name,
|
||||
obj_index_span_ix=block.cur_obj_index_span_ix,
|
||||
obj_data_span_ix=block.cur_obj_data_span_ix)
|
||||
continue
|
||||
except (IndexError, SpiffsFullError):
|
||||
# All pages in the block have been exhausted. Create a new block, copying
|
||||
# the previous state of the block to a new one for the continuation of the
|
||||
# current object
|
||||
prev_block = block
|
||||
block = self._create_block()
|
||||
block.cur_obj_id = prev_block.cur_obj_id
|
||||
block.cur_obj_idx_page = prev_block.cur_obj_idx_page
|
||||
block.cur_obj_data_span_ix = prev_block.cur_obj_data_span_ix
|
||||
block.cur_obj_index_span_ix = prev_block.cur_obj_index_span_ix
|
||||
continue
|
||||
|
||||
contents_chunk = stream.read(self.build_config.OBJ_DATA_PAGE_CONTENT_LEN)
|
||||
|
||||
block.end_obj()
|
||||
|
||||
self.cur_obj_id += 1
|
||||
|
||||
def to_binary(self): # type: () -> bytes
|
||||
img = b''
|
||||
all_blocks = []
|
||||
for block in self.blocks:
|
||||
all_blocks.append(block.to_binary(self.blocks_lim))
|
||||
bix = len(self.blocks)
|
||||
if self.build_config.use_magic:
|
||||
# Create empty blocks with magic numbers
|
||||
while self.remaining_blocks > 0:
|
||||
block = SpiffsBlock(bix, self.build_config)
|
||||
all_blocks.append(block.to_binary(self.blocks_lim))
|
||||
self.remaining_blocks -= 1
|
||||
bix += 1
|
||||
else:
|
||||
# Just fill remaining spaces FF's
|
||||
all_blocks.append(b'\xFF' * (self.img_size - len(all_blocks) * self.build_config.block_size))
|
||||
img += b''.join([blk for blk in all_blocks])
|
||||
return img
|
||||
|
||||
|
||||
class CustomHelpFormatter(argparse.HelpFormatter):
|
||||
"""
|
||||
Similar to argparse.ArgumentDefaultsHelpFormatter, except it
|
||||
doesn't add the default value if "(default:" is already present.
|
||||
This helps in the case of options with action="store_false", like
|
||||
--no-magic or --no-magic-len.
|
||||
"""
|
||||
def _get_help_string(self, action): # type: (argparse.Action) -> str
|
||||
if action.help is None:
|
||||
return ''
|
||||
if '%(default)' not in action.help and '(default:' not in action.help:
|
||||
if action.default is not argparse.SUPPRESS:
|
||||
defaulting_nargs = [argparse.OPTIONAL, argparse.ZERO_OR_MORE]
|
||||
if action.option_strings or action.nargs in defaulting_nargs:
|
||||
return action.help + ' (default: %(default)s)'
|
||||
return action.help
|
||||
|
||||
|
||||
def main(): # type: () -> None
|
||||
parser = argparse.ArgumentParser(description='SPIFFS Image Generator',
|
||||
formatter_class=CustomHelpFormatter)
|
||||
|
||||
parser.add_argument('image_size',
|
||||
help='Size of the created image')
|
||||
|
||||
parser.add_argument('base_dir',
|
||||
help='Path to directory from which the image will be created')
|
||||
|
||||
parser.add_argument('output_file',
|
||||
help='Created image output file path')
|
||||
|
||||
parser.add_argument('--page-size',
|
||||
help='Logical page size. Set to value same as CONFIG_SPIFFS_PAGE_SIZE.',
|
||||
type=int,
|
||||
default=256)
|
||||
|
||||
parser.add_argument('--block-size',
|
||||
help="Logical block size. Set to the same value as the flash chip's sector size (g_rom_flashchip.sector_size).",
|
||||
type=int,
|
||||
default=4096)
|
||||
|
||||
parser.add_argument('--obj-name-len',
|
||||
help='File full path maximum length. Set to value same as CONFIG_SPIFFS_OBJ_NAME_LEN.',
|
||||
type=int,
|
||||
default=32)
|
||||
|
||||
parser.add_argument('--meta-len',
|
||||
help='File metadata length. Set to value same as CONFIG_SPIFFS_META_LENGTH.',
|
||||
type=int,
|
||||
default=4)
|
||||
|
||||
parser.add_argument('--use-magic',
|
||||
dest='use_magic',
|
||||
help='Use magic number to create an identifiable SPIFFS image. Specify if CONFIG_SPIFFS_USE_MAGIC.',
|
||||
action='store_true')
|
||||
|
||||
parser.add_argument('--no-magic',
|
||||
dest='use_magic',
|
||||
help='Inverse of --use-magic (default: --use-magic is enabled)',
|
||||
action='store_false')
|
||||
|
||||
parser.add_argument('--use-magic-len',
|
||||
dest='use_magic_len',
|
||||
help='Use position in memory to create different magic numbers for each block. Specify if CONFIG_SPIFFS_USE_MAGIC_LENGTH.',
|
||||
action='store_true')
|
||||
|
||||
parser.add_argument('--no-magic-len',
|
||||
dest='use_magic_len',
|
||||
help='Inverse of --use-magic-len (default: --use-magic-len is enabled)',
|
||||
action='store_false')
|
||||
|
||||
parser.add_argument('--follow-symlinks',
|
||||
help='Take into account symbolic links during partition image creation.',
|
||||
action='store_true')
|
||||
|
||||
parser.add_argument('--big-endian',
|
||||
help='Specify if the target architecture is big-endian. If not specified, little-endian is assumed.',
|
||||
action='store_true')
|
||||
|
||||
parser.add_argument('--aligned-obj-ix-tables',
|
||||
action='store_true',
|
||||
help='Use aligned object index tables. Specify if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES is set.')
|
||||
|
||||
parser.set_defaults(use_magic=True, use_magic_len=True)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not os.path.exists(args.base_dir):
|
||||
raise RuntimeError('given base directory %s does not exist' % args.base_dir)
|
||||
|
||||
with open(args.output_file, 'wb') as image_file:
|
||||
image_size = int(args.image_size, 0)
|
||||
spiffs_build_default = SpiffsBuildConfig(args.page_size, SPIFFS_PAGE_IX_LEN,
|
||||
args.block_size, SPIFFS_BLOCK_IX_LEN, args.meta_len,
|
||||
args.obj_name_len, SPIFFS_OBJ_ID_LEN, SPIFFS_SPAN_IX_LEN,
|
||||
True, True, 'big' if args.big_endian else 'little',
|
||||
args.use_magic, args.use_magic_len, args.aligned_obj_ix_tables)
|
||||
|
||||
spiffs = SpiffsFS(image_size, spiffs_build_default)
|
||||
|
||||
for root, dirs, files in os.walk(args.base_dir, followlinks=args.follow_symlinks):
|
||||
for f in files:
|
||||
full_path = os.path.join(root, f)
|
||||
spiffs.create_file('/' + os.path.relpath(full_path, args.base_dir).replace('\\', '/'), full_path)
|
||||
|
||||
image = spiffs.to_binary()
|
||||
|
||||
image_file.write(image)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
BIN
Release/rnode_firmware_meshadventurer.merged.bin
Normal file
BIN
Release/rnode_firmware_meshadventurer.merged.bin
Normal file
Binary file not shown.
83
Utilities.h
83
Utilities.h
@@ -250,6 +250,13 @@ uint8_t boot_vector = 0x00;
|
||||
void led_tx_off() { }
|
||||
void led_id_on() { }
|
||||
void led_id_off() { }
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V3
|
||||
void led_rx_on() { }
|
||||
void led_rx_off() { }
|
||||
void led_tx_on() { }
|
||||
void led_tx_off() { }
|
||||
void led_id_on() { }
|
||||
void led_id_off() { }
|
||||
#elif BOARD_MODEL == BOARD_LORA32_V1_0
|
||||
#if defined(EXTERNAL_LEDS)
|
||||
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
|
||||
@@ -340,6 +347,41 @@ uint8_t boot_vector = 0x00;
|
||||
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
|
||||
void led_id_on() { }
|
||||
void led_id_off() { }
|
||||
#elif BOARD_MODEL == BOARD_MESHPOE_S3
|
||||
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() { }
|
||||
#elif BOARD_MODEL == BOARD_MESHADVENTURER_S3
|
||||
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() { }
|
||||
#elif BOARD_MODEL == BOARD_MESHADVENTURER
|
||||
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() { }
|
||||
#elif BOARD_MODEL == BOARD_DIY_V1
|
||||
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() { }
|
||||
#elif BOARD_MODEL == BOARD_AETHERNODE
|
||||
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() { }
|
||||
#endif
|
||||
#elif MCU_VARIANT == MCU_NRF52
|
||||
#if HAS_NP == true
|
||||
@@ -356,6 +398,13 @@ uint8_t boot_vector = 0x00;
|
||||
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
|
||||
void led_id_on() { }
|
||||
void led_id_off() { }
|
||||
#elif BOARD_MODEL == BOARD_PROMICRO
|
||||
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() { }
|
||||
#elif BOARD_MODEL == BOARD_HELTEC_T114
|
||||
// Heltec T114 pulls pins LOW to turn on
|
||||
void led_rx_on() { digitalWrite(pin_led_rx, LOW); }
|
||||
@@ -1287,11 +1336,33 @@ int getTxPower() {
|
||||
}
|
||||
|
||||
#if HAS_LORA_PA
|
||||
#if BOARD_MODEL == BOARD_HELTEC32_V4
|
||||
bool pa_values_determined = false;
|
||||
int tx_gain[PA_GAIN_POINTS] = {100};
|
||||
#else
|
||||
bool pa_values_determined = true;
|
||||
const int tx_gain[PA_GAIN_POINTS] = {PA_GAIN_VALUES};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern uint8_t lora_pa_model;
|
||||
void determine_pa_values() {
|
||||
#if BOARD_MODEL == BOARD_HELTEC32_V4
|
||||
if (lora_pa_model == LORA_PA_GC1109) {
|
||||
for (int i=0; i < PA_GAIN_POINTS; i++) { tx_gain[i] = PA_GC1109_VALUES[i]; }
|
||||
pa_values_determined = true;
|
||||
for (int i=0; i < PA_GAIN_POINTS; i++) { Serial.print(" "); Serial.printf("%d", tx_gain[i]); }
|
||||
} else if (lora_pa_model == LORA_PA_KCT8103L) {
|
||||
for (int i=0; i < PA_GAIN_POINTS; i++) { tx_gain[i] = PA_KCT8103L_VALUES[i]; }
|
||||
pa_values_determined = true;
|
||||
for (int i=0; i < PA_GAIN_POINTS; i++) { Serial.print(" "); Serial.printf("%d", tx_gain[i]); }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int map_target_power_to_modem_output(int target_tx_power) {
|
||||
#if HAS_LORA_PA
|
||||
if (!pa_values_determined) { determine_pa_values(); }
|
||||
int modem_output_dbm = -9;
|
||||
for (int i = 0; i < PA_GAIN_POINTS; i++) {
|
||||
int gain = tx_gain[i];
|
||||
@@ -1653,6 +1724,18 @@ bool eeprom_model_valid() {
|
||||
if (model == MODEL_FF) {
|
||||
#elif BOARD_MODEL == BOARD_GENERIC_ESP32
|
||||
if (model == MODEL_FF || model == MODEL_FE) {
|
||||
#elif BOARD_MODEL == BOARD_MESHPOE_S3
|
||||
if (model == MODEL_FF || model == MODEL_FE) {
|
||||
#elif BOARD_MODEL == BOARD_MESHADVENTURER_S3
|
||||
if (model == MODEL_FF || model == MODEL_FE) {
|
||||
#elif BOARD_MODEL == BOARD_MESHADVENTURER
|
||||
if (model == MODEL_FF || model == MODEL_FE) {
|
||||
#elif BOARD_MODEL == BOARD_DIY_V1
|
||||
if (model == MODEL_FF || model == MODEL_FE) {
|
||||
#elif BOARD_MODEL == BOARD_AETHERNODE
|
||||
if (model == MODEL_FF || model == MODEL_FE) {
|
||||
#elif BOARD_MODEL == BOARD_PROMICRO
|
||||
if (model == MODEL_FF || model == MODEL_FE) {
|
||||
#else
|
||||
if (false) {
|
||||
#endif
|
||||
|
||||
@@ -4,4 +4,3 @@ board_manager:
|
||||
- https://raw.githubusercontent.com/RAKwireless/RAKwireless-Arduino-BSP-Index/main/package_rakwireless_index.json
|
||||
- https://github.com/HelTecAutomation/Heltec_nRF52/releases/download/1.7.0/package_heltec_nrf_index.json
|
||||
- https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
|
||||
- http://unsigned.io/arduino/package_unsignedio_UnsignedBoards_index.json
|
||||
|
||||
151
sx126x.cpp
151
sx126x.cpp
@@ -87,7 +87,7 @@
|
||||
#define FREQ_DIV_6X (double)pow(2.0, 25.0)
|
||||
#define FREQ_STEP_6X (double)(XTAL_FREQ_6X / FREQ_DIV_6X)
|
||||
|
||||
#if BOARD_MODEL == BOARD_TECHO
|
||||
#if BOARD_MODEL == BOARD_TECHO || BOARD_MODEL == BOARD_PROMICRO
|
||||
SPIClass spim3 = SPIClass(NRF_SPIM3, pin_miso, pin_sclk, pin_mosi) ;
|
||||
#define SPI spim3
|
||||
|
||||
@@ -96,13 +96,21 @@
|
||||
#define SPI spiModem
|
||||
#endif
|
||||
|
||||
#if HAS_LORA_PA
|
||||
uint8_t lora_pa_model = LORA_PA_MODEL;
|
||||
#endif
|
||||
|
||||
#if HAS_LORA_LNA
|
||||
int lora_lna_gain = LORA_LNA_GAIN;
|
||||
#endif
|
||||
|
||||
extern SPIClass SPI;
|
||||
|
||||
#define MAX_PKT_LENGTH 255
|
||||
|
||||
sx126x::sx126x() :
|
||||
_spiSettings(16E6, MSBFIRST, SPI_MODE0),
|
||||
_ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), _busy(LORA_DEFAULT_BUSY_PIN), _rxen(LORA_DEFAULT_RXEN_PIN),
|
||||
_ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), _busy(LORA_DEFAULT_BUSY_PIN), _rxen(LORA_DEFAULT_RXEN_PIN), _txen(LORA_DEFAULT_TXEN_PIN),
|
||||
_frequency(0),
|
||||
_txp(0),
|
||||
_sf(0x07),
|
||||
@@ -125,7 +133,7 @@ bool sx126x::preInit() {
|
||||
pinMode(_ss, OUTPUT);
|
||||
digitalWrite(_ss, HIGH);
|
||||
|
||||
#if BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_HELTEC32_V4 || BOARD_MODEL == BOARD_TDECK || BOARD_MODEL == BOARD_XIAO_S3
|
||||
#if BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_HELTEC32_V4 || BOARD_MODEL == BOARD_TDECK || BOARD_MODEL == BOARD_XIAO_S3 || BOARD_MODEL == BOARD_GENERIC_ESP32 || BOARD_MODEL == BOARD_MESHPOE_S3 || BOARD_MODEL == BOARD_MESHADVENTURER_S3 || BOARD_MODEL == BOARD_MESHADVENTURER || BOARD_MODEL == BOARD_DIY_V1 || BOARD_MODEL == BOARD_AETHERNODE
|
||||
SPI.begin(pin_sclk, pin_miso, pin_mosi, pin_cs);
|
||||
#elif BOARD_MODEL == BOARD_TECHO
|
||||
SPI.setPins(pin_miso, pin_sclk, pin_mosi);
|
||||
@@ -183,6 +191,7 @@ uint8_t ISR_VECT sx126x::singleTransfer(uint8_t opcode, uint16_t address, uint8_
|
||||
|
||||
void sx126x::rxAntEnable() {
|
||||
if (_rxen != -1) { digitalWrite(_rxen, HIGH); }
|
||||
if (_txen != -1) { digitalWrite(_txen, LOW); }
|
||||
}
|
||||
|
||||
void sx126x::loraMode() {
|
||||
@@ -273,6 +282,21 @@ void sx126x::setPacketParams(long preamble_symbols, uint8_t headermode, uint8_t
|
||||
buf[7] = 0x00;
|
||||
buf[8] = 0x00;
|
||||
executeOpcode(OP_PACKET_PARAMS_6X, buf, 9);
|
||||
|
||||
// SX1262 errata section 15.4: IQ polarity is inverted compared to
|
||||
// SX1276. The SetPacketParams command resets register 0x0736 to an
|
||||
// incorrect default. For standard IQ (no inversion), bit 2 must be
|
||||
// SET after every SetPacketParams call. For inverted IQ, bit 2 must
|
||||
// be CLEARED. Without this fix, LoRa RX demodulation fails silently
|
||||
// while TX continues to work.
|
||||
uint8_t iqreg = readRegister(0x0736);
|
||||
if (buf[5] == 0x00) {
|
||||
// Standard IQ: set bit 2
|
||||
writeRegister(0x0736, iqreg | 0x04);
|
||||
} else {
|
||||
// Inverted IQ: clear bit 2
|
||||
writeRegister(0x0736, iqreg & ~0x04);
|
||||
}
|
||||
}
|
||||
|
||||
void sx126x::reset(void) {
|
||||
@@ -285,6 +309,22 @@ void sx126x::reset(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void sx126x::setDCDCRegulator(void) {
|
||||
// Documentation
|
||||
// 5. Power Distribution -> 5.1 Selecting DC-DC Converter or LDO Regulation
|
||||
// 13.1.11 SetRegulatorMode
|
||||
|
||||
uint8_t mode_byte = MODE_STDBY_RC_6X;
|
||||
executeOpcode(OP_STANDBY_6X, &mode_byte, 1);
|
||||
|
||||
// Enable DC-DC regulator for high power operation
|
||||
uint8_t reg_mode = 0x01; // 0x00 = LDO, 0x01 = DC-DC
|
||||
executeOpcode(OP_REGULATOR_MODE_6X, ®_mode, 1);
|
||||
|
||||
delay(5);
|
||||
waitOnBusy();
|
||||
}
|
||||
|
||||
void sx126x::calibrate(void) {
|
||||
// Put in STDBY_RC mode before calibration
|
||||
uint8_t mode_byte = MODE_STDBY_RC_6X;
|
||||
@@ -315,10 +355,21 @@ int sx126x::begin(long frequency) {
|
||||
if (_busy != -1) { pinMode(_busy, INPUT); }
|
||||
if (!_preinit_done) { if (!preInit()) { return false; } }
|
||||
if (_rxen != -1) { pinMode(_rxen, OUTPUT); }
|
||||
if (_txen != -1) { pinMode(_txen, OUTPUT); }
|
||||
|
||||
//TODO: if it works, make it optional
|
||||
//#ifdef SX1262_USE_DCDC_REGULATOR
|
||||
setDCDCRegulator();
|
||||
//#endif
|
||||
|
||||
calibrate();
|
||||
calibrate_image(frequency);
|
||||
#if HAS_TCXO
|
||||
enableTCXO();
|
||||
//13.1.15 SetRxTxFallbackMode to STDBY_XOSC
|
||||
uint8_t fallback_mode = 0x30; // STDBY_XOSC after TX/RX
|
||||
executeOpcode(OP_RX_TX_FALLBACK_MODE_6X, &fallback_mode, 1);
|
||||
#endif
|
||||
loraMode();
|
||||
standby();
|
||||
|
||||
@@ -335,7 +386,9 @@ int sx126x::begin(long frequency) {
|
||||
setFrequency(frequency);
|
||||
setTxPower(2);
|
||||
enableCrc();
|
||||
writeRegister(REG_LNA_6X, 0x96); // Set LNA boost
|
||||
writeRegister(REG_LNA_6X, 0x96); // Set LNA boosted gain mode
|
||||
// Undocumented SX1262 register patch recommended by Heltec/Semtech for improved RX sensitivity.
|
||||
writeRegister(0x08B5, readRegister(0x08B5) | 0x01);
|
||||
uint8_t basebuf[2] = {0}; // Set base addresses
|
||||
executeOpcode(OP_BUFFER_BASE_ADDR_6X, basebuf, 2);
|
||||
|
||||
@@ -343,7 +396,22 @@ int sx126x::begin(long frequency) {
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
|
||||
#if HAS_LORA_PA
|
||||
#if LORA_PA_GC1109
|
||||
if (lora_pa_model == LORA_PA_UNKNOWN) {
|
||||
#if BOARD_MODEL == BOARD_HELTEC32_V4
|
||||
|
||||
pinMode(LORA_PA_PWR_EN, OUTPUT);
|
||||
pinMode(LORA_PA_CSD, INPUT);
|
||||
digitalWrite(LORA_PA_PWR_EN, HIGH); delay(5);
|
||||
if (digitalRead(LORA_PA_CSD) == HIGH) {
|
||||
lora_pa_model = LORA_PA_KCT8103L;
|
||||
lora_lna_gain = LORA_LNA_KCT8103L_GAIN;
|
||||
} else {
|
||||
lora_pa_model = LORA_PA_GC1109;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (lora_pa_model == LORA_PA_GC1109) {
|
||||
// Enable Vfem_ctl for supply to
|
||||
// PA power net.
|
||||
pinMode(LORA_PA_PWR_EN, OUTPUT);
|
||||
@@ -368,7 +436,26 @@ int sx126x::begin(long frequency) {
|
||||
// is driven by the SX1262 DIO2
|
||||
// pin directly, so we do not
|
||||
// need to manually raise this.
|
||||
#endif
|
||||
|
||||
} else if (lora_pa_model == LORA_PA_KCT8103L) {
|
||||
// Enable Vfem_ctl for supply to
|
||||
// PA power net.
|
||||
pinMode(LORA_PA_PWR_EN, OUTPUT);
|
||||
digitalWrite(LORA_PA_PWR_EN, HIGH);
|
||||
|
||||
// Enable KCT8103L chip
|
||||
pinMode(LORA_PA_CSD, OUTPUT);
|
||||
digitalWrite(LORA_PA_CSD, HIGH);
|
||||
|
||||
// Enable receive LNA
|
||||
pinMode(LORA_PA_CTX, OUTPUT);
|
||||
digitalWrite(LORA_PA_CTX, LOW);
|
||||
|
||||
// On Heltec V4.3, the PA CPS pin
|
||||
// is driven by the SX1262 DIO2
|
||||
// pin directly, so we do not
|
||||
// need to manually raise this.
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
@@ -378,14 +465,18 @@ void sx126x::end() { sleep(); SPI.end(); _preinit_done = false; }
|
||||
|
||||
int sx126x::beginPacket(int implicitHeader) {
|
||||
#if HAS_LORA_PA
|
||||
#if LORA_PA_GC1109
|
||||
if (lora_pa_model == LORA_PA_GC1109) {
|
||||
// Enable PA CPS for transmit
|
||||
// digitalWrite(LORA_PA_CPS, HIGH);
|
||||
// Disabled since we're keeping it
|
||||
// on permanently as long as the
|
||||
// radio is powered up.
|
||||
} else if (lora_pa_model == LORA_PA_KCT8103L) {
|
||||
digitalWrite(LORA_PA_CTX, HIGH);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (_txen != -1) { digitalWrite(_txen, HIGH); } //Set TXen high when transmitting
|
||||
|
||||
standby();
|
||||
if (implicitHeader) { implicitHeaderMode(); }
|
||||
@@ -400,6 +491,9 @@ int sx126x::beginPacket(int implicitHeader) {
|
||||
|
||||
int sx126x::endPacket() {
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
|
||||
if (_rxen != -1) { digitalWrite(_rxen, LOW); } //Set RXen low when transmitting
|
||||
|
||||
uint8_t timeout[3] = {0}; // Put in single TX mode
|
||||
executeOpcode(OP_TX_6X, timeout, 3);
|
||||
|
||||
@@ -472,7 +566,7 @@ int ISR_VECT sx126x::currentRssi() {
|
||||
executeOpcodeRead(OP_CURRENT_RSSI_6X, &byte, 1);
|
||||
int rssi = -(int(byte)) / 2;
|
||||
#if HAS_LORA_LNA
|
||||
rssi -= LORA_LNA_GAIN;
|
||||
rssi -= lora_lna_gain;
|
||||
#endif
|
||||
return rssi;
|
||||
}
|
||||
@@ -488,7 +582,7 @@ int ISR_VECT sx126x::packetRssi() {
|
||||
executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3);
|
||||
int pkt_rssi = -buf[0] / 2;
|
||||
#if HAS_LORA_LNA
|
||||
pkt_rssi -= LORA_LNA_GAIN;
|
||||
pkt_rssi -= lora_lna_gain;
|
||||
#endif
|
||||
return pkt_rssi;
|
||||
}
|
||||
@@ -595,7 +689,7 @@ void sx126x::onReceive(void(*callback)(int)){
|
||||
|
||||
void sx126x::receive(int size) {
|
||||
#if HAS_LORA_PA
|
||||
#if LORA_PA_GC1109
|
||||
if (lora_pa_model == LORA_PA_GC1109) {
|
||||
// Disable PA CPS for receive
|
||||
// digitalWrite(LORA_PA_CPS, LOW);
|
||||
// That turned out to be a bad idea.
|
||||
@@ -603,7 +697,9 @@ void sx126x::receive(int size) {
|
||||
// on and off too quickly. We'll keep
|
||||
// it on permanently, as long as the
|
||||
// radio is powered up.
|
||||
#endif
|
||||
} else if (lora_pa_model == LORA_PA_KCT8103L) {
|
||||
digitalWrite(LORA_PA_CTX, LOW);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (size > 0) {
|
||||
@@ -634,6 +730,8 @@ void sx126x::enableTCXO() {
|
||||
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
|
||||
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V3
|
||||
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
|
||||
#elif BOARD_MODEL == BOARD_T3S3
|
||||
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
|
||||
#elif BOARD_MODEL == BOARD_HELTEC_T114
|
||||
@@ -642,6 +740,20 @@ void sx126x::enableTCXO() {
|
||||
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
|
||||
#elif BOARD_MODEL == BOARD_HELTEC32_V4
|
||||
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
|
||||
#elif BOARD_MODEL == BOARD_GENERIC_ESP32
|
||||
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
|
||||
#elif BOARD_MODEL == BOARD_MESHPOE_S3
|
||||
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
|
||||
#elif BOARD_MODEL == BOARD_MESHADVENTURER_S3
|
||||
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
|
||||
#elif BOARD_MODEL == BOARD_MESHADVENTURER
|
||||
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
|
||||
#elif BOARD_MODEL == BOARD_DIY_V1
|
||||
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
|
||||
#elif BOARD_MODEL == BOARD_AETHERNODE
|
||||
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
|
||||
#elif BOARD_MODEL == BOARD_PROMICRO
|
||||
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
|
||||
#endif
|
||||
executeOpcode(OP_DIO3_TCXO_CTRL_6X, buf, 4);
|
||||
#endif
|
||||
@@ -729,7 +841,17 @@ void sx126x::handleLowDataRate() {
|
||||
}
|
||||
|
||||
// TODO: Check if there's anything the sx1262 can do here
|
||||
void sx126x::optimizeModemSensitivity(){ }
|
||||
// SX1262 errata section 15.1: Modulation quality with 500 kHz LoRa BW.
|
||||
// Register 0x0889 bit 2 must be cleared for 500 kHz, set for all other
|
||||
// bandwidths. Improves receiver sensitivity at non-500 kHz bandwidths.
|
||||
void sx126x::optimizeModemSensitivity(){
|
||||
uint8_t reg = readRegister(0x0889);
|
||||
if (getSignalBandwidth() == 500E3) {
|
||||
writeRegister(0x0889, reg & 0xFB); // clear bit 2
|
||||
} else {
|
||||
writeRegister(0x0889, reg | 0x04); // set bit 2
|
||||
}
|
||||
}
|
||||
|
||||
void sx126x::setSignalBandwidth(long sbw) {
|
||||
if (sbw <= 7.8E3) { _bw = 0x00; }
|
||||
@@ -769,12 +891,13 @@ void sx126x::setSyncWord(uint16_t sw) {
|
||||
writeRegister(REG_SYNC_WORD_LSB_6X, 0x24);
|
||||
}
|
||||
|
||||
void sx126x::setPins(int ss, int reset, int dio0, int busy, int rxen) {
|
||||
void sx126x::setPins(int ss, int reset, int dio0, int busy, int rxen, int txen) {
|
||||
_ss = ss;
|
||||
_reset = reset;
|
||||
_dio0 = dio0;
|
||||
_busy = busy;
|
||||
_rxen = rxen;
|
||||
_txen = txen;
|
||||
}
|
||||
|
||||
void sx126x::dumpRegisters(Stream& out) {
|
||||
|
||||
7
sx126x.h
7
sx126x.h
@@ -74,6 +74,7 @@ public:
|
||||
void disableCrc();
|
||||
void enableTCXO();
|
||||
void disableTCXO();
|
||||
void setDCDCRegulator();
|
||||
|
||||
void rxAntEnable();
|
||||
void loraMode();
|
||||
@@ -92,11 +93,13 @@ public:
|
||||
|
||||
byte random();
|
||||
|
||||
void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN, int busy = LORA_DEFAULT_BUSY_PIN, int rxen = LORA_DEFAULT_RXEN_PIN);
|
||||
void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN, int busy = LORA_DEFAULT_BUSY_PIN, int rxen = LORA_DEFAULT_RXEN_PIN, int txen = LORA_DEFAULT_TXEN_PIN);
|
||||
void setSPIFrequency(uint32_t frequency);
|
||||
|
||||
void dumpRegisters(Stream& out);
|
||||
|
||||
bool isKCT8103L() { return _kct8103l; }
|
||||
|
||||
private:
|
||||
void explicitHeaderMode();
|
||||
void implicitHeaderMode();
|
||||
@@ -121,6 +124,7 @@ private:
|
||||
int _reset;
|
||||
int _dio0;
|
||||
int _rxen;
|
||||
int _txen;
|
||||
int _busy;
|
||||
long _frequency;
|
||||
int _txp;
|
||||
@@ -137,6 +141,7 @@ private:
|
||||
int _fifo_rx_addr_ptr;
|
||||
uint8_t _packet[255];
|
||||
bool _preinit_done;
|
||||
bool _kct8103l;
|
||||
void (*_onReceive)(int);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user