Merge upstream into dev

master
jacob.eva 3 weeks ago
commit 31b5e0f0ea
No known key found for this signature in database
GPG Key ID: B92E083BBCCAA1E
  1. 39
      .github/ISSUE_TEMPLATE/🐛-bug-report.md
  2. 51
      Bluetooth.h
  3. 430
      Boards.h
  4. 24
      Config.h
  5. 2
      Console/Makefile
  6. BIN
      Console/assets/images/bg_h_1.webp
  7. BIN
      Console/assets/stl/Handheld_RNode_Parts.7z
  8. 10
      Console/build.py
  9. 37
      Console/source/guides/make_rnodes.md
  10. 3
      Device.h
  11. 1165
      Display.h
  12. 5
      Framing.h
  13. 1710
      Graphics.h
  14. 11
      Interfaces.h
  15. 161
      Makefile
  16. 76
      Power.h
  17. 24
      README.md
  18. 284
      RNode_Firmware_CE.ino
  19. 5
      ROM.h
  20. 446
      Radio.cpp
  21. 342
      Radio.hpp
  22. 2
      Release/README.md
  23. 250
      Utilities.h
  24. 1
      arduino-cli.yaml
  25. 15
      partition_hashes
  26. 2
      src/ble/BLESerial.cpp
  27. 2
      src/ble/BLESerial.h
  28. 440
      src/display/ST7789.h

@ -0,0 +1,39 @@
---
name: "\U0001F41B Bug Report"
about: Report a reproducible bug
title: ''
labels: ''
assignees: ''
---
**Read the Contribution Guidelines**
Before creating a bug report on this issue tracker, you **must** read the [Contribution Guidelines](https://github.com/markqvist/Reticulum/blob/master/Contributing.md). Issues that do not follow the contribution guidelines **will be deleted without comment**.
- The issue tracker is used by developers of this project. **Do not use it to ask general questions, or for support requests**.
- Ideas and feature requests can be made on the [Discussions](https://github.com/markqvist/Reticulum/discussions). **Only** feature requests accepted by maintainers and developers are tracked and included on the issue tracker. **Do not post feature requests here**.
- After reading the [Contribution Guidelines](https://github.com/markqvist/Reticulum/blob/master/Contributing.md), delete this section from your bug report.
**Describe the Bug**
First of all: Is this really a bug? Is it reproducible?
If this is a request for help because something is not working as you expected, stop right here, and go to the [discussions](https://github.com/markqvist/Reticulum/discussions) instead, where you can post your questions and get help from other users.
If this really is a bug or issue with the software, remove this section of the template, and provide **a clear and concise description of what the bug is**.
**To Reproduce**
Describe in detail how to reproduce the bug.
**Expected Behavior**
A clear and concise description of what you expected to happen.
**Logs & Screenshots**
Please include any relevant log output. If applicable, also add screenshots to help explain your problem. In most cases, without any relevant log output, we will not be able to determine the cause of the bug, or reproduce it.
**System Information**
- OS and version
- Python version
- Program version
**Additional context**
Add any other context about the problem here.

@ -61,7 +61,7 @@ char bt_devname[11];
}
void bt_stop() {
//display_unblank();
display_unblank();
if (bt_state != BT_STATE_OFF) {
SerialBT.end();
bt_allow_pairing = false;
@ -70,7 +70,7 @@ char bt_devname[11];
}
void bt_start() {
//display_unblank();
display_unblank();
if (bt_state == BT_STATE_OFF) {
SerialBT.begin(bt_devname);
bt_state = BT_STATE_ON;
@ -78,7 +78,7 @@ char bt_devname[11];
}
void bt_enable_pairing() {
//display_unblank();
display_unblank();
if (bt_state == BT_STATE_OFF) bt_start();
bt_allow_pairing = true;
bt_pairing_started = millis();
@ -86,14 +86,14 @@ char bt_devname[11];
}
void bt_disable_pairing() {
//display_unblank();
display_unblank();
bt_allow_pairing = false;
bt_ssp_pin = 0;
bt_state = BT_STATE_ON;
}
void bt_pairing_complete(boolean success) {
//display_unblank();
display_unblank();
if (success) {
bt_disable_pairing();
} else {
@ -102,7 +102,7 @@ char bt_devname[11];
}
void bt_connection_callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param) {
//display_unblank();
display_unblank();
if(event == ESP_SPP_SRV_OPEN_EVT) {
bt_state = BT_STATE_CONNECTED;
cable_state = CABLE_STATE_DISCONNECTED;
@ -172,7 +172,7 @@ char bt_devname[11];
void bt_flush() { if (bt_state == BT_STATE_CONNECTED) { SerialBT.flush(); } }
void bt_disable_pairing() {
//display_unblank();
display_unblank();
bt_allow_pairing = false;
bt_ssp_pin = 0;
bt_state = BT_STATE_ON;
@ -270,7 +270,7 @@ char bt_devname[11];
void bt_connect_callback(BLEServer *server) {
// uint16_t conn_id = server->getConnId();
// Serial.printf("Connected: %d\n", conn_id);
//display_unblank();
display_unblank();
ble_authenticated = false;
bt_state = BT_STATE_CONNECTED;
cable_state = CABLE_STATE_DISCONNECTED;
@ -279,7 +279,7 @@ char bt_devname[11];
void bt_disconnect_callback(BLEServer *server) {
// uint16_t conn_id = server->getConnId();
// Serial.printf("Disconnected: %d\n", conn_id);
//display_unblank();
display_unblank();
ble_authenticated = false;
bt_state = BT_STATE_ON;
}
@ -317,7 +317,7 @@ char bt_devname[11];
}
void bt_start() {
//display_unblank();
display_unblank();
if (bt_state == BT_STATE_OFF) {
bt_state = BT_STATE_ON;
SerialBT.begin(bt_devname);
@ -326,7 +326,7 @@ char bt_devname[11];
}
void bt_stop() {
//display_unblank();
display_unblank();
if (bt_state != BT_STATE_OFF) {
bt_allow_pairing = false;
bt_state = BT_STATE_OFF;
@ -345,7 +345,7 @@ char bt_devname[11];
}
void bt_enable_pairing() {
//display_unblank();
display_unblank();
if (bt_state == BT_STATE_OFF) bt_start();
bt_security_setup();
@ -370,6 +370,8 @@ char bt_devname[11];
#endif
#elif MCU_VARIANT == MCU_NRF52
uint32_t pairing_pin = 0;
uint8_t eeprom_read(uint32_t mapped_addr);
void bt_stop() {
@ -385,6 +387,8 @@ char bt_devname[11];
bt_state = BT_STATE_ON;
}
void bt_flush() { if (bt_state == BT_STATE_CONNECTED) { SerialBT.flushTXD(); } }
void bt_pairing_complete(uint16_t conn_handle, uint8_t auth_status) {
if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) {
BLEConnection* connection = Bluefruit.Connection(conn_handle);
@ -421,11 +425,6 @@ char bt_devname[11];
}
bool bt_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) {
for (int i = 0; i < 6; i++) {
// multiply by tens however many times needed to make numbers appear in order
bt_ssp_pin += ((int)passkey[i] - 48) * pow(10, 5-i);
}
kiss_indicate_btpin();
if (bt_allow_pairing) {
return true;
}
@ -435,6 +434,7 @@ char bt_devname[11];
void bt_connect_callback(uint16_t conn_handle) {
bt_state = BT_STATE_CONNECTED;
cable_state = CABLE_STATE_DISCONNECTED;
BLEConnection* conn = Bluefruit.Connection(conn_handle);
conn->requestPHY(BLE_GAP_PHY_2MBPS);
conn->requestMtuExchange(512+3);
@ -447,6 +447,17 @@ void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason) {
}
}
void bt_update_passkey() {
pairing_pin = random(899999)+100000;
bt_ssp_pin = pairing_pin;
}
uint32_t bt_get_passkey() {
// Serial.println("API passkey request");
if (pairing_pin == 0) { bt_update_passkey(); }
return pairing_pin;
}
bool bt_setup_hw() {
if (!bt_ready) {
#if HAS_EEPROM
@ -461,6 +472,10 @@ void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason) {
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
Bluefruit.autoConnLed(false);
if (Bluefruit.begin()) {
uint32_t pin = bt_get_passkey();
char pin_char[6];
sprintf(pin_char,"%lu", pin);
Bluefruit.setTxPower(8); // Check bluefruit.h for supported values
Bluefruit.Security.setIOCaps(true, false, false); // display, yes; yes / no, no; keyboard, no
// This device is indeed capable of yes / no through the pairing mode
@ -470,6 +485,7 @@ void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason) {
Bluefruit.Security.setMITM(true);
Bluefruit.Security.setPairPasskeyCallback(bt_passkey_callback);
Bluefruit.Security.setSecuredCallback(bt_connect_callback);
Bluefruit.Security.setPIN(pin_char);
Bluefruit.Periph.setDisconnectCallback(bt_disconnect_callback);
Bluefruit.Security.setPairCompleteCallback(bt_pairing_complete);
Bluefruit.Periph.setConnInterval(6, 12); // 7.5 - 15 ms
@ -546,6 +562,7 @@ void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason) {
bt_allow_pairing = true;
bt_pairing_started = millis();
bt_state = BT_STATE_PAIRING;
kiss_indicate_btpin();
}
void update_bt() {

@ -40,13 +40,14 @@
#define MODEL_A2 0xA2 // RNode v2.1, 433 MHz
#define MODEL_A7 0xA7 // RNode v2.1, 868 MHz
#define BOARD_RNODE_NG_22 0x42 // RNode hardware revision v2.2 (T3S3)
#define MODEL_A1 0xA1 // RNode v2.2, 433 MHz with SX1268
#define MODEL_A5 0xA5 // RNode v2.2, 433 MHz with SX1278
#define MODEL_A6 0xA6 // RNode v2.2, 868 MHz with SX1262
#define MODEL_AA 0xAA // RNode v2.2, 868 MHz with SX1276
#define PRODUCT_TBEAM 0xE0 // T-Beam - sold by LilyGO
#define BOARD_T3S3 0x42 // T3S3 devices
#define MODEL_A1 0xA1 // T3S3, 433 MHz with SX1268
#define MODEL_A5 0xA5 // T3S3, 433 MHz with SX1278
#define MODEL_A6 0xA6 // T3S3, 868 MHz with SX1262
#define MODEL_AA 0xAA // T3S3, 868 MHz with SX1276
#define MODEL_AC 0xAC // T3S3, 2.4 GHz with SX1280 and PA
#define PRODUCT_TBEAM 0xE0 // T-Beam devices
#define BOARD_TBEAM 0x33
#define MODEL_E4 0xE4 // T-Beam SX1278, 433 Mhz
#define MODEL_E9 0xE9 // T-Beam SX1276, 868 Mhz
@ -73,33 +74,25 @@
#define MODEL_B3 0xB3 // LilyGO T3 v2.0, 433 MHz
#define MODEL_B8 0xB8 // LilyGO T3 v2.0, 868 MHz
#define PRODUCT_T32_21 0xB1 // T3 v2.1 - sold by LilyGO
#define PRODUCT_T32_21 0xB1
#define BOARD_LORA32_V2_1 0x37
#define MODEL_B4 0xB4 // LilyGO T3 v2.1, 433 MHz
#define MODEL_B9 0xB9 // LilyGO T3 v2.1, 868 MHz
#define BOARD_T3S3 0x43 // T3S3 - sold by LilyGO
#define MODEL_A1 0xA1 // T3S3 SX1262 868/915 MHz
#define MODEL_AB 0xAB // T3S3 SX1276 868/915 MHz
#define MODEL_A5 0xA5 // T3S3 SX1278 433 MHz
#define MODEL_AC 0xAC // T3S3 SX1280 2.4 GHz w/ PA
#define PRODUCT_TECHO 0x15 // LilyGO T-Echo devices
#define BOARD_TECHO 0x44
#define MODEL_16 0x16 // T-Echo 433 MHz
#define MODEL_17 0x17 // T-Echo 868/915 MHz
#define PRODUCT_H32_V2 0xC0 // LoRa32 v2 - sold by Heltec
#define PRODUCT_H32_V2 0xC0 // Board code 0x38
#define BOARD_HELTEC32_V2 0x38
#define MODEL_C4 0xC4 // Heltec Lora32 v2, 433 MHz
#define MODEL_C9 0xC9 // Heltec Lora32 v2, 868 MHz
#define PRODUCT_H32_V3 0xC1 // LoRa32 v3 - sold by Heltec
#define PRODUCT_H32_V3 0xC1
#define BOARD_HELTEC32_V3 0x3A
#define MODEL_C5 0xC5 // Heltec Lora32 v3, 433 MHz
#define MODEL_CA 0xCA // Heltec Lora32 v3, 868 MHz
#define PRODUCT_H_W_PAPER 0xC3
#define BOARD_H_W_PAPER 0x3E
#define MODEL_C8 0xC8
#define PRODUCT_RAK4631 0x10 // RAK4631 - sold by RAKWireless
#define BOARD_RAK4631 0x51
#define MODEL_11 0x11 // RAK4631, 433 MHz
@ -114,6 +107,16 @@
#define BOARD_E22_ESP32 0x45 // Custom Ebyte E22 board design for meshtastic, source:
// https://github.com/NanoVHF/Meshtastic-DIY/blob/main/Schematics/E-Byte_E22/Mesh_Ebyte_E22-XXXM30S.pdf
#define PRODUCT_HELTEC_T114 0xC2 // Heltec Mesh Node T114
#define BOARD_HELTEC_T114 0x3C
#define MODEL_C6 0xC6 // Heltec Mesh Node T114, 470-510 MHz
#define MODEL_C7 0xC7 // Heltec Mesh Node T114, 863-928 MHz
#define PRODUCT_TECHO 0x15 // LilyGO T-Echo devices
#define BOARD_TECHO 0x44
#define MODEL_16 0x16 // T-Echo 433 MHz
#define MODEL_17 0x17 // T-Echo 868/915 MHz
#define PRODUCT_HMBRW 0xF0
#define BOARD_HMBRW 0x32
#define BOARD_HUZZAH32 0x34
@ -249,7 +252,8 @@
};
#elif BOARD_VARIANT == MODEL_E3 || BOARD_VARIANT == MODEL_E8
const uint8_t interfaces[INTERFACE_COUNT] = {SX126X};
#define OCP_TUNED 0x38
const uint8_t interfaces[INTERFACE_COUNT] = {SX1262};
const bool interface_cfg[INTERFACE_COUNT][3] = {
// SX1262
{
@ -525,6 +529,64 @@
#define PIN_WAKEUP GPIO_NUM_0
#define WAKEUP_LEVEL 0
#define INTERFACE_COUNT 1
#define OCP_TUNED 0x38
const int pin_btn_usr1 = 0;
#if defined(EXTERNAL_LEDS)
const int pin_led_rx = 13;
const int pin_led_tx = 14;
#else
const int pin_led_rx = 35;
const int pin_led_tx = 35;
#endif
const uint8_t interfaces[INTERFACE_COUNT] = {SX1262};
const bool interface_cfg[INTERFACE_COUNT][3] = {
// SX1262
{
true, // DEFAULT_SPI
true, // HAS_TCXO
true // DIO2_AS_RF_SWITCH
},
};
const int8_t interface_pins[INTERFACE_COUNT][10] = {
// SX1262
{
8, // pin_ss
9, // pin_sclk
10, // pin_mosi
11, // pin_miso
13, // pin_busy
14, // pin_dio
12, // pin_reset
-1, // pin_txen
-1, // pin_rxen
-1 // pin_tcxo_enable
}
};
#elif BOARD_MODEL == BOARD_H_W_PAPER
// Heltec Wireless Paper. Basically the Heltec LoRa32 v3 with an eink display.
// TODO, need to confirm that the display is a 213BN
#define IS_ESP32S3 true
#define HAS_DISPLAY true
#define HAS_BLUETOOTH false
#define HAS_BLE true
#define HAS_PMU true
#define HAS_CONSOLE true
#define HAS_EEPROM true
#define HAS_INPUT true
#define HAS_SLEEP true
#define HAS_DISPLAY true
#define DISPLAY EINK_BW
#define DISPLAY_SCALE_OVERRIDE true
#define DISPLAY_SCALE 1.90625
#define DISPLAY_MODEL GxEPD2_213_BN
#define PIN_WAKEUP GPIO_NUM_0
#define WAKEUP_LEVEL 0
#define INTERFACE_COUNT 1
#define OCP_TUNED 0x38
const int pin_btn_usr1 = 0;
@ -561,6 +623,12 @@
}
};
const int pin_disp_cs = 4;
const int pin_disp_dc = 5;
const int pin_disp_reset = 6;
const int pin_disp_busy = 7;
const int pin_disp_en = 45;
#elif BOARD_MODEL == BOARD_RNODE_NG_20
#define HAS_DISPLAY true
#define DISPLAY OLED
@ -636,7 +704,6 @@
#endif
#endif
const uint8_t interfaces[INTERFACE_COUNT] = {SX127X};
const bool interface_cfg[INTERFACE_COUNT][3] = {
// SX127X
@ -662,11 +729,13 @@
}
};
// todo ce-ise all boards below here
#elif BOARD_MODEL == BOARD_T3S3
#define IS_ESP32S3 true
#define HAS_DISPLAY true
#define DISPLAY OLED
#define HAS_CONSOLE false
#define HAS_CONSOLE true
#define HAS_BLUETOOTH false
#define HAS_BLE true
#define HAS_PMU true
@ -678,11 +747,40 @@
#define HAS_SLEEP true
#define PIN_WAKEUP GPIO_NUM_0
#define WAKEUP_LEVEL 0
#define INTERFACE_COUNT 1
// #define PIN_DISP_SLEEP 21
// #define DISP_SLEEP_LEVEL HIGH
const int pin_btn_usr1 = 0;
const int pin_cs = 7;
const int pin_reset = 8;
const int pin_sclk = 5;
const int pin_mosi = 6;
const int pin_miso = 3;
#if MODEM == SX1262
#define DIO2_AS_RF_SWITCH true
#define HAS_BUSY true
#define HAS_TCXO true
const int pin_busy = 34;
const int pin_dio = 33;
const int pin_tcxo_enable = -1;
#elif MODEM == SX1280
#define CONFIG_QUEUE_SIZE 6144
#define DIO2_AS_RF_SWITCH false
#define HAS_BUSY true
#define HAS_TCXO true
#define HAS_PA true
const int pa_max_input = 3;
#define HAS_RF_SWITCH_RX_TX true
const int pin_rxen = 21;
const int pin_txen = 10;
const int pin_busy = 36;
const int pin_dio = 9;
const int pin_tcxo_enable = -1;
#else
const int pin_dio = 9;
#endif
const int pin_np = 38;
const int pin_dac = 25;
const int pin_adc = 1;
@ -702,6 +800,101 @@
#endif
#endif
#elif BOARD_MODEL == BOARD_TDECK
#define IS_ESP32S3 true
#define MODEM SX1262
#define DIO2_AS_RF_SWITCH true
#define HAS_BUSY true
#define HAS_TCXO true
#define HAS_DISPLAY false
const int pin_poweron = 10;
const int pin_btn_usr1 = 0;
const int pin_cs = 9;
const int pin_reset = 17;
const int pin_sclk = 40;
const int pin_mosi = 41;
const int pin_miso = 38;
const int pin_tcxo_enable = -1;
const int pin_dio = 45;
const int pin_busy = 13;
const int SD_MISO = 38;
const int SD_MOSI = 41;
const int SD_CLK = 40;
const int SD_CS = 39;
const int DISPLAY_DC = 11;
const int DISPLAY_CS = 12;
const int DISPLAY_MISO = 38;
const int DISPLAY_MOSI = 41;
const int DISPLAY_CLK = 40;
const int DISPLAY_BL_PIN = 42;
#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_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 0x38
#define HAS_DISPLAY true
#define HAS_CONSOLE 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
#if BOARD_VARIANT == MODEL_A1
const uint8_t interfaces[INTERFACE_COUNT] = {SX1262};
const bool interface_cfg[INTERFACE_COUNT][3] = {
@ -931,7 +1124,7 @@
//#define I2C_SCL 27
#define CONFIG_QUEUE_1_SIZE 40000
// first interface in list is the primary
const uint8_t interfaces[INTERFACE_COUNT] = {SX126X};
const uint8_t interfaces[INTERFACE_COUNT] = {SX1262};
const bool interface_cfg[INTERFACE_COUNT][3] = {
// SX1262
{
@ -974,8 +1167,7 @@
const int pin_led_tx = LED_RED;
#elif BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_OPENCOM_XL
#define HAS_EEPROM false
#define HAS_DISPLAY true
#define DISPLAY EINK_BW
#define HAS_DISPLAY false
#define HAS_BLUETOOTH false
#define HAS_BLE true
#define HAS_CONSOLE false
@ -995,7 +1187,7 @@
#define INTERFACE_COUNT 1
// first interface in list is the primary
const uint8_t interfaces[INTERFACE_COUNT] = {SX126X};
const uint8_t interfaces[INTERFACE_COUNT] = {SX1262};
const bool interface_cfg[INTERFACE_COUNT][3] = {
// SX1262
{
@ -1020,13 +1212,18 @@
}
};
#elif BOARD_VARIANT == MODEL_13 || BOARD_VARIANT == MODEL_14 || BOARD_VARIANT == MODEL_21
#define HAS_DISPLAY true
#define DISPLAY EINK_BW
#define DISPLAY_SCALE_OVERRIDE true
#define DISPLAY_SCALE 1.90625
#define DISPLAY_MODEL GxEPD2_213_BN
#define INTERFACE_COUNT 2
#define CONFIG_QUEUE_1_SIZE 40000
#define CONFIG_UART_BUFFER_SIZE 40000 // \todo, does it have to be this big?
// first interface in list is the primary
const uint8_t interfaces[INTERFACE_COUNT] = {SX126X, SX128X};
const uint8_t interfaces[INTERFACE_COUNT] = {SX1262, SX1280};
const bool interface_cfg[INTERFACE_COUNT][3] = {
// SX1262
{
@ -1082,9 +1279,176 @@
const int pin_led_rx = LED_BLUE;
const int pin_led_tx = LED_GREEN;
#elif BOARD_MODEL == BOARD_TECHO
#define _PINNUM(port, pin) ((port) * 32 + (pin))
#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_INPUT true
#define HAS_SLEEP true
#define BLE_MANUFACTURER "LilyGO"
#define BLE_MODEL "T-Echo"
#define HAS_INPUT true
#define EEPROM_SIZE 296
#define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
#define CONFIG_UART_BUFFER_SIZE 32768
#define CONFIG_QUEUE_SIZE 6144
#define CONFIG_QUEUE_MAX_LENGTH 200
#define HAS_DISPLAY true
#define DISPLAY EINK_BW
#define HAS_BACKLIGHT true
#define DISPLAY_SCALE 1
#define LED_ON LOW
#define LED_OFF HIGH
#define PIN_LED_GREEN _PINNUM(1, 1)
#define PIN_LED_RED _PINNUM(1, 3)
#define PIN_LED_BLUE _PINNUM(0, 14)
#define PIN_VEXT_EN _PINNUM(0, 12)
const int pin_disp_cs = 30;
const int pin_disp_dc = 28;
const int pin_disp_reset = 2;
const int pin_disp_busy = 3;
const int pin_disp_en = -1;
const int pin_disp_sck = 31;
const int pin_disp_mosi = 29;
const int pin_disp_miso = -1;
const int pin_backlight = 43;
const int pin_btn_usr1 = _PINNUM(1, 10);
const int pin_btn_touch = _PINNUM(0, 11);
const int pin_reset = 25;
const int pin_cs = 24;
const int pin_sclk = 19;
const int pin_mosi = 22;
const int pin_miso = 23;
const int pin_busy = 17;
const int pin_dio = 20;
const int pin_tcxo_enable = 21;
const int pin_led_rx = PIN_LED_BLUE;
const int pin_led_tx = PIN_LED_RED;
#elif BOARD_MODEL == BOARD_HELTEC_T114
#define MODEM SX1262
#define HAS_EEPROM false
#define HAS_DISPLAY true
#define HAS_BLUETOOTH false
#define HAS_BLE true
#define HAS_CONSOLE false
#define HAS_PMU true
#define HAS_NP true
#define HAS_SD false
#define HAS_TCXO true
#define HAS_BUSY true
#define HAS_INPUT true
#define HAS_SLEEP true
#define DIO2_AS_RF_SWITCH true
#define CONFIG_UART_BUFFER_SIZE 6144
#define CONFIG_QUEUE_SIZE 6144
#define CONFIG_QUEUE_MAX_LENGTH 200
#define EEPROM_SIZE 296
#define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
#define BLE_MANUFACTURER "Heltec"
#define BLE_MODEL "T114"
#define PIN_T114_ADC_EN 6
#define PIN_VEXT_EN 21
// LED
#define LED_T114_GREEN 3
#define PIN_T114_LED 14
#define NP_M 1
const int pin_np = PIN_T114_LED;
// SPI
#define PIN_T114_MOSI 22
#define PIN_T114_MISO 23
#define PIN_T114_SCK 19
#define PIN_T114_SS 24
// SX1262
#define PIN_T114_RST 25
#define PIN_T114_DIO1 20
#define PIN_T114_BUSY 17
// TFT
#define DISPLAY_SCALE_OVERRIDE true
#define DISPLAY_SCALE 2
#define PIN_T114_TFT_MOSI 9
#define PIN_T114_TFT_MISO 11 // not connected
#define PIN_T114_TFT_SCK 8
#define PIN_T114_TFT_SS 11
#define PIN_T114_TFT_DC 12
#define PIN_T114_TFT_RST 2
#define PIN_T114_TFT_EN 3
#define PIN_T114_TFT_BLGT 15
// pins for buttons on Heltec T114
const int pin_btn_usr1 = 42;
// pins for sx1262 on Heltec T114
const int pin_reset = PIN_T114_RST;
const int pin_cs = PIN_T114_SS;
const int pin_sclk = PIN_T114_SCK;
const int pin_mosi = PIN_T114_MOSI;
const int pin_miso = PIN_T114_MISO;
const int pin_busy = PIN_T114_BUSY;
const int pin_dio = PIN_T114_DIO1;
const int pin_led_rx = 35;
const int pin_led_tx = 35;
const int pin_tcxo_enable = -1;
// pins for ST7789 display on Heltec T114
const int DISPLAY_DC = PIN_T114_TFT_DC;
const int DISPLAY_CS = PIN_T114_TFT_SS;
const int DISPLAY_MISO = PIN_T114_TFT_MISO;
const int DISPLAY_MOSI = PIN_T114_TFT_MOSI;
const int DISPLAY_CLK = PIN_T114_TFT_SCK;
const int DISPLAY_BL_PIN = PIN_T114_TFT_BLGT;
const int DISPLAY_RST = PIN_T114_TFT_RST;
#else
#error An unsupported nRF board was selected. Cannot compile RNode firmware.
#endif
#endif
#ifndef DISPLAY_SCALE
#define DISPLAY_SCALE 1
#endif
#ifndef HAS_BUSY
const int pin_busy = -1;
#endif
#ifndef LED_ON
#define LED_ON HIGH
#endif
#ifndef LED_OFF
#define LED_OFF LOW
#endif
// Default OCP value if not specified
// in board configuration
#ifndef OCP_TUNED
#define OCP_TUNED 0x38
#endif
#ifndef NP_M
#define NP_M 0.15
#endif
#endif

@ -65,11 +65,6 @@
// packet RSSI register
const int rssi_offset = 157;
// Default LoRa settings
const int lora_rx_turnaround_ms = 66;
const int lora_post_tx_yield_slots = 6;
#define LORA_CAD_SYMBOLS 3
// Operational variables
bool community_fw = true;
bool hw_ready = false;
@ -84,6 +79,7 @@
uint8_t model = 0x00;
uint8_t hwrev = 0x00;
int current_rssi = -292;
int last_rssi = -292;
uint8_t last_rssi_raw = 0x00;
uint8_t last_snr_raw = 0x80;
@ -108,8 +104,21 @@
uint32_t stat_rx = 0;
uint32_t stat_tx = 0;
unsigned long last_tx = 0;
unsigned long last_rx = 0;
bool stat_signal_detected = false;
bool stat_signal_synced = false;
bool stat_rx_ongoing = false;
bool dcd = false;
bool dcd_led = false;
bool dcd_waiting = false;
long dcd_wait_until = 0;
uint16_t dcd_count = 0;
uint16_t dcd_threshold = 2;
uint32_t last_status_update = 0;
uint32_t last_dcd = 0;
uint32_t last_rx = 0;
uint32_t last_tx = 0;
// Power management
#define BATTERY_STATE_UNKNOWN 0x00
@ -125,6 +134,7 @@
uint8_t battery_state = 0x00;
uint8_t display_intensity = 0xFF;
uint8_t display_addr = 0xFF;
volatile bool display_updating = false;
bool display_blanking_enabled = false;
bool display_diagnostics = true;
bool device_init_done = false;

@ -21,7 +21,7 @@ pages-debug:
sourcepack:
@echo Packing firmware sources...
zip --junk-paths -r build/pkg/rnode_firmware.zip ../arduino-cli.yaml ../src/ble/BLESerial.cpp ../src/ble/BLESerial.h ../Bluetooth.h ../Boards.h ../Config.h ../Console.h ../Device.h ../Display.h ../Framing.h ../Graphics.h .../Input.h ../Interfaces.h ../LICENSE ../Makefile ../src/misc/FIFOBuffer.c ../src/misc/FIFOBuffer.h ../src/misc/MD5.cpp ../src/misc/MD5.h ../partition_hashes ../Power.h ../README.md ../release_hashes.py ../RNode_Firmware_CE.ino ../ROM.h ../Radio.cpp ../Radio.hpp ../Utilities.h ../esp32_btbufs.py
cd .. && zip -r build/pkg/rnode_firmware.zip * -x Builds/\* Console/\* Documentation/images/\* Documentation/RNode_v1_Manual.pdf Graphics/\* Python\ Module/\* Release/\* build/\* partition_hashes
data:
@echo Including assets...

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 33 KiB

@ -4,10 +4,10 @@ import sys
import shutil
packages = {
"rns": "rns-0.8.2-py3-none-any.whl",
"nomadnet": "nomadnet-0.5.4-py3-none-any.whl",
"lxmf": "lxmf-0.5.5-py3-none-any.whl",
"rnsh": "rnsh-0.1.4-py3-none-any.whl",
"rns": "rns-0.9.1-py3-none-any.whl",
"nomadnet": "nomadnet-0.5.7-py3-none-any.whl",
"lxmf": "lxmf-0.6.0-py3-none-any.whl",
"rnsh": "rnsh-0.1.5-py3-none-any.whl",
}
DEFAULT_TITLE = "RNode Bootstrap Console"
@ -174,7 +174,7 @@ mf.write(help_redirect)
mf.close()
def optimise_manual(path):
pm = 60
pm = 90
scale_imgs = [
("_images/board_rnodev2.png", pm),
("_images/board_rnode.png", pm),

@ -2,7 +2,6 @@
[title]: <> (How To Make Your Own RNodes)
[image]: <> (images/g3p.webp)
[excerpt]: <> (This article will outline the general process, and provide the information you need, for building your own RNode from a few basic modules. The RNode will be functionally identical to a commercially purchased board.)
<div class="article_date">{DATE}</div>
# How To Make Your Own RNodes
This article will outline the general process, and provide the information you need, for building your own RNode from a few basic modules. The RNode will be functionally identical to a purchased device.
@ -31,10 +30,9 @@ Currently, the RNode firmware supports a variety of different microcontrollers,
Regarding the LoRa transceiver module, there is going to be an almost overwhelming amount of options to choose from. To narrow it down, here are the essential characteristics to look for:
- The RNode firmware needs a module based on the **Semtech SX1276** or **Semtech SX1278** LoRa transceiver IC. These come in several different variants, for all frequency bands from about 150 MHz to about 1100 MHz.
- Support for **SX1262**, **SX1268** and **SX1280**-based modules is coming soon, but until that is released, only **SX1276** and **SX1278** modules will work.
- The RNode firmware needs a module based on the **Semtech SX1276**, **Semtech SX1278**, **SX1262**, **SX1268** and **SX1280** LoRa transceiver ICs. These come in several different variants, for all frequency bands from about 150 MHz to 2500 MHz.
- The module *must* expose the direct SPI bus to the transceiver chip. UART based modules that add their own communications layer will not work.
- The module must also expose the *reset* line of the chip, and provide the **DIO0** interrupt signal *from* the chip.
- The module must also expose the *reset* line of the chip, and provide the **DIO0** (or other relevant) interrupt signal *from* the chip.
- As mentioned above, the module must be logic-level compatible with the microcontroller you are using, unless you want to add a level-shifter. Resistor divider arrays will most likely not work here, due to the bus speeds required.
Keeping those things in mind, you should be able to select a suitable combination of microcontroller board and transceiver module.
@ -56,12 +54,17 @@ In the photo above I used an Adafruit Feather ESP32 board and a ModTronix inAir4
9. Connect the *DIO0* pin of the transceiver module to the *DIO0 interrupt pin* of the microcontroller board.
10. You can optionally connect transmit and receiver LEDs to the corresponding pins of the microcontroller board.
The pin layouts of your transceiver module and microcontroller board will vary, but you can look up the correct pin assignments for your processor type and board layout in the `Config.h` file of the [RNode Firmware]({ASSET_PATH}pkg/rnode_firmware.zip).
The pin layouts of your transceiver module and microcontroller board will vary, but you can look up the correct pin assignments for your processor type and board layout in the [Config.h](https://github.com/markqvist/RNode_Firmware/blob/master/Config.h) file of the [RNode Firmware](https://unsigned.io/rnode_firmware).
## Loading the Firmware
Once the hardware is assembled, you are ready to load the firmware onto the board and configure the configuration parameters in the boards EEPROM. Luckily, this process is completely automated by the [RNode Configuration Utility]({ASSET_PATH}m/using.html#the-rnodeconf-utility).
### Loading the Firmware
Once the hardware is assembled, you are ready to load the firmware onto the board and configure the configuration parameters in the boards EEPROM. Luckily, this process is completely automated by the [RNode Configuration Utility](https://markqvist.github.io/Reticulum/manual/using.html#the-rnodeconf-utility). To prepare for loading the firmware, make sure that `python` and `pip` is installed on your system, then install the `rns` package (which includes the `rnodeconf` program) by issuing the command:
The `rnodeconf` program is included in the `rns` package. Please read [these instructions]({ASSET_PATH}s_rns.html) for more information on how to install it from this repository, or from the Internet. If installation goes well, you can now move on to the next step.
```txt
pip install rns
```
If installation goes well, you can now move on to the next step.
> *Take Care*: A LoRa transceiver module **must** be connected to the board for the firmware to start and accept commands. If the firmware does not verify that the correct transceiver is available on the SPI bus, execution is stopped, and the board will not accept commands. If you find the board unresponsive after installing the firmware, or EEPROM configuration fails, double-check your transceiver module wiring!
@ -73,24 +76,6 @@ rnodeconf --autoinstall
The installer will now ask you to insert the device you want to set up, scan for connected serial ports, and ask you a number of questions regarding the device. When it has the information it needs, it will install the correct firmware and configure the necessary parameters in the device EEPROM for it to function properly.
> **Please Note!** If you are connected to the Internet while installing, the autoinstaller will automatically download any needed firmware files to a local cache before installing.
> If you do not have an active Internet connection while installing, you can extract and use the firmware from this device instead. This will **only** work if you are building the same type of RNode as the device you are extracting from, as the firmware has to match the targeted board and hardware configuration.
If you need to extract the firmware from an existing RNode, run the following command:
```
rnodeconf --extract
```
If `rnodeconf` finds a working RNode, it will extract and save the firmware from the device for later use. You can then run the auto-installer with the `--use-extracted` option to use the locally extracted file:
```
rnodeconf --autoinstall --use-extracted
```
This also works for updating the firmware on existing RNodes, so you can extract a newer firmware from one RNode, and deploy it onto other RNodes using the same method. Just use the `--update` option instead of `--autoinstall`.
If the install goes well, you will be greated with a success message telling you that your device is now ready. To confirm everything is OK, you can query the device info with:
```txt

@ -147,9 +147,6 @@ uint32_t retrieve_application_size() {
uint8_t bytes[4];
memcpy(bytes, (const void*)IMG_SIZE_START, 4);
uint32_t fw_len = bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24;
Serial.println("FIRMWARE LEN:");
Serial.print(fw_len);
Serial.flush();
return fw_len;
}

File diff suppressed because it is too large Load Diff

@ -44,6 +44,7 @@
#define CMD_STAT_CHTM 0x25
#define CMD_STAT_PHYPRM 0x26
#define CMD_STAT_BAT 0x27
#define CMD_STAT_CSMA 0x28
#define CMD_BLINK 0x30
#define CMD_RANDOM 0x40
@ -51,12 +52,16 @@
#define CMD_FB_READ 0x42
#define CMD_FB_WRITE 0x43
#define CMD_FB_READL 0x44
#define CMD_DISP_READ 0x66
#define CMD_DISP_INT 0x45
#define CMD_DISP_ADDR 0x63
#define CMD_DISP_BLNK 0x64
#define CMD_DISP_ROT 0x67
#define CMD_DISP_RCND 0x68
#define CMD_NP_INT 0x65
#define CMD_BT_CTRL 0x46
#define CMD_BT_PIN 0x62
#define CMD_DIS_IA 0x69
#define CMD_BOARD 0x47
#define CMD_PLATFORM 0x48

File diff suppressed because it is too large Load Diff

@ -1,7 +1,4 @@
#define SX127X 0x00
#define SX1276 0x01
#define SX1278 0x02
#define SX126X 0x10
#define SX1262 0x11
#define SX128X 0x20
#define SX1280 0x21
#define SX1276 0x00
#define SX1278 0x01
#define SX1262 0x10
#define SX1280 0x20

@ -23,7 +23,7 @@ VFLAG =-v
endif
COMMON_BUILD_FLAGS = $(VFLAG) -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152"
COMMON_ESP_UPLOAD_FlAGS = $(VFLAG) --chip esp32 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000
COMMON_ESP_UPLOAD_FLAGS = $(VFLAG) --chip esp32 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000
all: release
@ -50,9 +50,12 @@ prep-esp32:
prep-nrf:
arduino-cli core install adafruit:nrf52 --config-file arduino-cli.yaml
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 lib install "Crypto"
arduino-cli lib install "Adafruit GFX Library"
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 pyserial rns --upgrade --user --break-system-packages # This looks scary, but it's actually just telling pip to install packages as a user instead of trying to install them systemwide, which bypasses the "externally managed environment" error.
pip install adafruit-nrfutil --upgrade --user --break-system-packages # This looks scary, but it's actually just telling pip to install packages as a user instead of trying to install them systemwide, which bypasses the "externally managed environment" error.
@ -79,13 +82,8 @@ firmware-tbeam: check_bt_buffers
firmware-tbeam_sx1262: check_bt_buffers
arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DBOARD_VARIANT=0xE8\""
firmware-techo: firmware-techo4 firmware-techo9
firmware-techo4:
arduino-cli compile --fqbn adafruit:nrf52:pca10056 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\" \"-DBOARD_VARIANT=0x16\""
firmware-techo9:
arduino-cli compile --fqbn adafruit:nrf52:pca10056 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\" \"-DBOARD_VARIANT=0x17\""
firmware-techo:
arduino-cli compile --fqbn adafruit:nrf52:pca10056 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\""
firmware-t3s3:
arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x43\" \"-DBOARD_VARIANT=0xAB\""
@ -126,6 +124,9 @@ firmware-heltec32_v2_extled: check_bt_buffers
firmware-heltec32_v3:
arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V3 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3A\""
firmware-heltec_w_paper:
arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V3 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3E\""
firmware-rnode_ng_20: check_bt_buffers
arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x40\""
@ -147,6 +148,8 @@ firmware-rak4631_sx1280:
firmware-opencom-xl:
arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x52\" \"-DBOARD_VARIANT=0x21\""
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\""
upload-tbeam:
arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:t-beam
@ -155,40 +158,42 @@ upload-tbeam:
@sleep 3
python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) $(COMMON_ESP_UPLOAD_FLAGS) ./Release/console_image.bin
upload-techo:
arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn adafruit:nrf52:pca10056
unzip -o build/adafruit.nrf52.pca10056/RNode_Firmware_CE.ino.zip -d build/adafruit.nrf52.pca10056
rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(sha256sum ./build/adafruit.nrf52.pca10056/RNode_Firmware_CE.ino.bin | grep -o '^\S*')
upload-tbeam_sx1262:
arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:t-beam
@sleep 1
rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.t-beam/RNode_Firmware_CE.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-lora32_v10:
arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:ttgo-lora32
@sleep 1
rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin)
@sleep 3
python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FlAGS) ./Release/console_image.bin
python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FLAGS) ./Release/console_image.bin
upload-lora32_v20:
arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:ttgo-lora32
@sleep 1
rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin)
@sleep 3
python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FlAGS) ./Release/console_image.bin
python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FLAGS) ./Release/console_image.bin
upload-lora32_v21:
arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:ttgo-lora32
@sleep 1
rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin)
@sleep 3
python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) $(COMMON_ESP_UPLOAD_FlAGS) ./Release/console_image.bin
python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) $(COMMON_ESP_UPLOAD_FLAGS) ./Release/console_image.bin
upload-heltec32_v2:
arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:heltec_wifi_lora_32_V2
@sleep 1
rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware_CE.ino.bin)
@sleep 3
python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FlAGS) ./Release/console_image.bin
python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FLAGS) ./Release/console_image.bin
upload-heltec32_v3:
upload-heltec_w_paper upload-heltec32_v3:
arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:heltec_wifi_lora_32_V3
@sleep 1
rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware_CE.ino.bin)
@ -200,40 +205,34 @@ upload-tdeck:
@sleep 1
rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin)
@sleep 3
python ./Release/esptool/esptool.py --chip esp32-s3 --port $(or $(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 --port $(or $(port), /dev/ttyACM0) --chip esp32-s3 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
upload-tbeam_supreme:
arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:esp32s3
@sleep 1
rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin)
@sleep 3
python ./Release/esptool/esptool.py --chip esp32-s3 --port $(or $(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 --port $(or $(port), /dev/ttyACM0) --chip esp32-s3 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
upload-rnode_ng_20:
arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:ttgo-lora32
@sleep 1
rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin)
@sleep 3
python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FlAGS) ./Release/console_image.bin
python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FLAGS) ./Release/console_image.bin
upload-rnode_ng_21:
arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:ttgo-lora32
@sleep 1
rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin)
@sleep 3
python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) $(COMMON_ESP_UPLOAD_FlAGS) ./Release/console_image.bin
python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) $(COMMON_ESP_UPLOAD_FLAGS) ./Release/console_image.bin
upload-t3s3:
@echo
@echo Put board into flashing mode by holding BOOT button while momentarily pressing the RESET button. Hit enter when done.
@read
arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:esp32s3
@sleep 2
python ./Release/esptool/esptool.py --chip esp32s3 --port $(or $(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
@echo
@echo Press the RESET button on the board now, and hit enter
@read
@sleep 1
python ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) --chip esp32-s3 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
@sleep 3
rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin)
upload-featheresp32:
@ -253,7 +252,17 @@ upload-e22_esp32:
@sleep 1
rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32/RNode_Firmware_CE.ino.bin)
@sleep 3
python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FlAGS) ./Release/console_image.bin
python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FLAGS) ./Release/console_image.bin
upload-heltec_t114:
arduino-cli upload -p /dev/ttyACM0 --fqbn Heltec_nRF52:Heltec_nRF52:HT-n5262
@sleep 1
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
rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes from_device /dev/ttyACM0)
release: console-site spiffs-image $(shell grep ^release- Makefile | cut -d: -f1)
@ -351,51 +360,52 @@ release-heltec32_v2: check_bt_buffers
release-heltec32_v3:
arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V3 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3A\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_heltec32v3.boot_app0
cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware.ino.bin build/rnode_firmware_heltec32v3.bin
cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_heltec32v3.bootloader
cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_heltec32v3.partitions
cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware_CE.ino.bin build/rnode_firmware_heltec32v3.bin
cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_heltec32v3.bootloader
cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_heltec32v3.partitions
zip --junk-paths ./Release/rnode_firmware_heltec32v3.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_heltec32v3.boot_app0 build/rnode_firmware_heltec32v3.bin build/rnode_firmware_heltec32v3.bootloader build/rnode_firmware_heltec32v3.partitions
rm -r build
release-heltec_w_paper:
arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V3 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3E\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_heltecwpaper.boot_app0
cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware_CE.ino.bin build/rnode_firmware_heltecwpaper.bin
cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_heltecwpaper.bootloader
cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_heltecwpaper.partitions
zip --junk-paths ./Release/rnode_firmware_heltecwpaper.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_heltecwpaper.boot_app0 build/rnode_firmware_heltecwpaper.bin build/rnode_firmware_heltecwpaper.bootloader build/rnode_firmware_heltecwpaper.partitions
rm -r build
release-heltec32_v2_extled: check_bt_buffers
arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V2 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x38\" \"-DEXTERNAL_LEDS=true\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_heltec32v2.boot_app0
cp build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware.ino.bin build/rnode_firmware_heltec32v2.bin
cp build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_heltec32v2.bootloader
cp build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware.ino.partitions.bin build/rnode_firmware_heltec32v2.partitions
cp build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware_CE.ino.bin build/rnode_firmware_heltec32v2.bin
cp build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_heltec32v2.bootloader
cp build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_heltec32v2.partitions
zip --junk-paths ./Release/rnode_firmware_heltec32v2.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_heltec32v2.boot_app0 build/rnode_firmware_heltec32v2.bin build/rnode_firmware_heltec32v2.bootloader build/rnode_firmware_heltec32v2.partitions
rm -r build
release-rnode_ng_20: check_bt_buffers
arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x40\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_ng20.boot_app0
cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.bin build/rnode_firmware_ng20.bin
cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_ng20.bootloader
cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.partitions.bin build/rnode_firmware_ng20.partitions
cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin build/rnode_firmware_ng20.bin
cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_ng20.bootloader
cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_ng20.partitions
zip --junk-paths ./Release/rnode_firmware_ng20.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_ng20.boot_app0 build/rnode_firmware_ng20.bin build/rnode_firmware_ng20.bootloader build/rnode_firmware_ng20.partitions
rm -r build
release-rnode_ng_21: check_bt_buffers
arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x41\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_ng21.boot_app0
cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.bin build/rnode_firmware_ng21.bin
cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_ng21.bootloader
cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.partitions.bin build/rnode_firmware_ng21.partitions
cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin build/rnode_firmware_ng21.bin
cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_ng21.bootloader
cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_ng21.partitions
zip --junk-paths ./Release/rnode_firmware_ng21.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_ng21.boot_app0 build/rnode_firmware_ng21.bin build/rnode_firmware_ng21.bootloader build/rnode_firmware_ng21.partitions
rm -r build
release-techo: release-techo4 release-techo9
release-techo4:
arduino-cli compile --fqbn adafruit:nrf52:pca10056 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\" \"-DBOARD_VARIANT=0x16\""
cp build/adafruit.nrf52.pca10056/RNode_Firmware_CE.ino.hex build/rnode_firmware_techo4.hex
adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_techo4.hex Release/rnode_firmware_techo4.zip
rm -r build
release-techo9:
arduino-cli compile --fqbn adafruit:nrf52:pca10056 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\" \"-DBOARD_VARIANT=0x17\""
cp build/adafruit.nrf52.pca10056/RNode_Firmware_CE.ino.hex build/rnode_firmware_techo9.hex
adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_techo9.hex Release/rnode_firmware_techo9.zip
release-techo:
arduino-cli compile --fqbn adafruit:nrf52:pca10056 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\""
cp build/adafruit.nrf52.pca10056/RNode_Firmware_CE.ino.hex build/rnode_firmware_techo.hex
adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_techo.hex Release/rnode_firmware_techo.zip
rm -r build
release-t3s3:
@ -419,31 +429,49 @@ release-e22_esp32:
release-t3s3_sx126x:
arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_MODEL=0xA1\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_t3s3_sx126x.boot_app0
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin build/rnode_firmware_t3s3_sx126x.bin
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_t3s3_sx126x.bootloader
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_t3s3_sx126x.partitions
cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin build/rnode_firmware_t3s3_sx126x.bin
cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_t3s3_sx126x.bootloader
cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_t3s3_sx126x.partitions
zip --junk-paths ./Release/rnode_firmware_t3s3_sx126x.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_t3s3_sx126x.boot_app0 build/rnode_firmware_t3s3_sx126x.bin build/rnode_firmware_t3s3_sx126x.bootloader build/rnode_firmware_t3s3_sx126x.partitions
rm -r build
release-tdeck:
arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3B\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_tdeck.boot_app0
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin build/rnode_firmware_tdeck.bin
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_tdeck.bootloader
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_tdeck.partitions
cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin build/rnode_firmware_tdeck.bin
cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_tdeck.bootloader
cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_tdeck.partitions
zip --junk-paths ./Release/rnode_firmware_tdeck.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_tdeck.boot_app0 build/rnode_firmware_tdeck.bin build/rnode_firmware_tdeck.bootloader build/rnode_firmware_tdeck.partitions
rm -r build
release-t3s3_sx1280_pa:
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=0x42\" \"-DMODEM=0x04\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_t3s3_sx1280_pa.boot_app0
cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin build/rnode_firmware_t3s3_sx1280_pa.bin
cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_t3s3_sx1280_pa.bootloader
cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_t3s3_sx1280_pa.partitions
zip --junk-paths ./Release/rnode_firmware_t3s3_sx1280_pa.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_t3s3_sx1280_pa.boot_app0 build/rnode_firmware_t3s3_sx1280_pa.bin build/rnode_firmware_t3s3_sx1280_pa.bootloader build/rnode_firmware_t3s3_sx1280_pa.partitions
rm -r build
release-t3s3_sx127x:
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=0x42\" \"-DMODEM=0x01\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_t3s3_sx127x.boot_app0
cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin build/rnode_firmware_t3s3_sx127x.bin
cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_t3s3_sx127x.bootloader
cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_t3s3_sx127x.partitions
zip --junk-paths ./Release/rnode_firmware_t3s3_sx127x.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_t3s3_sx127x.boot_app0 build/rnode_firmware_t3s3_sx127x.bin build/rnode_firmware_t3s3_sx127x.bootloader build/rnode_firmware_t3s3_sx127x.partitions
rm -r build
release-tbeam_supreme:
arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3D\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_tbeam_supreme.boot_app0
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin build/rnode_firmware_tbeam_supreme.bin
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_tbeam_supreme.bootloader
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_tbeam_supreme.partitions
cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin build/rnode_firmware_tbeam_supreme.bin
cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_tbeam_supreme.bootloader
cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_tbeam_supreme.partitions
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-featheresp32: check_bt_buffers
arduino-cli compile --fqbn esp32:esp32:featheresp32 $(COMMON_BUILD_FLAGS) --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
@ -479,3 +507,8 @@ release-opencom-xl:
cp build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.hex build/rnode_firmware_opencom_xl.hex
adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_opencom_xl.hex Release/rnode_firmware_opencom_xl.zip
rm -r build
release-heltec_t114:
arduino-cli compile --fqbn Heltec_nRF52:Heltec_nRF52:HT-n5262 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3C\""
cp build/Heltec_nRF52.Heltec_nRF52.HT-n5262/RNode_Firmware_CE.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

@ -82,6 +82,22 @@
int bat_charged_samples = 0;
bool bat_voltage_dropping = false;
float bat_delay_v = 0;
#elif BOARD_MODEL == BOARD_T3S3
#define BAT_V_MIN 3.15
#define BAT_V_MAX 4.217
#define BAT_V_CHG 4.48
#define BAT_V_FLOAT 4.33
#define BAT_SAMPLES 5
const uint8_t pin_vbat = 1;
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_TDECK
#define BAT_V_MIN 3.15
#define BAT_V_MAX 4.3
@ -115,6 +131,39 @@
bool bat_voltage_dropping = false;
float bat_delay_v = 0;
float bat_state_change_v = 0;
#elif BOARD_MODEL == BOARD_HELTEC_T114
#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 = 4;
const uint8_t pin_ctrl = 6;
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
#define BAT_V_CHG 4.48
#define BAT_V_FLOAT 4.33
#define BAT_SAMPLES 7
const uint8_t pin_vbat = 4;
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;
#endif
uint32_t last_pmu_update = 0;
@ -125,14 +174,20 @@ uint8_t pmu_rc = 0;
void kiss_indicate_battery();
void measure_battery() {
#if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_TDECK
#if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_TDECK || BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_HELTEC_T114 || BOARD_MODEL == BOARD_TECHO
battery_installed = true;
battery_indeterminate = true;
#if BOARD_MODEL == BOARD_HELTEC32_V3
float battery_measurement = (float)(analogRead(pin_vbat)) * 0.0041;
#elif BOARD_MODEL == BOARD_T3S3
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_TECHO
float battery_measurement = (float)(analogRead(pin_vbat)) * 0.007067;
#else
float battery_measurement = (float)(analogRead(pin_vbat)) / 4095.0*2.0*3.3*1.1;
float battery_measurement = (float)(analogRead(pin_vbat)) / 4095.0*7.26;
#endif
bat_v_samples[bat_samples_count%BAT_SAMPLES] = battery_measurement;
@ -197,13 +252,14 @@ void measure_battery() {
}
}
#if MCU_VARIANT == MCU_NRF52
if (bt_state != BT_STATE_OFF) { blebas.write(battery_percent); }
#endif
// if (bt_state == BT_STATE_CONNECTED) {
// SerialBT.printf("Bus voltage %.3fv. Unfiltered %.3fv.", battery_voltage, bat_v_samples[BAT_SAMPLES-1]);
// if (bat_voltage_dropping) {
// SerialBT.printf(" Voltage is dropping. Percentage %.1f%%.", battery_percent);
// } else {
// SerialBT.printf(" Voltage is not dropping. Percentage %.1f%%.", battery_percent);
// }
// if (bat_voltage_dropping) { SerialBT.printf(" Voltage is dropping. Percentage %.1f%%.", battery_percent); }
// else { SerialBT.printf(" Voltage is not dropping. Percentage %.1f%%.", battery_percent); }
// if (battery_state == BATTERY_STATE_DISCHARGING) { SerialBT.printf(" Battery discharging. delay_v %.3fv", bat_delay_v); }
// if (battery_state == BATTERY_STATE_CHARGING) { SerialBT.printf(" Battery charging. delay_v %.3fv", bat_delay_v); }
// if (battery_state == BATTERY_STATE_CHARGED) { SerialBT.print(" Battery is charged."); }
@ -378,13 +434,17 @@ void update_pmu() {
}
bool init_pmu() {
#if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_TDECK
#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
pinMode(pin_vbat, INPUT);
return true;
#elif BOARD_MODEL == BOARD_HELTEC32_V3
pinMode(pin_ctrl,OUTPUT);
digitalWrite(pin_ctrl, LOW);
return true;
#elif BOARD_MODEL == BOARD_HELTEC_T114
pinMode(pin_ctrl,OUTPUT);
digitalWrite(pin_ctrl, HIGH);
return true;
#elif BOARD_MODEL == BOARD_TBEAM
Wire.begin(I2C_SDA, I2C_SCL);

@ -24,7 +24,7 @@ The latest release, installable through `rnodeconf`, is version `1.73`. This rel
- Fix TNC EEPROM settings not being saved - courtesy of @attermann
- Fix ESP32 linker errors - BSP version is now fixed at 2.0.17, using the older crosstool-ng linker from previous versions (2021r1)
You must have at least version `2.1.3` of `rnodeconf` installed to update the RNode Firmware to version `1.73`. Get it by updating the `rns` package to at least version `0.6.4`.
You must have at least version `2.1.3` of `rnodeconf` installed to update your RNode Firmware install to version `1.73`. Get it by updating the `rns` package to at least version `0.6.4`.
## Supported products and boards
@ -39,13 +39,33 @@ You must have at least version `2.1.3` of `rnodeconf` installed to update the RN
| :--- | :---: | :---: | :---: | :---: |
| RAK4631 | [Buy here](https://store.rakwireless.com/products/rak4631-lpwan-node?m=5&h=wisblock-core) | SX1262 | nRF52 |
| LilyGO T-BEAM v1.1 | [Buy here](https://www.lilygo.cc/products/t-beam-v1-1-esp32-lora-module) | SX1276/8 or SX1262 | ESP32 |
| LilyGO T-Beam Supreme | [Buy here](https://lilygo.cc/products/t-beam-supreme) | SX1262 | ESP32-S3 |
| LilyGO LoRa32 v1.0 | [Buy here](https://www.lilygo.cc/products/lora32-v1-0) | SX1276/8 | ESP32 |
| LilyGO LoRa32 v2.0 | No link | SX1276/8 | ESP32 | Discontinued? |
| LilyGO LoRa32 v2.1 | [Buy here](https://www.lilygo.cc/products/lora3) | SX1276/8 | ESP32 | With and without TCXO |
| LilyGO T-Deck | [Buy here](https://lilygo.cc/products/t-deck) | SX1262 | ESP32-S3 |
| Heltec LoRa32 v2 | No link | SX1276/8 | ESP32 | Discontinued? |
| Heltec LoRa32 v3 | [Buy here](https://heltec.org/project/wifi-lora-32-v3/) | SX1262 | ESP32 |
| Heltec Wireless Paper | [Buy here](https://heltec.org/project/wireless-paper/) | SX1262 | ESP32-S3 |
| Heltec T114 | [Buy here](https://heltec.org/project/mesh-node-t114/) | SX1262 | nRF52 |
| Homebrew ESP32 boards | | Any supported | ESP32 | This can be any board with an Adafruit Feather (or generic) ESP32 chip |
- 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 T114 devices
- RAK4631 devices
- 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
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](Documentation/CONTRIBUTING.md) and help create a board definition and pin mapping for it!
<!--<img src="Documentation/images/devboards_1.webp" width="100%"/>-->
@ -108,6 +128,8 @@ pip install rns --upgrade
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)

@ -105,12 +105,21 @@ void setup() {
pinMode(DISPLAY_BL_PIN, OUTPUT);
#endif
#elif MCU_VARIANT == MCU_NRF52
#if BOARD_MODEL == BOARD_TECHO
delay(200);
pinMode(PIN_VEXT_EN, OUTPUT);
digitalWrite(PIN_VEXT_EN, HIGH);
pinMode(pin_btn_usr1, INPUT_PULLUP);
pinMode(pin_btn_touch, INPUT_PULLUP);
pinMode(PIN_LED_RED, OUTPUT);
pinMode(PIN_LED_GREEN, OUTPUT);
pinMode(PIN_LED_BLUE, OUTPUT);
delay(200);
#endif
#if MCU_VARIANT == MCU_NRF52
if (!eeprom_begin()) {
Serial.write("EEPROM initialisation failed.\r\n");
}
if (!eeprom_begin()) { Serial.write("EEPROM initialisation failed.\r\n"); }
#endif
// Seed the PRNG for CSMA R-value selection
@ -135,7 +144,7 @@ void setup() {
led_init();
#endif
#if BOARD_MODEL != BOARD_RAK4631 && BOARD_MODEL != BOARD_RNODE_NG_22 && BOARD_MODEL != BOARD_TBEAM_S_V1 && BOARD_MODEL != BOARD_T3S3 && BOARD_MODEL != BOARD_TECHO && BOARD_MODEL != BOARD_OPENCOM_XL
#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_OPENCOM_XL
// Some boards need to wait until the hardware UART is set up before booting
// the full firmware. In the case of the RAK4631/TECHO, the line below will wait
// until a serial connection is actually established with a master. Thus, it
@ -187,7 +196,6 @@ void setup() {
// Create and configure interface objects
for (uint8_t i = 0; i < INTERFACE_COUNT; i++) {
switch (interfaces[i]) {
case SX126X:
case SX1262:
{
sx126x* obj;
@ -209,7 +217,6 @@ void setup() {
break;
}
case SX127X:
case SX1276:
case SX1278:
{
@ -230,7 +237,6 @@ void setup() {
break;
}
case SX128X:
case SX1280:
{
sx128x* obj;
@ -257,16 +263,20 @@ void setup() {
}
}
#if BOARD_MODEL == BOARD_T3S3 && BOARD_VARIANT == MODEL_AC
// Fix weird radio not found bug on T3S3 SX1280
delay(300);
interface_obj[0]->reset();
delay(100);
#endif
// Check installed transceiver chip(s) and probe boot parameters. If any of
// the configured modems cannot be initialised, do not boot
for (int i = 0; i < INTERFACE_COUNT; i++) {
switch (interfaces[i]) {
case SX126X:
case SX1262:
case SX127X:
case SX1276:
case SX1278:
case SX128X:
case SX1280:
selected_radio = interface_obj[i];
break;
@ -277,6 +287,9 @@ void setup() {
}
if (selected_radio->preInit()) {
modems_installed = true;
#if HAS_INPUT
// Skip quick-reset console activation
#else
uint32_t lfr = selected_radio->getFrequency();
if (lfr == 0) {
// Normal boot
@ -291,6 +304,7 @@ void setup() {
// Unknown boot
}
selected_radio->setFrequency(M_FRQ_S);
#endif
} else {
modems_installed = false;
}
@ -306,13 +320,23 @@ void setup() {
if (eeprom_read(eeprom_addr(ADDR_CONF_DSET)) != CONF_OK_BYTE) {
#endif
eeprom_update(eeprom_addr(ADDR_CONF_DSET), CONF_OK_BYTE);
#if BOARD_MODEL == BOARD_TECHO
eeprom_update(eeprom_addr(ADDR_CONF_DINT), 0x03);
#else
eeprom_update(eeprom_addr(ADDR_CONF_DINT), 0xFF);
#endif
}
#if DISPLAY == EINK_BW || DISPLAY == EINK_3C
// Poll and process incoming serial commands whilst e-ink display is
// refreshing to make device still seem responsive
#if BOARD_MODEL == BOARD_OPENCOM_XL && (DISPLAY == EINK_BW || DISPLAY == EINK_3C)
// On this board it isn't possible to run the main loop whilst the
// display is updating as the SPI pins are shared between the display and
// secondary modem. Because running the main loop causes a lockup, we
// just run the serial poll loop instead.
display_add_callback(process_serial);
#elif DISPLAY == EINK_BW || DISPLAY == EINK_3C
display_add_callback(work_while_waiting);
#endif
display_unblank();
disp_ready = display_init();
update_display();
#endif
@ -336,6 +360,25 @@ void setup() {
kiss_indicate_reset();
}
for (int i = 0; i < INTERFACE_COUNT; i++) {
selected_radio = interface_obj[i];
if (interfaces[i] == SX1280) {
selected_radio->setAvdInterference(false);
}
if (selected_radio->getAvdInterference()) {
#if HAS_EEPROM
uint8_t ia_conf = EEPROM.read(eeprom_addr(ADDR_CONF_DIA));
if (ia_conf == 0x00) { selected_radio->setAvdInterference(true); }
else { selected_radio->setAvdInterference(false); }
#elif MCU_VARIANT == MCU_NRF52
uint8_t ia_conf = eeprom_read(eeprom_addr(ADDR_CONF_DIA));
if (ia_conf == 0x00) { selected_radio->setAvdInterference(true); }
else { selected_radio->setAvdInterference(false); }
#endif
}
}
// Validate board health, EEPROM and config
validate_status();
}
@ -349,7 +392,6 @@ void lora_receive(RadioInterface* radio) {
}
inline void kiss_write_packet(int index) {
// Print index of interface the packet came from
serial_write(FEND);
serial_write(CMD_SEL_INT);
@ -516,6 +558,7 @@ bool startRadio(RadioInterface* radio) {
update_radio_lock(radio);
if (modems_installed && !console_active) {
if (!radio->getRadioOnline()) {
if (!radio->getRadioLock() && hw_ready) {
if (!radio->begin()) {
// The radio could not be started.
@ -557,12 +600,15 @@ bool startRadio(RadioInterface* radio) {
return true;
}
}
}
void stopRadio(RadioInterface* radio) {
if (radio->getRadioOnline()) {
radio->end();
sort_interfaces();
kiss_indicate_radiostate(radio);
}
}
void update_radio_lock(RadioInterface* radio) {
if (radio->getFrequency() != 0 && radio->getSignalBandwidth() != 0 && radio->getTxPower() != 0xFF && radio->getSpreadingFactor() != 0) {
@ -574,14 +620,14 @@ void update_radio_lock(RadioInterface* radio) {
// Check if the queue is full for the selected radio.
// Returns true if full, false if not
bool queueFull(RadioInterface* radio) {
bool queue_full(RadioInterface* radio) {
return (queue_height[radio->getIndex()] >= (CONFIG_QUEUE_MAX_LENGTH) || queued_bytes[radio->getIndex()] >= (getQueueSize(radio->getIndex())));
}
volatile bool queue_flushing = false;
// Flushes all packets for the interface
void flushQueue(RadioInterface* radio) {
void flush_queue(RadioInterface* radio) {
uint8_t index = radio->getIndex();
if (!queue_flushing) {
queue_flushing = true;
@ -607,13 +653,47 @@ void flushQueue(RadioInterface* radio) {
lora_receive(radio);
led_tx_off();
radio->setPostTxYieldTimeout(millis()+(lora_post_tx_yield_slots*selected_radio->getCSMASlotMS()));
}
queue_height[index] = 0;
queued_bytes[index] = 0;
selected_radio->updateAirtime();
queue_flushing = false;
}
void pop_queue(RadioInterface* radio) {
uint8_t index = radio->getIndex();
if (!queue_flushing) {
queue_flushing = true;
led_tx_on(); uint16_t processed = 0;
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
if (!fifo16_isempty(&packet_starts[index])) {
#else
if (!fifo16_isempty_locked(&packet_starts[index])) {
#endif
uint16_t start = fifo16_pop(&packet_starts[index]);
uint16_t length = fifo16_pop(&packet_lengths[index]);
if (length >= MIN_L && length <= MTU) {
for (uint16_t i = 0; i < length; i++) {
uint16_t pos = (start+i)%getQueueSize(index);
tbuf[i] = packet_queue[index][pos];
}
transmit(radio, length); processed++;
}
queue_height[index] -= processed;
queued_bytes[index] -= length;
}
lora_receive(radio); led_tx_off();
}
radio->updateAirtime();
queue_flushing = false;
#if HAS_DISPLAY
display_tx = true;
#endif
@ -641,7 +721,7 @@ void transmit(RadioInterface* radio, uint16_t size) {
// Only start a new packet if this is a split packet and it has
// exceeded the length of a single packet
if (written == 255 && header & 0x0F) {
radio->endPacket(); radio->addAirtime(written);
radio->endPacket(); radio->addAirtime();
radio->beginPacket();
radio->write(header);
written = 1;
@ -654,7 +734,7 @@ void transmit(RadioInterface* radio, uint16_t size) {
led_indicate_error(5);
hard_reset();
}
radio->addAirtime(written);
radio->addAirtime();
} else {
// In promiscuous mode, we only send out
@ -681,7 +761,7 @@ void transmit(RadioInterface* radio, uint16_t size) {
written++;
}
radio->endPacket(); radio->addAirtime(written);
radio->endPacket(); radio->addAirtime();
}
last_tx = millis();
} else {
@ -690,7 +770,7 @@ void transmit(RadioInterface* radio, uint16_t size) {
}
}
void serialCallback(uint8_t sbyte) {
void serial_callback(uint8_t sbyte) {
if (IN_FRAME && sbyte == FEND &&
command == CMD_DATA) {
IN_FRAME = false;
@ -765,9 +845,9 @@ void serialCallback(uint8_t sbyte) {
}
if (frame_len == 4) {
selected_radio = interface_obj[interface];
uint32_t freq = (uint32_t)cmdbuf[0] << 24 | (uint32_t)cmdbuf[1] << 16 | (uint32_t)cmdbuf[2] << 8 | (uint32_t)cmdbuf[3];
selected_radio = interface_obj[interface];
if (freq == 0) {
kiss_indicate_frequency(selected_radio);
} else {
@ -789,9 +869,8 @@ void serialCallback(uint8_t sbyte) {
}
if (frame_len == 4) {
uint32_t bw = (uint32_t)cmdbuf[0] << 24 | (uint32_t)cmdbuf[1] << 16 | (uint32_t)cmdbuf[2] << 8 | (uint32_t)cmdbuf[3];
selected_radio = interface_obj[interface];
uint32_t bw = (uint32_t)cmdbuf[0] << 24 | (uint32_t)cmdbuf[1] << 16 | (uint32_t)cmdbuf[2] << 8 | (uint32_t)cmdbuf[3];
if (bw == 0) {
kiss_indicate_bandwidth(selected_radio);
@ -873,7 +952,6 @@ void serialCallback(uint8_t sbyte) {
}
interface = 0;
} else if (command == CMD_ST_ALOCK) {
selected_radio = interface_obj[interface];
if (sbyte == FESC) {
ESCAPE = true;
} else {
@ -886,6 +964,7 @@ void serialCallback(uint8_t sbyte) {
}
if (frame_len == 2) {
selected_radio = interface_obj[interface];
uint16_t at = (uint16_t)cmdbuf[0] << 8 | (uint16_t)cmdbuf[1];
if (at == 0) {
@ -896,10 +975,9 @@ void serialCallback(uint8_t sbyte) {
selected_radio->setSTALock(st_airtime_limit);
}
kiss_indicate_st_alock(selected_radio);
}
interface = 0;
}
} else if (command == CMD_LT_ALOCK) {
selected_radio = interface_obj[interface];
if (sbyte == FESC) {
ESCAPE = true;
} else {
@ -912,6 +990,7 @@ void serialCallback(uint8_t sbyte) {
}
if (frame_len == 2) {
selected_radio = interface_obj[interface];
uint16_t at = (uint16_t)cmdbuf[0] << 8 | (uint16_t)cmdbuf[1];
if (at == 0) {
@ -922,8 +1001,8 @@ void serialCallback(uint8_t sbyte) {
selected_radio->setLTALock(lt_airtime_limit);
}
kiss_indicate_lt_alock(selected_radio);
}
interface = 0;
}
} else if (command == CMD_STAT_RX) {
kiss_indicate_stat_rx();
} else if (command == CMD_STAT_TX) {
@ -957,7 +1036,7 @@ void serialCallback(uint8_t sbyte) {
kiss_indicate_promisc();
} else if (command == CMD_READY) {
selected_radio = interface_obj[interface];
if (!queueFull(selected_radio)) {
if (!queue_full(selected_radio)) {
kiss_indicate_ready();
} else {
kiss_indicate_not_ready();
@ -1035,6 +1114,8 @@ void serialCallback(uint8_t sbyte) {
if (sbyte != 0x00) {
kiss_indicate_fb();
}
} else if (command == CMD_DISP_READ) {
if (sbyte != 0x00) { kiss_indicate_disp(); }
} else if (command == CMD_DEV_HASH) {
if (sbyte != 0x00) {
kiss_indicate_device_hash();
@ -1117,7 +1198,7 @@ void serialCallback(uint8_t sbyte) {
}
display_intensity = sbyte;
di_conf_save(display_intensity);
//display_unblank();
display_unblank();
}
#endif
@ -1147,10 +1228,48 @@ void serialCallback(uint8_t sbyte) {
ESCAPE = false;
}
db_conf_save(sbyte);
//display_unblank();
display_unblank();
}
#endif
} else if (command == CMD_DISP_ROT) {
#if HAS_DISPLAY
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
drot_conf_save(sbyte);
display_unblank();
}
#endif
} else if (command == CMD_DIS_IA) {
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
dia_conf_save(sbyte);
}
} else if (command == CMD_DISP_RCND) {
#if HAS_DISPLAY
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
if (sbyte > 0x00) recondition_display = true;
}
#endif
} else if (command == CMD_NP_INT) {
#if HAS_NP
if (sbyte == FESC) {
@ -1175,6 +1294,12 @@ void serialCallback(uint8_t sbyte) {
portMUX_TYPE update_lock = portMUX_INITIALIZER_UNLOCKED;
#endif
bool medium_free(RadioInterface* radio) {
radio->updateModemStatus();
if (radio->getAvdInterference() && radio->getInterference()) { return false; }
return !radio->getDCD();
}
void validate_status() {
#if MCU_VARIANT == MCU_ESP32
// TODO: Get ESP32 boot flags
@ -1283,6 +1408,38 @@ void validate_status() {
}
}
void tx_queue_handler(RadioInterface* radio) {
if (queue_height[radio->getIndex()] > 0) {
if (radio->getCW() == -1) {
radio->setCW(random(radio->getCWMin(), radio->getCWMax()));
radio->setCWWaitTarget(radio->getCW() * radio->getCSMASlotMS());
}
if (radio->getDifsWaitStart() == 0) { // DIFS wait not yet started
if (medium_free(radio)) { radio->setDifsWaitStart(millis()); return; } // Set DIFS wait start time
else { return; } } // Medium not yet free, continue waiting
else { // We are waiting for DIFS or CW to pass
if (!medium_free(radio)) { radio->setDifsWaitStart(0); radio->setCWWaitStart(0); return; } // Medium became occupied while in DIFS wait, restart waiting when free again
else { // Medium is free, so continue waiting
if (millis() < radio->getDifsWaitStart()+radio->getDifsMS()) { return; } // DIFS has not yet passed, continue waiting
else { // DIFS has passed, and we are now in CW wait
if (radio->getCWWaitStart() == 0) { radio->setCWWaitStart(millis()); return; } // If we haven't started counting CW wait time, do it from now
else { // If we are already counting CW wait time, add it to the counter
radio->addCWWaitPassed(millis()-radio->getCWWaitStart()); radio->setCWWaitStart(millis());
if (radio->getCWWaitStatus()) { return; } // Contention window wait time has not yet passed, continue waiting
else { // Wait time has passed, flush the queue
if (!radio->getLimitRate()) { flush_queue(radio); } else { pop_queue(radio); }
radio->resetCWWaitPassed(); radio->setCW(-1); radio->setDifsWaitStart(0); }
}
}
}
}
}
}
void work_while_waiting() { loop(); }
void loop() {
#if MCU_VARIANT == MCU_ESP32
modem_packet_t *modem_packet = NULL;
@ -1311,8 +1468,8 @@ void loop() {
free(modem_packet);
modem_packet = NULL;
kiss_indicate_stat_rssi(packet_interface);
kiss_indicate_stat_snr(packet_interface);
kiss_indicate_stat_rssi(interface_obj[packet_interface]);
kiss_indicate_stat_snr(interface_obj[packet_interface]);
kiss_write_packet(packet_interface);
}
#endif
@ -1321,7 +1478,6 @@ void loop() {
for (int i = 0; i < INTERFACE_COUNT; i++) {
selected_radio = interface_obj[i];
if (selected_radio->getRadioOnline()) {
selected_radio->checkModemStatus();
ready = true;
}
}
@ -1336,30 +1492,11 @@ void loop() {
// skip this interface
continue;
}
tx_queue_handler(selected_radio);
selected_radio->checkModemStatus();
if (queue_height[selected_radio->getIndex()] > 0) {
uint32_t check_time = millis();
if (check_time > selected_radio->getPostTxYieldTimeout()) {
if (selected_radio->getDCDWaiting() && (check_time >= selected_radio->getDCDWaitUntil())) { selected_radio->setDCDWaiting(false); }
if (!selected_radio->getDCDWaiting()) {
// todo, will the delay here slow down transmission with
// multiple interfaces? needs investigation
for (uint8_t dcd_i = 0; dcd_i < DCD_THRESHOLD*2; dcd_i++) {
delay(STATUS_INTERVAL_MS); selected_radio->updateModemStatus();
}
if (!selected_radio->getDCD()) {
uint8_t csma_r = (uint8_t)random(256);
if (selected_radio->getCSMAp() >= csma_r) {
flushQueue(selected_radio);
} else {
selected_radio->setDCDWaiting(true);
selected_radio->setDCDWaitUntil(millis()+selected_radio->getCSMASlotMS());
}
}
}
}
}
// debug
Serial.write("Bitrate :"); Serial.print(selected_radio->getBitrate()); Serial.write("\n");
}
} else {
@ -1380,8 +1517,7 @@ void loop() {
}
}
buffer_serial();
if (!fifo_isempty(&serialFIFO)) serial_poll();
process_serial();
#if HAS_DISPLAY
#if DISPLAY == OLED
@ -1436,6 +1572,7 @@ void process_serial() {
void sleep_now() {
#if HAS_SLEEP == true
#if PLATFORM == PLATFORM_ESP32
#if BOARD_MODEL == BOARD_T3S3
display_intensity = 0;
update_display(true);
@ -1452,13 +1589,30 @@ void sleep_now() {
#endif
esp_sleep_enable_ext0_wakeup(PIN_WAKEUP, WAKEUP_LEVEL);
esp_deep_sleep_start();
#elif PLATFORM == PLATFORM_NRF52
#if BOARD_MODEL == BOARD_HELTEC_T114
npset(0,0,0);
digitalWrite(PIN_VEXT_EN, LOW);
digitalWrite(PIN_T114_TFT_BLGT, HIGH);
digitalWrite(PIN_T114_TFT_EN, HIGH);
#elif BOARD_MODEL == BOARD_TECHO
for (uint8_t i = display_intensity; i > 0; i--) { analogWrite(pin_backlight, i-1); delay(1); }
epd_black(true); delay(300); epd_black(true); delay(300); epd_black(false);
delay(2000);
analogWrite(PIN_VEXT_EN, 0);
delay(100);
#endif
sd_power_gpregret_set(0, 0x6d);
nrf_gpio_cfg_sense_input(pin_btn_usr1, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW);
NRF_POWER->SYSTEMOFF = 1;
#endif
#endif
}
void button_event(uint8_t event, unsigned long duration) {
//if (display_blanked) {
// display_unblank();
//} else {
if (display_blanked) {
display_unblank();
} else {
if (duration > 10000) {
#if HAS_CONSOLE
#if HAS_BLUETOOTH || HAS_BLE
@ -1488,7 +1642,7 @@ void button_event(uint8_t event, unsigned long duration) {
}
#endif
}
//}
}
}
void poll_buffers() {
@ -1501,7 +1655,7 @@ void serial_poll() {
while (!fifo_isempty(&serialFIFO)) {
char sbyte = fifo_pop(&serialFIFO);
serialCallback(sbyte);
serial_callback(sbyte);
}
serial_polling = false;

@ -42,6 +42,11 @@
#define ADDR_CONF_PSET 0xB5
#define ADDR_CONF_PINT 0xB6
#define ADDR_CONF_BSET 0xB7
#define ADDR_CONF_DROT 0xB8
#define ADDR_CONF_PSET 0xB5
#define ADDR_CONF_PINT 0xB6
#define ADDR_CONF_BSET 0xB7
#define ADDR_CONF_DIA 0xB9
#define INFO_LOCK_BYTE 0x73
#define CONF_OK_BYTE 0x73

@ -102,7 +102,7 @@ void ISR_VECT onDio0Rise() {
if (interface_obj[i]->getPacketValidity()) {
interface_obj[i]->handleDio0Rise();
}
if ((interfaces[i] == SX128X) || (interfaces[i] == SX1280)) {
if (interfaces[i] == SX1280) {
// On the SX1280, there is a bug which can cause the busy line
// to remain high if a high amount of packets are received when
// in continuous RX mode. This is documented as Errata 16.1 in
@ -120,8 +120,8 @@ sx126x::sx126x(uint8_t index, SPIClass* spi, bool tcxo, bool dio2_as_rf_switch,
RadioInterface(index),
_spiSettings(8E6, MSBFIRST, SPI_MODE0), _spiModem(spi), _ss(ss),
_sclk(sclk), _mosi(mosi), _miso(miso), _reset(reset), _dio0(dio0),
_busy(busy), _rxen(rxen), _frequency(0), _sf(0x07), _bw(0x04),
_cr(0x01), _ldro(0x00), _packetIndex(0), _implicitHeaderMode(0),
_busy(busy), _rxen(rxen), _frequency(0), _bw(0x04),
_cr(0x01), _packetIndex(0), _implicitHeaderMode(0),
_payloadLength(255), _crcMode(1), _fifo_tx_addr_ptr(0),
_fifo_rx_addr_ptr(0), _preinit_done(false), _tcxo(tcxo),
_dio2_as_rf_switch(dio2_as_rf_switch)
@ -217,12 +217,11 @@ void sx126x::loraMode() {
void sx126x::waitOnBusy() {
unsigned long time = millis();
if (_busy != -1) {
while (digitalRead(_busy) == HIGH)
{
if (millis() >= (time + 100)) {
break;
if (millis() >= (time + 100)) { break; }
}
// do nothing
}
}
@ -275,11 +274,7 @@ void sx126x::writeBuffer(const uint8_t* buffer, size_t size)
_spiModem->transfer(OP_FIFO_WRITE_6X);
_spiModem->transfer(_fifo_tx_addr_ptr);
for (int i = 0; i < size; i++)
{
_spiModem->transfer(buffer[i]);
_fifo_tx_addr_ptr++;
}
for (int i = 0; i < size; i++) {_spiModem->transfer(buffer[i]); _fifo_tx_addr_ptr++;}
_spiModem->endTransaction();
@ -297,10 +292,7 @@ void sx126x::readBuffer(uint8_t* buffer, size_t size)
_spiModem->transfer(_fifo_rx_addr_ptr);
_spiModem->transfer(0x00);
for (int i = 0; i < size; i++)
{
buffer[i] = _spiModem->transfer(0x00);
}
for (int i = 0; i < size; i++) {buffer[i] = _spiModem->transfer(0x00);}
_spiModem->endTransaction();
@ -308,7 +300,7 @@ void sx126x::readBuffer(uint8_t* buffer, size_t size)
}
void sx126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro) {
// because there is no access to these registers on the sx1262, we have
// Because there is no access to these registers on the sx1262, we have
// to set all these parameters at once or not at all.
uint8_t buf[8];
@ -327,7 +319,7 @@ void sx126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro) {
}
void sx126x::setPacketParams(uint32_t preamble, uint8_t headermode, uint8_t length, uint8_t crc) {
// because there is no access to these registers on the sx1262, we have
// Because there is no access to these registers on the sx1262, we have
// to set all these parameters at once or not at all.
uint8_t buf[9];
@ -374,27 +366,11 @@ void sx126x::calibrate(void) {
void sx126x::calibrate_image(uint32_t frequency) {
uint8_t image_freq[2] = {0};
if (frequency >= 430E6 && frequency <= 440E6) {
image_freq[0] = 0x6B;
image_freq[1] = 0x6F;
}
else if (frequency >= 470E6 && frequency <= 510E6) {
image_freq[0] = 0x75;
image_freq[1] = 0x81;
}
else if (frequency >= 779E6 && frequency <= 787E6) {
image_freq[0] = 0xC1;
image_freq[1] = 0xC5;
}
else if (frequency >= 863E6 && frequency <= 870E6) {
image_freq[0] = 0xD7;
image_freq[1] = 0xDB;
}
else if (frequency >= 902E6 && frequency <= 928E6) {
image_freq[0] = 0xE1;
image_freq[1] = 0xE9;
}
if (frequency >= 430E6 && frequency <= 440E6) { image_freq[0] = 0x6B; image_freq[1] = 0x6F; }
else if (frequency >= 470E6 && frequency <= 510E6) { image_freq[0] = 0x75; image_freq[1] = 0x81; }
else if (frequency >= 779E6 && frequency <= 787E6) { image_freq[0] = 0xC1; image_freq[1] = 0xC5; }
else if (frequency >= 863E6 && frequency <= 870E6) { image_freq[0] = 0xD7; image_freq[1] = 0xDB; }
else if (frequency >= 902E6 && frequency <= 928E6) { image_freq[0] = 0xE1; image_freq[1] = 0xE9; }
executeOpcode(OP_CALIBRATE_IMAGE_6X, image_freq, 2);
waitOnBusy();
}
@ -403,9 +379,7 @@ int sx126x::begin()
{
reset();
if (_busy != -1) {
pinMode(_busy, INPUT);
}
if (_busy != -1) { pinMode(_busy, INPUT); }
if (!_preinit_done) {
if (!preInit()) {
@ -413,9 +387,7 @@ int sx126x::begin()
}
}
if (_rxen != -1) {
pinMode(_rxen, OUTPUT);
}
if (_rxen != -1) { pinMode(_rxen, OUTPUT); }
calibrate();
calibrate_image(_frequency);
@ -502,47 +474,57 @@ int sx126x::endPacket()
executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
// wait for TX done
while ((buf[1] & IRQ_TX_DONE_MASK_6X) == 0) {
// Wait for TX done
bool timed_out = false;
uint32_t w_timeout = millis()+(getAirtime(_payloadLength)* MODEM_TIMEOUT_MULT);
while ((millis() < w_timeout) && ((buf[1] & IRQ_TX_DONE_MASK_6X) == 0)) {
buf[0] = 0x00;
buf[1] = 0x00;
executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
yield();
}
if (millis() > w_timeout) { timed_out = true; }
// clear IRQ's
uint8_t mask[2];
mask[0] = 0x00;
mask[1] = IRQ_TX_DONE_MASK_6X;
executeOpcode(OP_CLEAR_IRQ_STATUS_6X, mask, 2);
return 1;
return !timed_out;
}
uint8_t sx126x::modemStatus() {
// imitate the register status from the sx1276 / 78
uint8_t buf[2] = {0};
executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
uint8_t clearbuf[2] = {0};
uint8_t byte = 0x00;
bool sx126x::dcd() {
bool false_preamble_detected = false;
uint8_t buf[2] = {0}; executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
uint32_t now = millis();
bool header_detected = false;
bool carrier_detected = false;
if ((buf[1] & IRQ_HEADER_DET_MASK_6X) != 0) { header_detected = true; carrier_detected = true; }
else { header_detected = false; }
if ((buf[1] & IRQ_PREAMBLE_DET_MASK_6X) != 0) {
byte = byte | 0x01 | 0x04;
// clear register after reading
carrier_detected = true;
if (_preamble_detected_at == 0) { _preamble_detected_at = now; }
if (now - _preamble_detected_at > _lora_preamble_time_ms + _lora_header_time_ms) {
_preamble_detected_at = 0;
if (!header_detected) { false_preamble_detected = true; }
uint8_t clearbuf[2] = {0};
clearbuf[1] = IRQ_PREAMBLE_DET_MASK_6X;
executeOpcode(OP_CLEAR_IRQ_STATUS_6X, clearbuf, 2);
}
if ((buf[1] & IRQ_HEADER_DET_MASK_6X) != 0) {
byte = byte | 0x02 | 0x04;
}
executeOpcode(OP_CLEAR_IRQ_STATUS_6X, clearbuf, 2);
return byte;
// TODO: Maybe there's a way of unlatching the RSSI
// status without re-activating receive mode?
if (false_preamble_detected) { receive(); false_preamble_detected = false; }
return carrier_detected;
}
uint8_t sx126x::currentRssiRaw() {
uint8_t byte = 0;
executeOpcodeRead(OP_CURRENT_RSSI_6X, &byte, 1);
@ -615,9 +597,7 @@ int ISR_VECT sx126x::available()
int ISR_VECT sx126x::read()
{
if (!available()) {
return -1;
}
if (!available()) { return -1; }
// if received new packet
if (_packetIndex == 0) {
@ -753,6 +733,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_HELTEC_T114
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
#else
uint8_t buf[4] = {0};
#endif
@ -784,7 +766,7 @@ void sx126x::setTxPower(int level, int outputPin) {
_txp = level;
writeRegister(REG_OCP_6X, 0x38); // 160mA limit, overcurrent protection
writeRegister(REG_OCP_6X, OCP_TUNED); // 160mA limit, overcurrent protection
uint8_t tx_buf[2];
@ -927,7 +909,7 @@ void sx126x::setPreambleLength(long length)
void sx126x::setSyncWord(uint16_t sw)
{
// TODO: Fix
// TODO: Why was this hardcoded instead of using the config value?
// writeRegister(REG_SYNC_WORD_MSB_6X, (sw & 0xFF00) >> 8);
// writeRegister(REG_SYNC_WORD_LSB_6X, sw & 0x00FF);
writeRegister(REG_SYNC_WORD_MSB_6X, 0x14);
@ -946,7 +928,7 @@ void sx126x::disableCrc()
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
}
byte sx126x::random()
uint8_t sx126x::random()
{
return readRegister(REG_RANDOM_GEN_6X);
}
@ -994,28 +976,6 @@ void sx126x::handleDio0Rise()
}
}
void sx126x::updateBitrate() {
if (_radio_online) {
_lora_symbol_rate = (float)getSignalBandwidth()/(float)(pow(2, _sf));
_lora_symbol_time_ms = (1.0/_lora_symbol_rate)*1000.0;
_bitrate = (uint32_t)(_sf * ( (4.0/(float)(_cr+4)) / ((float)(pow(2, _sf))/((float)getSignalBandwidth()/1000.0)) ) * 1000.0);
_lora_us_per_byte = 1000000.0/((float)_bitrate/8.0);
_csma_slot_ms = _lora_symbol_time_ms*12;
if (_csma_slot_ms > CSMA_SLOT_MAX_MS) { _csma_slot_ms = CSMA_SLOT_MAX_MS; }
if (_csma_slot_ms < CSMA_SLOT_MIN_MS) { _csma_slot_ms = CSMA_SLOT_MIN_MS; }
float target_preamble_symbols = (LORA_PREAMBLE_TARGET_MS/_lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW;
if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) {
target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN;
} else {
target_preamble_symbols = ceil(target_preamble_symbols);
}
_preambleLength = (long)target_preamble_symbols;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
} else {
_bitrate = 0;
}
}
bool ISR_VECT sx126x::getPacketValidity() {
uint8_t buf[2];
@ -1095,19 +1055,13 @@ sx127x::sx127x(uint8_t index, SPIClass* spi, int ss, int sclk, int mosi, int mis
_spiModem(spi),
_ss(ss), _sclk(sclk), _mosi(mosi), _miso(miso), _reset(reset), _dio0(dio0),
_busy(busy), _frequency(0), _packetIndex(0), _preinit_done(false), _bw(0)
{
setTimeout(0);
// TODO, figure out why this has to be done. Using the index to reference the
// interface_obj list causes a crash otherwise
//_index = getIndex();
}
{ setTimeout(0); }
void sx127x::setSPIFrequency(uint32_t frequency) { _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); }
uint8_t ISR_VECT sx127x::readRegister(uint8_t address) { return singleTransfer(address & 0x7f, 0x00); }
void sx127x::writeRegister(uint8_t address, uint8_t value) { singleTransfer(address | 0x80, value); }
void sx127x::standby() { writeRegister(REG_OP_MODE_7X, MODE_LONG_RANGE_MODE_7X | MODE_STDBY_7X); }
void sx127x::sleep() { writeRegister(REG_OP_MODE_7X, MODE_LONG_RANGE_MODE_7X | MODE_SLEEP_7X); }
uint8_t sx127x::modemStatus() { return readRegister(REG_MODEM_STAT_7X); }
void sx127x::setSyncWord(uint8_t sw) { writeRegister(REG_SYNC_WORD_7X, sw); }
void sx127x::enableCrc() { writeRegister(REG_MODEM_CONFIG_2_7X, readRegister(REG_MODEM_CONFIG_2_7X) | 0x04); }
void sx127x::disableCrc() { writeRegister(REG_MODEM_CONFIG_2_7X, readRegister(REG_MODEM_CONFIG_2_7X) & 0xfb); }
@ -1115,7 +1069,7 @@ void sx127x::enableTCXO() { uint8_t tcxo_reg = readRegister(REG_TCXO_7X); writeR
void sx127x::disableTCXO() { uint8_t tcxo_reg = readRegister(REG_TCXO_7X); writeRegister(REG_TCXO_7X, tcxo_reg & 0xEF); }
void sx127x::explicitHeaderMode() { _implicitHeaderMode = 0; writeRegister(REG_MODEM_CONFIG_1_7X, readRegister(REG_MODEM_CONFIG_1_7X) & 0xfe); }
void sx127x::implicitHeaderMode() { _implicitHeaderMode = 1; writeRegister(REG_MODEM_CONFIG_1_7X, readRegister(REG_MODEM_CONFIG_1_7X) | 0x01); }
byte sx127x::random() { return readRegister(REG_RSSI_WIDEBAND_7X); }
uint8_t sx127x::random() { return readRegister(REG_RSSI_WIDEBAND_7X); }
void sx127x::flush() { }
bool sx127x::preInit() {
@ -1185,11 +1139,11 @@ int sx127x::begin() {
setCodingRate4(_cr);
setTxPower(_txp);
// set base addresses
// Set base addresses
writeRegister(REG_FIFO_TX_BASE_ADDR_7X, 0);
writeRegister(REG_FIFO_RX_BASE_ADDR_7X, 0);
// set LNA boost and auto AGC
// Set LNA boost and auto AGC
writeRegister(REG_LNA_7X, readRegister(REG_LNA_7X) | 0x03);
writeRegister(REG_MODEM_CONFIG_3_7X, 0x04);
@ -1239,6 +1193,15 @@ int sx127x::endPacket() {
return 1;
}
bool sx127x::dcd() {
bool carrier_detected = false;
uint8_t status = readRegister(REG_MODEM_STAT_7X);
if ((status & SIG_DETECT) == SIG_DETECT) { carrier_detected = true; }
if ((status & SIG_SYNCED) == SIG_SYNCED) { carrier_detected = true; }
return carrier_detected;
}
uint8_t sx127x::currentRssiRaw() {
uint8_t rssi = readRegister(REG_RSSI_VALUE_7X);
return rssi;
@ -1257,13 +1220,10 @@ uint8_t sx127x::packetRssiRaw() {
int ISR_VECT sx127x::packetRssi(uint8_t pkt_snr_raw) {
int pkt_rssi = (int)readRegister(REG_PKT_RSSI_VALUE_7X) - RSSI_OFFSET;
int pkt_snr;
if (pkt_snr_raw == 0xFF) {
pkt_snr = packetSnr();
} else {
pkt_snr = ((int8_t)pkt_snr_raw)*0.25;
}
int pkt_snr = ((int8_t)pkt_snr_raw)*0.25;
if (_frequency < 820E6) pkt_rssi -= 7;
if (pkt_snr < 0) {
pkt_rssi += pkt_snr;
} else {
@ -1275,14 +1235,26 @@ int ISR_VECT sx127x::packetRssi(uint8_t pkt_snr_raw) {
return pkt_rssi;
}
int ISR_VECT sx127x::packetRssi() {
int pkt_rssi = (int)readRegister(REG_PKT_RSSI_VALUE_7X) - RSSI_OFFSET;
int pkt_snr = packetSnr();
uint8_t ISR_VECT sx127x::packetSnrRaw() {
return readRegister(REG_PKT_SNR_VALUE_7X);
}
if (_frequency < 820E6) pkt_rssi -= 7;
float ISR_VECT sx127x::packetSnr() {
return ((int8_t)readRegister(REG_PKT_SNR_VALUE_7X)) * 0.25;
if (pkt_snr < 0) { pkt_rssi += pkt_snr; }
else {
// Slope correction is (16/15)*pkt_rssi,
// this estimation looses one floating point
// operation, and should be precise enough.
pkt_rssi = (int)(1.066 * pkt_rssi);
}
return pkt_rssi;
}
uint8_t ISR_VECT sx127x::packetSnrRaw() { return readRegister(REG_PKT_SNR_VALUE_7X); }
float ISR_VECT sx127x::packetSnr() { return ((int8_t)readRegister(REG_PKT_SNR_VALUE_7X)) * 0.25; }
long sx127x::packetFrequencyError() {
int32_t freqError = 0;
@ -1306,13 +1278,9 @@ size_t sx127x::write(uint8_t byte) { return write(&byte, sizeof(byte)); }
size_t sx127x::write(const uint8_t *buffer, size_t size) {
int currentLength = readRegister(REG_PAYLOAD_LENGTH_7X);
if ((currentLength + size) > MAX_PKT_LENGTH) {
size = MAX_PKT_LENGTH - currentLength;
}
if ((currentLength + size) > MAX_PKT_LENGTH) { size = MAX_PKT_LENGTH - currentLength; }
for (size_t i = 0; i < size; i++) {
writeRegister(REG_FIFO_7X, buffer[i]);
}
for (size_t i = 0; i < size; i++) { writeRegister(REG_FIFO_7X, buffer[i]); }
writeRegister(REG_PAYLOAD_LENGTH_7X, currentLength + size);
return size;
@ -1490,9 +1458,11 @@ void sx127x::handleLowDataRate() {
if ( long( (1<<sf) / (getSignalBandwidth()/1000)) > 16) {
// Set auto AGC and LowDataRateOptimize
writeRegister(REG_MODEM_CONFIG_3_7X, (1<<3)|(1<<2));
_ldro = true;
} else {
// Only set auto AGC
writeRegister(REG_MODEM_CONFIG_3_7X, (1<<2));
_ldro = false;
}
}
@ -1512,34 +1482,17 @@ void sx127x::optimizeModemSensitivity() {
}
void sx127x::handleDio0Rise() {
int irqFlags = readRegister(REG_IRQ_FLAGS_7X);
// Clear IRQs
writeRegister(REG_IRQ_FLAGS_7X, irqFlags);
if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK_7X) == 0) {
_packetIndex = 0;
int packetLength = _implicitHeaderMode ? readRegister(REG_PAYLOAD_LENGTH_7X) : readRegister(REG_RX_NB_BYTES_7X);
writeRegister(REG_FIFO_ADDR_PTR_7X, readRegister(REG_FIFO_RX_CURRENT_ADDR_7X));
if (_onReceive) {
_onReceive(_index, packetLength);
}
if (_onReceive) { _onReceive(_index, packetLength); }
writeRegister(REG_FIFO_ADDR_PTR_7X, 0);
}
void sx127x::updateBitrate() {
if (_radio_online) {
_lora_symbol_rate = (float)getSignalBandwidth()/(float)(pow(2, _sf));
_lora_symbol_time_ms = (1.0/_lora_symbol_rate)*1000.0;
_bitrate = (uint32_t)(_sf * ( (4.0/(float)(_cr+4)) / ((float)(pow(2, _sf))/((float)getSignalBandwidth()/1000.0)) ) * 1000.0);
_lora_us_per_byte = 1000000.0/((float)_bitrate/8.0);
_csma_slot_ms = _lora_symbol_time_ms*12;
if (_csma_slot_ms > CSMA_SLOT_MAX_MS) { _csma_slot_ms = CSMA_SLOT_MAX_MS; }
if (_csma_slot_ms < CSMA_SLOT_MIN_MS) { _csma_slot_ms = CSMA_SLOT_MIN_MS; }
float target_preamble_symbols = (LORA_PREAMBLE_TARGET_MS/_lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW;
if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) {
target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN;
} else {
target_preamble_symbols = ceil(target_preamble_symbols);
}
_preambleLength = (long)target_preamble_symbols;
} else {
_bitrate = 0;
}
}
bool ISR_VECT sx127x::getPacketValidity() {
@ -1603,11 +1556,11 @@ sx128x::sx128x(uint8_t index, SPIClass* spi, bool tcxo, int ss, int sclk, int mo
_spiSettings(8E6, MSBFIRST, SPI_MODE0),
_spiModem(spi),
_ss(ss), _sclk(sclk), _mosi(mosi), _miso(miso), _reset(reset), _dio0(dio0),
_busy(busy), _rxen(rxen), _txen(txen), _frequency(0), _sf(0x05),
_busy(busy), _rxen(rxen), _txen(txen), _frequency(0),
_bw(0x34), _cr(0x01), _packetIndex(0), _implicitHeaderMode(0),
_payloadLength(255), _crcMode(0), _fifo_tx_addr_ptr(0), _fifo_rx_addr_ptr(0),
_rxPacketLength(0), _preinit_done(false),
_tcxo(tcxo)
_tcxo(tcxo), _preamble_e(1), _preamble_m(1), _last_preamble(0)
{
// overide Stream timeout value
setTimeout(0);
@ -1633,25 +1586,21 @@ bool sx128x::preInit() {
_spiModem->begin();
#endif
// check version (retry for up to 2 seconds)
// check version (retry for up to 500 ms)
long start = millis();
uint8_t version_msb;
uint8_t version_lsb;
while (((millis() - start) < 2000) && (millis() >= start)) {
while (((millis() - start) < 500) && (millis() >= start)) {
version_msb = readRegister(REG_FIRM_VER_MSB);
version_lsb = readRegister(REG_FIRM_VER_LSB);
if ((version_msb == 0xB7 && version_lsb == 0xA9) || (version_msb == 0xB5 && version_lsb == 0xA9)) {
break;
}
if ((version_msb == 0xB7 && version_lsb == 0xA9) || (version_msb == 0xB5 && version_lsb == 0xA9)) { break; }
delay(100);
}
if ((version_msb != 0xB7 || version_lsb != 0xA9) && (version_msb != 0xB5 || version_lsb != 0xA9)) {
return false;
}
if ((version_msb != 0xB7 || version_lsb != 0xA9) && (version_msb != 0xB5 || version_lsb != 0xA9)) { return false; }
_preinit_done = true;
return true;
@ -1679,9 +1628,7 @@ uint8_t ISR_VECT sx128x::singleTransfer(uint8_t opcode, uint16_t address, uint8_
_spiModem->transfer(opcode);
_spiModem->transfer((address & 0xFF00) >> 8);
_spiModem->transfer(address & 0x00FF);
if (opcode == OP_READ_REGISTER_8X) {
_spiModem->transfer(0x00);
}
if (opcode == OP_READ_REGISTER_8X) { _spiModem->transfer(0x00); }
response = _spiModem->transfer(value);
_spiModem->endTransaction();
@ -1692,26 +1639,17 @@ uint8_t ISR_VECT sx128x::singleTransfer(uint8_t opcode, uint16_t address, uint8_
void sx128x::rxAntEnable()
{
if (_txen != -1) {
digitalWrite(_txen, LOW);
}
if (_rxen != -1) {
digitalWrite(_rxen, HIGH);
}
if (_txen != -1) { digitalWrite(_txen, LOW); }
if (_rxen != -1) { digitalWrite(_rxen, HIGH); }
}
void sx128x::txAntEnable()
{
if (_txen != -1) {
digitalWrite(_txen, HIGH);
}
if (_rxen != -1) {
digitalWrite(_rxen, LOW);
}
if (_txen != -1) { digitalWrite(_txen, HIGH); }
if (_rxen != -1) { digitalWrite(_rxen, LOW); }
}
void sx128x::loraMode() {
// enable lora mode on the SX1262 chip
uint8_t mode = MODE_LONG_RANGE_MODE_8X;
executeOpcode(OP_PACKET_TYPE_8X, &mode, 1);
}
@ -1720,10 +1658,7 @@ void sx128x::waitOnBusy() {
unsigned long time = millis();
while (digitalRead(_busy) == HIGH)
{
if (millis() >= (time + 100)) {
break;
}
// do nothing
if (millis() >= (time + 100)) { break; }
}
}
@ -1818,37 +1753,38 @@ void sx128x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr) {
buf[2] = cr;
executeOpcode(OP_MODULATION_PARAMS_8X, buf, 3);
if (sf <= 6) {
writeRegister(0x925, 0x1E);
} else if (sf <= 8) {
writeRegister(0x925, 0x37);
} else if (sf >= 9) {
writeRegister(0x925, 0x32);
}
if (sf <= 6) { writeRegister(0x925, 0x1E); }
else if (sf <= 8) { writeRegister(0x925, 0x37); }
else if (sf >= 9) { writeRegister(0x925, 0x32); }
writeRegister(0x093C, 0x1);
}
void sx128x::setPacketParams(uint32_t preamble, uint8_t headermode, uint8_t length, uint8_t crc) {
void sx128x::setPacketParams(uint32_t target_preamble, uint8_t headermode, uint8_t length, uint8_t crc) {
// because there is no access to these registers on the sx1280, we have
// to set all these parameters at once or not at all.
uint8_t buf[7];
// calculate exponent and mantissa values for modem
uint8_t e = 1;
uint8_t m = 1;
uint32_t preamblelen;
uint32_t calc_preamble;
while (e <= 15) {
while (m <= 15) {
preamblelen = m * (pow(2,e));
if (preamblelen >= preamble) break;
m++;
// Cap max preamble length
if (target_preamble >= 0xF000) target_preamble = 0xF000;
if (_last_preamble != target_preamble) {
_preamble_e = 1;
_preamble_m = 1;
// calculate exponent and mantissa values for modem
while (_preamble_e <= 15) {
while (_preamble_m <= 15) {
calc_preamble = _preamble_m * (pow(2,_preamble_e));
if (calc_preamble >= target_preamble - 4) break;
_preamble_m++;
}
if (calc_preamble >= target_preamble - 4) break;
_preamble_m = 1;
_preamble_e++;
}
if (preamblelen >= preamble) break;
m = 0;
e++;
}
buf[0] = (e << 4) | m;
buf[0] = (_preamble_e << 4) | _preamble_m;
buf[1] = headermode;
buf[2] = length;
buf[3] = crc;
@ -1859,6 +1795,8 @@ void sx128x::setPacketParams(uint32_t preamble, uint8_t headermode, uint8_t leng
buf[6] = 0x00;
executeOpcode(OP_PACKET_PARAMS_8X, buf, 7);
_last_preamble = target_preamble;
}
int sx128x::begin()
@ -1933,11 +1871,8 @@ int sx128x::beginPacket(int implicitHeader)
// put in standby mode
standby();
if (implicitHeader) {
implicitHeaderMode();
} else {
explicitHeaderMode();
}
if (implicitHeader) { implicitHeaderMode(); }
else { explicitHeaderMode(); }
_payloadLength = 0;
_fifo_tx_addr_ptr = 0;
@ -1963,14 +1898,17 @@ int sx128x::endPacket()
executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2);
// wait for TX done
while ((buf[1] & IRQ_TX_DONE_MASK_8X) == 0) {
// Wait for TX done
bool timed_out = false;
uint32_t w_timeout = millis()+(getAirtime(_payloadLength)* MODEM_TIMEOUT_MULT);
while ((millis() < w_timeout) && ((buf[1] & IRQ_TX_DONE_MASK_8X) == 0)) {
buf[0] = 0x00;
buf[1] = 0x00;
executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2);
yield();
}
if (millis() > w_timeout) { timed_out = true; }
// clear IRQ's
@ -1978,35 +1916,37 @@ int sx128x::endPacket()
mask[0] = 0x00;
mask[1] = IRQ_TX_DONE_MASK_8X;
executeOpcode(OP_CLEAR_IRQ_STATUS_8X, mask, 2);
return 1;
return !timed_out;
}
uint8_t sx128x::modemStatus() {
// imitate the register status from the sx1276 / 78
uint8_t buf[2] = {0};
bool sx128x::dcd() {
bool false_preamble_detected = false;
uint8_t buf[2] = {0}; executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2);
uint32_t now = millis();
executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2);
bool header_detected = false;
bool carrier_detected = false;
uint8_t clearbuf[2] = {0};
uint8_t byte = 0x00;
if ((buf[1] & IRQ_HEADER_DET_MASK_8X) != 0) { header_detected = true; carrier_detected = true; }
else { header_detected = false; }
if ((buf[0] & IRQ_PREAMBLE_DET_MASK_8X) != 0) {
byte = byte | 0x01 | 0x04;
// clear register after reading
clearbuf[0] = IRQ_PREAMBLE_DET_MASK_8X;
carrier_detected = true;
if (_preamble_detected_at == 0) { _preamble_detected_at = now; }
if (now - _preamble_detected_at > _lora_preamble_time_ms + _lora_header_time_ms) {
_preamble_detected_at = 0;
if (!header_detected) { false_preamble_detected = true; }
uint8_t clearbuf[2] = {0}; clearbuf[0] = IRQ_PREAMBLE_DET_MASK_8X;
executeOpcode(OP_CLEAR_IRQ_STATUS_8X, clearbuf, 2);
}
if ((buf[1] & IRQ_HEADER_DET_MASK_8X) != 0) {
byte = byte | 0x02 | 0x04;
}
executeOpcode(OP_CLEAR_IRQ_STATUS_8X, clearbuf, 2);
return byte;
// TODO: Maybe there's a way of unlatching the RSSI
// status without re-activating receive mode?
if (false_preamble_detected) { receive(); }
return carrier_detected;
}
uint8_t sx128x::currentRssiRaw() {
uint8_t byte = 0;
executeOpcodeRead(OP_CURRENT_RSSI_8X, &byte, 1);
@ -2096,9 +2036,7 @@ int ISR_VECT sx128x::read()
}
_fifo_rx_addr_ptr = rxbuf[1];
if (size > 255) {
size = 255;
}
if (size > 255) { size = 255; }
readBuffer(_packet, size);
}
@ -2110,9 +2048,7 @@ int ISR_VECT sx128x::read()
int sx128x::peek()
{
if (!available()) {
return -1;
}
if (!available()) { return -1; }
uint8_t b = _packet[_packetIndex];
return b;
@ -2227,11 +2163,8 @@ void sx128x::setTxPower(int level, int outputPin) {
uint8_t tx_buf[2];
#if BOARD_VARIANT == MODEL_13 || BOARD_VARIANT == MODEL_21
// RAK4631 with WisBlock SX1280 module (LIBSYS002)
if (level > 27) {
level = 27;
} else if (level < 0) {
level = 0;
}
if (level > 27) { level = 27; }
else if (level < 0) { level = 0; }
_txp = level;
@ -2334,18 +2267,15 @@ void sx128x::setTxPower(int level, int outputPin) {
#elif BOARD_VARIANT == MODEL_AC
// T3S3 SX1280 PA
if (level > 20) {
level = 20;
} else if (level < 0) {
level = 0;
}
if (level > 20) { level = 20; }
else if (level < 0) { level = 0; }
_txp = level;
int reg_value;
switch (level) {
/*case 0:
case 0:
reg_value = -18;
break;
case 1:
@ -2404,7 +2334,7 @@ void sx128x::setTxPower(int level, int outputPin) {
break;
case 19:
reg_value = 2;
break;*/
break;
case 20:
reg_value = 3;
break;
@ -2489,7 +2419,8 @@ uint32_t sx128x::getSignalBandwidth()
}
void sx128x::handleLowDataRate(){
// todo: do i need this??
if (_sf > 10) { _ldro = true; }
else { _ldro = false; }
}
void sx128x::optimizeModemSensitivity(){
@ -2498,15 +2429,10 @@ void sx128x::optimizeModemSensitivity(){
void sx128x::setSignalBandwidth(uint32_t sbw)
{
if (sbw <= 203.125E3) {
_bw = 0x34;
} else if (sbw <= 406.25E3) {
_bw = 0x26;
} else if (sbw <= 812.5E3) {
_bw = 0x18;
} else {
_bw = 0x0A;
}
if (sbw <= 203.125E3) { _bw = 0x34; }
else if (sbw <= 406.25E3) { _bw = 0x26; }
else if (sbw <= 812.5E3) { _bw = 0x18; }
else { _bw = 0x0A; }
setModulationParams(_sf, _bw, _cr);
@ -2514,8 +2440,8 @@ void sx128x::setSignalBandwidth(uint32_t sbw)
optimizeModemSensitivity();
}
void sx128x::setCodingRate4(int denominator)
{
void sx128x::setCodingRate4(int denominator) {
// TODO: add support for new interleaving scheme, see page 117 of sx1280 datasheet
if (denominator < 5) {
denominator = 5;
} else if (denominator > 8) {
@ -2618,34 +2544,6 @@ void sx128x::handleDio0Rise()
}
}
void sx128x::updateBitrate() {
if (_radio_online) {
_lora_symbol_rate = (float)getSignalBandwidth()/(float)(pow(2, _sf));
_lora_symbol_time_ms = (1.0/_lora_symbol_rate)*1000.0;
_bitrate = (uint32_t)(_sf * ( (4.0/(float)(_cr+4)) / ((float)(pow(2, _sf))/((float)getSignalBandwidth()/1000.0)) ) * 1000.0);
_lora_us_per_byte = 1000000.0/((float)_bitrate/8.0);
_csma_slot_ms = _lora_symbol_time_ms*12;
if (_csma_slot_ms > CSMA_SLOT_MAX_MS) { _csma_slot_ms = CSMA_SLOT_MAX_MS; }
if (_csma_slot_ms < CSMA_SLOT_MIN_MS) { _csma_slot_ms = CSMA_SLOT_MIN_MS; }
float target_preamble_symbols;
if (_bitrate <= LORA_FAST_BITRATE_THRESHOLD) {
target_preamble_symbols = (LORA_PREAMBLE_TARGET_MS/_lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW;
} else {
target_preamble_symbols = (LORA_PREAMBLE_FAST_TARGET_MS/_lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW;
}
if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) {
target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN;
} else {
target_preamble_symbols = ceil(target_preamble_symbols);
}
_preambleLength = (long)target_preamble_symbols;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
} else {
_bitrate = 0;
}
}
bool ISR_VECT sx128x::getPacketValidity() {
uint8_t buf[2];

@ -19,6 +19,15 @@
#define PA_OUTPUT_RFO_PIN 0
#define PA_OUTPUT_PA_BOOST_PIN 1
// Default LoRa settings
#define PHY_HEADER_LORA_SYMBOLS 20
#define PHY_CRC_LORA_BITS 16
#define LORA_PREAMBLE_SYMBOLS_MIN 18
#define LORA_PREAMBLE_TARGET_MS 24
#define LORA_PREAMBLE_FAST_DELTA 18
#define LORA_FAST_THRESHOLD_BPS 30E3
#define LORA_LIMIT_THRESHOLD_BPS 60E3
// DCD
#define STATUS_INTERVAL_MS 3
#define DCD_SAMPLES 2500
@ -29,22 +38,31 @@
#define AIRTIME_BINLEN_MS (STATUS_INTERVAL_MS*DCD_SAMPLES)
#define AIRTIME_BINS ((AIRTIME_LONGTERM*1000)/AIRTIME_BINLEN_MS)
#define current_airtime_bin(void) (millis()%AIRTIME_LONGTERM_MS)/AIRTIME_BINLEN_MS
#define DCD_THRESHOLD 2
#define DCD_LED_STEP_D 3
#define LORA_PREAMBLE_SYMBOLS_HW 4
#define LORA_PREAMBLE_SYMBOLS_MIN 18
#define LORA_PREAMBLE_TARGET_MS 15
#define LORA_PREAMBLE_FAST_TARGET_MS 4
#define LORA_FAST_BITRATE_THRESHOLD 40000
// CSMA Parameters
#define CSMA_SIFS_MS 0
#define CSMA_POST_TX_YIELD_SLOTS 3
#define CSMA_SLOT_MAX_MS 100
#define CSMA_SLOT_MIN_MS 24
#define CSMA_SLOT_MIN_FAST_DELTA 18
#define CSMA_SLOT_SYMBOLS 12
#define CSMA_CW_BANDS 4
#define CSMA_CW_MIN 0
#define CSMA_CW_PER_BAND_WINDOWS 15
#define CSMA_BAND_1_MAX_AIRTIME 7
#define CSMA_BAND_N_MIN_AIRTIME 85
#define CSMA_INFR_THRESHOLD_DB 12
#define LED_ID_TRIG 16
#define NOISE_FLOOR_SAMPLES 64
#define RSSI_OFFSET 157
#define PHY_HEADER_LORA_SYMBOLS 8
#define _e 2.71828183
#define _S 12.5
#define MODEM_TIMEOUT_MULT 1.1
// Status flags
const uint8_t SIG_DETECT = 0x01;
@ -53,10 +71,14 @@ const uint8_t RX_ONGOING = 0x04;
// forward declare Utilities.h LED functions
void led_rx_on();
void led_rx_off();
void led_id_on();
void led_id_off();
void led_indicate_airtime_lock();
void kiss_indicate_channel_stats(uint8_t index);
void kiss_indicate_csma_stats(uint8_t index);
#if PLATFORM == PLATFORM_ESP32
// get update_lock for ESP32
extern portMUX_TYPE update_lock;
@ -65,18 +87,19 @@ extern portMUX_TYPE update_lock;
class RadioInterface : public Stream {
public:
// todo: in the future define _spiModem and _spiSettings from here for inheritence by child classes
RadioInterface(uint8_t index) : _index(index), _radio_locked(false),
RadioInterface(uint8_t index) : _index(index), _sf(0x07), _radio_locked(false),
_radio_online(false), _st_airtime_limit(0.0), _lt_airtime_limit(0.0),
_airtime_lock(false), _airtime(0.0), _longterm_airtime(0.0),
_airtime_lock(false), _airtime(0.0), _longterm_airtime(0.0), _last_packet_cost(0.0),
_local_channel_util(0.0), _total_channel_util(0.0),
_longterm_channel_util(0.0), _last_status_update(0),
_stat_signal_detected(false), _stat_signal_synced(false),_stat_rx_ongoing(false), _last_dcd(0),
_dcd_count(0), _dcd(false), _dcd_led(false),
_dcd_waiting(false), _dcd_wait_until(0), _dcd_sample(0),
_post_tx_yield_timeout(0), _csma_slot_ms(50), _csma_p(85), _csma_p_min(0.15),
_csma_p_max(0.333), _csma_b_speed(0.15), _preambleLength(6), _lora_symbol_time_ms(0.0),
_lora_symbol_rate(0.0), _lora_us_per_byte(0.0), _bitrate(0),
_packet{0}, _onReceive(NULL), _txp(0) {};
_dcd_waiting(false), _dcd_sample(0),
_csma_slot_ms(CSMA_SLOT_MIN_MS),
_preambleLength(LORA_PREAMBLE_SYMBOLS_MIN), _lora_symbol_time_ms(0.0),
_lora_preamble_time_ms(0), _lora_header_time_ms(0), _lora_symbol_rate(0.0), _lora_us_per_byte(0.0), _bitrate(0),
_packet{0}, _onReceive(NULL), _txp(0), _ldro(false), _limit_rate(false), _interference_detected(false), _avoid_interference(true), _difs_ms(CSMA_SIFS_MS + 2 * _csma_slot_ms), _difs_wait_start(0), _cw_wait_start(0), _cw_wait_target(0), _cw_wait_passed(0), _csma_cw(-1), _cw_band(1), _cw_min(0), _cw_max(CSMA_CW_PER_BAND_WINDOWS), _noise_floor_sampled(false), _noise_floor_sample(0), _noise_floor_buffer({0}), _noise_floor(-292), _led_id_filter(0), _preamble_detected_at(0) {};
virtual int begin() = 0;
virtual void end() = 0;
@ -119,17 +142,48 @@ public:
virtual void setCodingRate4(int denominator) = 0;
virtual uint8_t getCodingRate4() = 0;
virtual void setPreambleLength(long length) = 0;
virtual uint8_t modemStatus() = 0;
virtual bool dcd() = 0;
virtual void enableCrc() = 0;
virtual void disableCrc() = 0;
virtual void enableTCXO() = 0;
virtual void disableTCXO() = 0;
virtual byte random() = 0;
virtual uint8_t random() = 0;
virtual void setSPIFrequency(uint32_t frequency) = 0;
virtual void updateBitrate() = 0;
void updateBitrate() {
if (!_radio_online) { _bitrate = 0; }
else {
_lora_symbol_rate = (float)getSignalBandwidth()/(float)(pow(2, _sf));
_lora_symbol_time_ms = (1.0/_lora_symbol_rate)*1000.0;
_bitrate = (uint32_t)(_sf * ( (4.0/(float)getCodingRate4()) / ((float)(pow(2, _sf))/((float)getSignalBandwidth()/1000.0)) ) * 1000.0);
_lora_us_per_byte = 1000000.0/((float)_bitrate/8.0);
bool fast_rate = _bitrate > LORA_FAST_THRESHOLD_BPS;
_limit_rate = _bitrate > LORA_LIMIT_THRESHOLD_BPS;
int csma_slot_min_ms = CSMA_SLOT_MIN_MS;
float lora_preamble_target_ms = LORA_PREAMBLE_TARGET_MS;
if (fast_rate) { csma_slot_min_ms -= CSMA_SLOT_MIN_FAST_DELTA;
lora_preamble_target_ms -= LORA_PREAMBLE_FAST_DELTA; }
_csma_slot_ms = _lora_symbol_time_ms*CSMA_SLOT_SYMBOLS;
if (_csma_slot_ms > CSMA_SLOT_MAX_MS) { _csma_slot_ms = CSMA_SLOT_MAX_MS; }
if (_csma_slot_ms < CSMA_SLOT_MIN_MS) { _csma_slot_ms = csma_slot_min_ms; }
_difs_ms = CSMA_SIFS_MS + 2*_csma_slot_ms;
float target_preamble_symbols = lora_preamble_target_ms/_lora_symbol_time_ms;
if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) { target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN; }
else { target_preamble_symbols = (ceil)(target_preamble_symbols); }
setPreambleLength(target_preamble_symbols);
_lora_preamble_time_ms = (ceil)(_preambleLength * _lora_symbol_time_ms);
_lora_header_time_ms = (ceil)(PHY_HEADER_LORA_SYMBOLS * _lora_symbol_time_ms);
}
}
virtual void handleDio0Rise() = 0;
virtual bool getPacketValidity() = 0;
uint32_t getBitrate() { return _bitrate; };
@ -171,24 +225,102 @@ public:
}
_longterm_channel_util = (float)longterm_channel_util_sum/(float)AIRTIME_BINS;
updateCSMAp();
//kiss_indicate_channel_stats(); // todo: enable me!
updateCSMAParameters();
kiss_indicate_channel_stats(_index);
};
void addAirtime(uint16_t written) {
float getAirtime(uint16_t written) {
float lora_symbols = 0;
float packet_cost_ms = 0.0;
float payload_cost_ms = ((float)written * _lora_us_per_byte)/1000.0;
packet_cost_ms += payload_cost_ms;
packet_cost_ms += (_preambleLength+4.25)*_lora_symbol_time_ms;
packet_cost_ms += PHY_HEADER_LORA_SYMBOLS * _lora_symbol_time_ms;
if (interfaces[_index] == SX1276 || interfaces[_index] == SX1278) {
lora_symbols += (8*written + PHY_CRC_LORA_BITS - 4*_sf + 8 + PHY_HEADER_LORA_SYMBOLS);
lora_symbols /= 4*(_sf-2*_ldro);
lora_symbols *= getCodingRate4();
lora_symbols += _preambleLength + 0.25 + 8;
packet_cost_ms += lora_symbols * _lora_symbol_time_ms;
}
else if (interfaces[_index] == SX1262 || interfaces[_index] == SX1280) {
if (_sf < 7) {
lora_symbols += (8*written + PHY_CRC_LORA_BITS - 4*_sf + PHY_HEADER_LORA_SYMBOLS);
lora_symbols /= 4*_sf;
lora_symbols *= getCodingRate4();
lora_symbols += _preambleLength + 2.25 + 8;
packet_cost_ms += lora_symbols * _lora_symbol_time_ms;
} else {
lora_symbols += (8*written + PHY_CRC_LORA_BITS - 4*_sf + 8 + PHY_HEADER_LORA_SYMBOLS);
lora_symbols /= 4*(_sf-2*_ldro);
lora_symbols *= getCodingRate4();
lora_symbols += _preambleLength + 0.25 + 8;
packet_cost_ms += lora_symbols * _lora_symbol_time_ms;
}
}
_last_packet_cost = packet_cost_ms;
return packet_cost_ms;
}
void addAirtime() {
uint16_t cb = current_airtime_bin();
uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; }
_airtime_bins[cb] += packet_cost_ms;
_airtime_bins[cb] += _last_packet_cost;
_airtime_bins[nb] = 0;
};
void updateModemStatus() {
#if MCU_VARIANT == MCU_ESP32
portENTER_CRITICAL(&update_lock);
#elif MCU_VARIANT == MCU_NRF52
portENTER_CRITICAL();
#endif
bool carrier_detected = dcd();
int current_rssi = currentRssi();
_last_status_update = millis();
#if MCU_VARIANT == MCU_ESP32
portEXIT_CRITICAL(&update_lock);
#elif MCU_VARIANT == MCU_NRF52
portEXIT_CRITICAL();
#endif
_interference_detected = !carrier_detected && (current_rssi > (_noise_floor+CSMA_INFR_THRESHOLD_DB));
if (_interference_detected) { if (_led_id_filter < LED_ID_TRIG) { _led_id_filter += 1; } }
else { if (_led_id_filter > 0) {_led_id_filter -= 1; } }
if (carrier_detected) { _dcd = true; } else { _dcd = false; }
_dcd_led = _dcd;
if (_dcd_led) { led_rx_on(); }
else {
if (_interference_detected) {
if (_led_id_filter >= LED_ID_TRIG && _noise_floor_sampled) { led_id_on(); }
} else {
if (_airtime_lock) { led_indicate_airtime_lock(); }
else { led_rx_off(); led_id_off(); }
}
}
}
void updateNoiseFloor() {
int current_rssi = currentRssi();
if (!_dcd) {
if (!_noise_floor_sampled || current_rssi < _noise_floor + CSMA_INFR_THRESHOLD_DB) {
_noise_floor_buffer[_noise_floor_sample] = current_rssi;
_noise_floor_sample = _noise_floor_sample+1;
if (_noise_floor_sample >= NOISE_FLOOR_SAMPLES) {
_noise_floor_sample %= NOISE_FLOOR_SAMPLES;
_noise_floor_sampled = true;
}
if (_noise_floor_sampled) {
_noise_floor = 0;
for (int ni = 0; ni < NOISE_FLOOR_SAMPLES; ni++) { _noise_floor += _noise_floor_buffer[ni]; }
_noise_floor /= NOISE_FLOOR_SAMPLES;
}
}
}
}
void checkModemStatus() {
if (millis()-_last_status_update >= STATUS_INTERVAL_MS) {
updateModemStatus();
updateNoiseFloor();
_util_samples[_dcd_sample] = _dcd;
_dcd_sample = (_dcd_sample+1)%DCD_SAMPLES;
@ -210,93 +342,65 @@ public:
}
}
};
void updateModemStatus() {
#if PLATFORM == PLATFORM_ESP32
portENTER_CRITICAL(&update_lock);
#elif PLATFORM == PLATFORM_NRF52
portENTER_CRITICAL();
#endif
uint8_t status = modemStatus();
_last_status_update = millis();
#if PLATFORM == PLATFORM_ESP32
portEXIT_CRITICAL(&update_lock);
#elif PLATFORM == PLATFORM_NRF52
portEXIT_CRITICAL();
#endif
if ((status & SIG_DETECT) == SIG_DETECT) { _stat_signal_detected = true; } else { _stat_signal_detected = false; }
if ((status & SIG_SYNCED) == SIG_SYNCED) { _stat_signal_synced = true; } else { _stat_signal_synced = false; }
if ((status & RX_ONGOING) == RX_ONGOING) { _stat_rx_ongoing = true; } else { _stat_rx_ongoing = false; }
// if (stat_signal_detected || stat_signal_synced || stat_rx_ongoing) {
if (_stat_signal_detected || _stat_signal_synced) {
if (_stat_rx_ongoing) {
if (_dcd_count < DCD_THRESHOLD) {
_dcd_count++;
} else {
_last_dcd = _last_status_update;
_dcd_led = true;
_dcd = true;
}
}
} else {
if (_dcd_count == 0) {
_dcd_led = false;
} else if (_dcd_count > DCD_LED_STEP_D) {
_dcd_count -= DCD_LED_STEP_D;
} else {
_dcd_count = 0;
void updateCSMAParameters() {
int airtime_pct = (int)(_airtime*100);
int new_cw_band = _cw_band;
if (airtime_pct <= CSMA_BAND_1_MAX_AIRTIME) { new_cw_band = 1; }
else {
int at = airtime_pct + CSMA_BAND_1_MAX_AIRTIME;
new_cw_band = map(at, CSMA_BAND_1_MAX_AIRTIME, CSMA_BAND_N_MIN_AIRTIME, 2, CSMA_CW_BANDS);
}
if (_last_status_update > _last_dcd+_csma_slot_ms) {
_dcd = false;
_dcd_led = false;
_dcd_count = 0;
if (new_cw_band > CSMA_CW_BANDS) { new_cw_band = CSMA_CW_BANDS; }
if (new_cw_band != _cw_band) {
_cw_band = (uint8_t)(new_cw_band);
_cw_min = (_cw_band-1) * CSMA_CW_PER_BAND_WINDOWS;
_cw_max = (_cw_band) * CSMA_CW_PER_BAND_WINDOWS - 1;
kiss_indicate_csma_stats(_index);
}
}
if (_dcd_led) {
led_rx_on();
} else {
if (_airtime_lock) {
led_indicate_airtime_lock();
} else {
led_rx_off();
}
}
};
void setPostTxYieldTimeout(uint32_t timeout) { _post_tx_yield_timeout = timeout; };
uint32_t getPostTxYieldTimeout() { return _post_tx_yield_timeout; };
void setDCD(bool dcd) { _dcd = dcd; };
bool getDCD() { return _dcd; };
void setDCDWaiting(bool dcd_waiting) { _dcd_waiting = dcd_waiting; };
bool getDCDWaiting() { return _dcd_waiting; };
void setDCDWaitUntil(uint32_t dcd_wait_until) { _dcd_wait_until = dcd_wait_until; };
bool getDCDWaitUntil() { return _dcd_wait_until; };
float getAirtime() { return _airtime; };
float getLongtermAirtime() { return _longterm_airtime; };
float getTotalChannelUtil() { return _total_channel_util; };
float getLongtermChannelUtil() { return _longterm_channel_util; };
float CSMASlope(float u) { return (pow(_e,_S*u-_S/2.0))/(pow(_e,_S*u-_S/2.0)+1.0); };
void updateCSMAp() {
_csma_p = (uint8_t)((1.0-(_csma_p_min+(_csma_p_max-_csma_p_min)*CSMASlope(_airtime+_csma_b_speed)))*255.0);
}
uint8_t getCSMAp() { return _csma_p; };
void setCSMASlotMS(int slot_size) { _csma_slot_ms = slot_size; };
int getCSMASlotMS() { return _csma_slot_ms; };
float getSymbolTime() { return _lora_symbol_time_ms; };
float getSymbolRate() { return _lora_symbol_rate; };
long getPreambleLength() { return _preambleLength; };
void setAvdInterference(bool cfg) { _avoid_interference = cfg; };
bool getAvdInterference() { return _avoid_interference; };
bool getInterference() { return _interference_detected; };
int getNoiseFloor() { return _noise_floor; };
unsigned long getDifsMS() { return _difs_ms; };
uint8_t getCWBand() { return _cw_band; };
uint8_t getCWMin() { return _cw_min; };
uint8_t getCWMax() { return _cw_max; };
uint8_t getCW() { return _csma_cw; };
void setCW(uint8_t cw) { _csma_cw = cw; };
void setCWWaitTarget(unsigned long target) { _cw_wait_target = target; };
unsigned long getCWWaitTarget() { return _cw_wait_target; };
unsigned long getDifsWaitStart() { return _difs_wait_start; };
void setDifsWaitStart(unsigned long start) { _difs_wait_start = start; };
unsigned long getCWWaitStart() { return _cw_wait_start; };
void setCWWaitStart(unsigned long start) { _cw_wait_start = start; };
void addCWWaitPassed(unsigned long start) { _cw_wait_passed += start; };
void resetCWWaitPassed() { _cw_wait_passed = 0; };
bool getCWWaitStatus() { return _cw_wait_passed < _cw_wait_target; };
bool getLimitRate() { return _limit_rate; };
protected:
virtual void explicitHeaderMode() = 0;
virtual void implicitHeaderMode() = 0;
uint8_t _index;
uint32_t _bitrate;
int8_t _txp;
uint8_t _sf;
bool _radio_locked;
bool _radio_online;
float _st_airtime_limit;
@ -306,6 +410,7 @@ protected:
uint16_t _longterm_bins[AIRTIME_BINS] = {0};
float _airtime;
float _longterm_airtime;
float _last_packet_cost;
float _local_channel_util;
float _total_channel_util;
float _longterm_channel_util;
@ -318,20 +423,35 @@ protected:
bool _dcd;
bool _dcd_led;
bool _dcd_waiting;
long _dcd_wait_until;
bool _util_samples[DCD_SAMPLES] = {false};
int _dcd_sample;
uint32_t _post_tx_yield_timeout;
uint8_t _csma_p;
int _csma_slot_ms;
float _csma_p_min;
float _csma_p_max;
float _csma_b_speed;
long _preambleLength;
float _lora_symbol_time_ms;
float _lora_symbol_rate;
float _lora_us_per_byte;
uint32_t _bitrate;
long _lora_preamble_time_ms;
long _lora_header_time_ms;
bool _ldro;
bool _limit_rate;
bool _interference_detected;
bool _avoid_interference;
int _csma_slot_ms;
unsigned long _difs_ms;
unsigned long _difs_wait_start;
unsigned long _cw_wait_start;
unsigned long _cw_wait_target;
unsigned long _cw_wait_passed;
int _csma_cw;
uint8_t _cw_band;
uint8_t _cw_min;
uint8_t _cw_max;
bool _noise_floor_sampled;
int _noise_floor_sample;
int _noise_floor_buffer[NOISE_FLOOR_SAMPLES];
int _noise_floor;
uint8_t _led_id_filter;
unsigned long _preamble_detected_at;
uint8_t _packet[255];
void (*_onReceive)(uint8_t, int);
};
@ -383,7 +503,7 @@ public:
void setCodingRate4(int denominator);
uint8_t getCodingRate4();
void setPreambleLength(long length);
uint8_t modemStatus();
bool dcd();
void enableCrc();
void disableCrc();
void enableTCXO();
@ -396,8 +516,6 @@ public:
void dumpRegisters(Stream& out);
void updateBitrate();
void handleDio0Rise();
private:
void writeBuffer(const uint8_t* buffer, size_t size);
@ -440,10 +558,8 @@ private:
int _rxen;
int _busy;
uint32_t _frequency;
uint8_t _sf;
uint8_t _bw;
uint8_t _cr;
uint8_t _ldro;
int _packetIndex;
int _implicitHeaderMode;
int _payloadLength;
@ -466,6 +582,7 @@ public:
int endPacket();
int packetRssi(uint8_t pkt_snr_raw = 0xFF);
int packetRssi();
int currentRssi();
uint8_t packetRssiRaw();
uint8_t currentRssiRaw();
@ -501,7 +618,7 @@ public:
void setCodingRate4(int denominator);
uint8_t getCodingRate4();
void setPreambleLength(long length);
uint8_t modemStatus();
bool dcd();
void enableCrc();
void disableCrc();
void enableTCXO();
@ -511,8 +628,6 @@ public:
void setSPIFrequency(uint32_t frequency);
void updateBitrate();
void handleDio0Rise();
bool getPacketValidity();
private:
@ -544,7 +659,6 @@ private:
int _packetIndex;
int _implicitHeaderMode;
bool _preinit_done;
uint8_t _sf;
uint8_t _cr;
uint32_t _bw;
};
@ -595,7 +709,7 @@ public:
void setCodingRate4(int denominator);
uint8_t getCodingRate4();
void setPreambleLength(long length);
uint8_t modemStatus();
bool dcd();
void enableCrc();
void disableCrc();
void enableTCXO();
@ -607,8 +721,6 @@ public:
void dumpRegisters(Stream& out);
void updateBitrate();
void handleDio0Rise();
bool getPacketValidity();
@ -652,7 +764,6 @@ private:
int _busy;
int _modem;
uint32_t _frequency;
uint8_t _sf;
uint8_t _bw;
uint8_t _cr;
int _packetIndex;
@ -664,5 +775,8 @@ private:
bool _preinit_done;
int _rxPacketLength;
bool _tcxo;
uint8_t _preamble_e;
uint8_t _preamble_m;
uint32_t _last_preamble;
};
#endif

@ -1,5 +1,5 @@
# 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`:
The firmware is now handled and installed to RNodes directly through `rnodeconf`, which is inclueded in the `rns` package. It can be installed via `pip`:
```
# Install rnodeconf via rns package

@ -89,7 +89,6 @@ uint8_t boot_vector = 0x00;
#if HAS_NP == true
#include <Adafruit_NeoPixel.h>
#define NUMPIXELS 1
#define NP_M 0.15
Adafruit_NeoPixel pixels(NUMPIXELS, pin_np, NEO_GRB + NEO_KHZ800);
uint8_t npr = 0;
@ -103,10 +102,23 @@ uint8_t boot_vector = 0x00;
}
void led_init() {
#if BOARD_MODEL == BOARD_HELTEC_T114
// Enable vext power supply to neopixel
pinMode(PIN_VEXT_EN, OUTPUT);
digitalWrite(PIN_VEXT_EN, HIGH);
#endif
#if MCU_VARIANT == MCU_NRF52
if (eeprom_read(eeprom_addr(ADDR_CONF_PSET)) == CONF_OK_BYTE) {
uint8_t int_val = eeprom_read(eeprom_addr(ADDR_CONF_PINT));
led_set_intensity(int_val);
}
#else
if (EEPROM.read(eeprom_addr(ADDR_CONF_PSET)) == CONF_OK_BYTE) {
uint8_t int_val = EEPROM.read(eeprom_addr(ADDR_CONF_PINT));
led_set_intensity(int_val);
}
#endif
}
void npset(uint8_t r, uint8_t g, uint8_t b) {
@ -143,16 +155,22 @@ uint8_t boot_vector = 0x00;
void led_rx_off() { npset(0, 0, 0); }
void led_tx_on() { npset(0xFF, 0x50, 0x00); }
void led_tx_off() { npset(0, 0, 0); }
void led_id_on() { npset(0x90, 0, 0x70); }
void led_id_off() { npset(0, 0, 0); }
#elif BOARD_MODEL == BOARD_RNODE_NG_20
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_RNODE_NG_21
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_T3S3
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
@ -163,32 +181,44 @@ uint8_t boot_vector = 0x00;
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_TBEAM
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, LOW); }
void led_tx_off() { digitalWrite(pin_led_tx, HIGH); }
void led_id_on() { }
void led_id_off() { }
#elif BOARD_MODEL == BOARD_TDECK
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_TBEAM_S_V1
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); }
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() { }
#else
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 BOARD_MODEL == BOARD_LORA32_V2_0
#if defined(EXTERNAL_LEDS)
@ -196,11 +226,15 @@ uint8_t boot_vector = 0x00;
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() { }
#else
void led_rx_on() { digitalWrite(pin_led_rx, LOW); }
void led_rx_off() { digitalWrite(pin_led_rx, HIGH); }
void led_tx_on() { digitalWrite(pin_led_tx, LOW); }
void led_tx_off() { digitalWrite(pin_led_tx, HIGH); }
void led_id_on() { }
void led_id_off() { }
#endif
#elif BOARD_MODEL == BOARD_HELTEC32_V2
#if defined(EXTERNAL_LEDS)
@ -208,44 +242,82 @@ uint8_t boot_vector = 0x00;
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() { }
#else
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 BOARD_MODEL == BOARD_HELTEC32_V3
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_H_W_PAPER
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_LORA32_V2_1
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
void led_id_on() { }
void led_id_off() { }
#elif BOARD_MODEL == BOARD_HUZZAH32
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_GENERIC_ESP32
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 BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_OPENCOM_XL
#if HAS_NP == true
void led_rx_on() { npset(0, 0, 0xFF); }
void led_rx_off() { npset(0, 0, 0); }
void led_tx_on() { npset(0xFF, 0x50, 0x00); }
void led_tx_off() { npset(0, 0, 0); }
void led_id_on() { npset(0x90, 0, 0x70); }
void led_id_off() { npset(0, 0, 0); }
#elif BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_OPENCOM_XL
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); }
void led_rx_off() { digitalWrite(pin_led_rx, HIGH); }
void led_tx_on() { digitalWrite(pin_led_tx, LOW); }
void led_tx_off() { digitalWrite(pin_led_tx, HIGH); }
void led_id_on() { }
void led_id_off() { }
#elif BOARD_MODEL == BOARD_TECHO
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_rx_on() { digitalWrite(pin_led_rx, LED_ON); }
void led_rx_off() { digitalWrite(pin_led_rx, LED_OFF); }
void led_tx_on() { digitalWrite(pin_led_tx, LED_ON); }
void led_tx_off() { digitalWrite(pin_led_tx, LED_OFF); }
void led_id_on() { }
void led_id_off() { }
#endif
#endif
@ -381,6 +453,19 @@ void led_indicate_warning(int cycles) {
}
led_rx_off();
}
#elif BOARD_MODEL == BOARD_TECHO
void led_indicate_info(int cycles) {
bool forever = (cycles == 0) ? true : false;
cycles = forever ? 1 : cycles;
while(cycles > 0) {
led_rx_off();
delay(100);
led_rx_on();
delay(100);
if (!forever) cycles--;
}
led_rx_off();
}
#else
void led_indicate_info(int cycles) {
bool forever = (cycles == 0) ? true : false;
@ -428,6 +513,8 @@ unsigned long led_standby_ticks = 0;
#endif
#elif MCU_VARIANT == MCU_NRF52
int led_standby_lng = 200;
int led_standby_cut = 100;
uint8_t led_standby_min = 200;
uint8_t led_standby_max = 255;
uint8_t led_notready_min = 0;
@ -442,7 +529,6 @@ unsigned long led_standby_ticks = 0;
unsigned long led_standby_value = led_standby_min;
int8_t led_standby_direction = 0;
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
#if HAS_NP == true
void led_indicate_standby() {
led_standby_ticks++;
@ -511,9 +597,17 @@ int8_t led_standby_direction = 0;
}
led_standby_value += led_standby_direction;
if (led_standby_value > 253) {
#if BOARD_MODEL == BOARD_TECHO
led_rx_on();
#else
led_tx_on();
#endif
} else {
#if BOARD_MODEL == BOARD_TECHO
led_rx_off();
#else
led_tx_off();
#endif
}
#if BOARD_MODEL == BOARD_LORA32_V2_1
#if defined(EXTERNAL_LEDS)
@ -533,9 +627,7 @@ int8_t led_standby_direction = 0;
led_indicate_standby();
}
#endif
#endif
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
#if HAS_NP == true
void led_indicate_not_ready() {
led_standby_ticks++;
@ -594,7 +686,6 @@ int8_t led_standby_direction = 0;
}
}
#endif
#endif
bool interface_bitrate_cmp(RadioInterface* p, RadioInterface* q) {
@ -617,13 +708,8 @@ void serial_write(uint8_t byte) {
#if MCU_VARIANT == MCU_NRF52 && HAS_BLE
// This ensures that the TX buffer is flushed after a frame is queued in serial.
// serial_in_frame is used to ensure that the flush only happens at the end of the frame
if (serial_in_frame && byte == FEND) {
SerialBT.flushTXD();
serial_in_frame = false;
}
else if (!serial_in_frame && byte == FEND) {
serial_in_frame = true;
}
if (serial_in_frame && byte == FEND) { SerialBT.flushTXD(); serial_in_frame = false; }
else if (!serial_in_frame && byte == FEND) { serial_in_frame = true; }
#endif
}
#else
@ -824,11 +910,16 @@ void kiss_indicate_lt_alock(RadioInterface* radio) {
serial_write(FEND);
}
void kiss_indicate_channel_stats(RadioInterface* radio) {
void kiss_indicate_channel_stats(uint8_t index) {
RadioInterface* radio = interface_obj[index];
int current_rssi = radio->currentRssi();
uint16_t ats = (uint16_t)(radio->getAirtime()*100*100);
uint16_t atl = (uint16_t)(radio->getLongtermAirtime()*100*100);
uint16_t cls = (uint16_t)(radio->getTotalChannelUtil()*100*100);
uint16_t cll = (uint16_t)(radio->getLongtermChannelUtil()*100*100);
uint8_t crs = (uint8_t)(current_rssi+rssi_offset);
uint8_t nfl = (uint8_t)(radio->getNoiseFloor()+rssi_offset);
uint8_t ntf = 0xFF; if (radio->getInterference()) { ntf = (uint8_t)(current_rssi+rssi_offset); }
serial_write(FEND);
serial_write(CMD_SEL_INT);
serial_write(radio->getIndex());
@ -843,6 +934,9 @@ void kiss_indicate_channel_stats(RadioInterface* radio) {
escaped_serial_write(cls);
escaped_serial_write(cll>>8);
escaped_serial_write(cll);
escaped_serial_write(crs);
escaped_serial_write(nfl);
escaped_serial_write(ntf);
serial_write(FEND);
}
@ -852,33 +946,42 @@ void kiss_indicate_phy_stats(RadioInterface* radio) {
uint16_t prs = (uint16_t)(radio->getPreambleLength()+4);
uint16_t prt = (uint16_t)((radio->getPreambleLength()+4)*radio->getSymbolTime());
uint16_t cst = (uint16_t)(radio->getCSMASlotMS());
uint16_t dft = (uint16_t)(radio->getDifsMS());
serial_write(FEND);
serial_write(CMD_SEL_INT);
serial_write(radio->getIndex());
serial_write(FEND);
serial_write(FEND);
serial_write(CMD_STAT_PHYPRM);
escaped_serial_write(lst>>8);
escaped_serial_write(lst);
escaped_serial_write(lsr>>8);
escaped_serial_write(lsr);
escaped_serial_write(prs>>8);
escaped_serial_write(prs);
escaped_serial_write(prt>>8);
escaped_serial_write(prt);
escaped_serial_write(cst>>8);
escaped_serial_write(cst);
escaped_serial_write(lst>>8); escaped_serial_write(lst);
escaped_serial_write(lsr>>8); escaped_serial_write(lsr);
escaped_serial_write(prs>>8); escaped_serial_write(prs);
escaped_serial_write(prt>>8); escaped_serial_write(prt);
escaped_serial_write(cst>>8); escaped_serial_write(cst);
escaped_serial_write(dft>>8); escaped_serial_write(dft);
serial_write(FEND);
}
void kiss_indicate_csma_stats(uint8_t index) {
selected_radio = interface_obj[index];
serial_write(FEND);
serial_write(CMD_SEL_INT);
serial_write(index);
serial_write(FEND);
serial_write(FEND);
serial_write(CMD_STAT_CSMA);
escaped_serial_write(selected_radio->getCWBand());
escaped_serial_write(selected_radio->getCWMin());
escaped_serial_write(selected_radio->getCWMax());
serial_write(FEND);
}
void kiss_indicate_battery() {
#if MCU_VARIANT == MCU_ESP32
serial_write(FEND);
serial_write(CMD_STAT_BAT);
escaped_serial_write(battery_state);
escaped_serial_write((uint8_t)int(battery_percent));
serial_write(FEND);
#endif
}
void kiss_indicate_btpin() {
@ -915,7 +1018,6 @@ void kiss_indicate_fbstate() {
serial_write(FEND);
}
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
void kiss_indicate_device_hash() {
serial_write(FEND);
serial_write(CMD_DEV_HASH);
@ -969,7 +1071,6 @@ void kiss_indicate_fbstate() {
}
serial_write(FEND);
}
#endif
void kiss_indicate_fb() {
serial_write(FEND);
@ -985,6 +1086,20 @@ void kiss_indicate_fb() {
serial_write(FEND);
}
void kiss_indicate_disp() {
serial_write(FEND);
serial_write(CMD_DISP_READ);
#if HAS_DISPLAY
uint8_t *da = disp_area.getBuffer();
uint8_t *sa = stat_area.getBuffer();
for (int i = 0; i < 512; i++) { escaped_serial_write(da[i]); }
for (int i = 0; i < 512; i++) { escaped_serial_write(sa[i]); }
#else
serial_write(0xFF);
#endif
serial_write(FEND);
}
void kiss_indicate_ready() {
serial_write(FEND);
serial_write(CMD_READY);
@ -1067,15 +1182,15 @@ void setTXPower(RadioInterface* radio, int txp) {
// Todo, revamp this function. The current parameters for setTxPower are
// suboptimal, as some chips have power amplifiers which means that the max
// dBm is not always the same.
if (model == MODEL_11) {
if (interfaces[radio->getIndex()] == SX128X) {
if (model == MODEL_12) {
if (interfaces[radio->getIndex()] == SX1280) {
radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
} else {
radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
}
}
if (model == MODEL_12) {
if (interfaces[radio->getIndex()] == SX128X) {
if (model == MODEL_13) {
if (interfaces[radio->getIndex()] == SX1280) {
radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
} else {
radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
@ -1083,7 +1198,7 @@ void setTXPower(RadioInterface* radio, int txp) {
}
if (model == MODEL_21) {
if (interfaces[radio->getIndex()] == SX128X) {
if (interfaces[radio->getIndex()] == SX1280) {
radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
} else {
radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
@ -1112,6 +1227,8 @@ void setTXPower(RadioInterface* radio, int txp) {
if (model == MODEL_C4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C5) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C6) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_C7) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_CA) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_D4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
@ -1203,13 +1320,10 @@ void promisc_disable() {
InternalFS.begin();
file.open(EEPROM_FILE, FILE_O_READ);
// if file doesn't exist
if (!file) {
if (file.open(EEPROM_FILE, FILE_O_WRITE)) {
// initialise the file with empty content
uint8_t empty_content[EEPROM_SIZE] = {0};
file.write(empty_content, EEPROM_SIZE);
for (uint32_t mapped_addr = 0; mapped_addr < EEPROM_SIZE; mapped_addr++) { file.seek(mapped_addr); file.write(0xFF); }
eeprom_flush();
return true;
} else {
return false;
@ -1285,7 +1399,6 @@ void kiss_dump_eeprom() {
#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
void eeprom_flush() {
// sync file contents to flash
file.close();
file.open(EEPROM_FILE, FILE_O_WRITE);
written_bytes = 0;
@ -1300,7 +1413,7 @@ void eeprom_update(int mapped_addr, uint8_t byte) {
}
#elif !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
// todo: clean up this implementation, writing one byte and syncing
// each time is really slow, but this is also suboptimal
// each time is really slow
uint8_t read_byte;
void* read_byte_ptr = &read_byte;
file.seek(mapped_addr);
@ -1310,17 +1423,7 @@ void eeprom_update(int mapped_addr, uint8_t byte) {
file.write(byte);
}
written_bytes++;
if (((mapped_addr - eeprom_addr(0)) == ADDR_INFO_LOCK) || (mapped_addr - eeprom_addr(0)) == ADDR_CONF_OK) {
// have to do a flush because we're only writing 1 byte and it syncs after 4
eeprom_flush();
}
if (written_bytes >= 4) {
file.close();
file.open(EEPROM_FILE, FILE_O_WRITE);
written_bytes = 0;
}
#endif
}
@ -1333,9 +1436,13 @@ void eeprom_write(uint8_t addr, uint8_t byte) {
}
void eeprom_erase() {
#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
InternalFS.format();
#else
for (int addr = 0; addr < EEPROM_RESERVED; addr++) {
eeprom_update(eeprom_addr(addr), 0xFF);
}
#endif
hard_reset();
}
@ -1359,9 +1466,9 @@ bool eeprom_product_valid() {
#endif
#if PLATFORM == PLATFORM_ESP32
if (rval == PRODUCT_RNODE || rval == BOARD_RNODE_NG_20 || rval == BOARD_RNODE_NG_21 || rval == PRODUCT_HMBRW || rval == PRODUCT_TBEAM || rval == PRODUCT_T32_10 || rval == PRODUCT_T32_20 || rval == PRODUCT_T32_21 || rval == PRODUCT_H32_V2 || rval == PRODUCT_H32_V3 || rval == PRODUCT_TDECK_V1 || rval == PRODUCT_TBEAM_S_V1) {
if (rval == PRODUCT_RNODE || rval == BOARD_RNODE_NG_20 || rval == BOARD_RNODE_NG_21 || rval == PRODUCT_HMBRW || rval == PRODUCT_TBEAM || rval == PRODUCT_T32_10 || rval == PRODUCT_T32_20 || rval == PRODUCT_T32_21 || rval == PRODUCT_H32_V2 || rval == PRODUCT_H32_V3 || rval == PRODUCT_TDECK_V1 || rval == PRODUCT_TBEAM_S_V1 || rval == PRODUCT_H_W_PAPER) {
#elif PLATFORM == PLATFORM_NRF52
if (rval == PRODUCT_TECHO || rval == PRODUCT_RAK4631 || rval == PRODUCT_HMBRW || rval == PRODUCT_OPENCOM_XL) {
if (rval == PRODUCT_RAK4631 || rval == PRODUCT_HELTEC_T114 || rval == PRODUCT_OPENCOM_XL || rval == PRODUCT_TECHO || rval == PRODUCT_HMBRW) {
#else
if (false) {
#endif
@ -1383,16 +1490,16 @@ bool eeprom_model_valid() {
if (model == MODEL_A3 || model == MODEL_A8) {
#elif BOARD_MODEL == BOARD_RNODE_NG_21
if (model == MODEL_A2 || model == MODEL_A7) {
#elif BOARD_MODEL == BOARD_RNODE_NG_22
if (model == MODEL_A1 || model == MODEL_A6 || model == MODEL_A5 || model == MODEL_AA) {
#elif BOARD_MODEL == BOARD_T3S3
if (model == MODEL_A1 || model == MODEL_A5 || model == MODEL_A6 || model == MODEL_AB || model == MODEL_AC) {
if (model == MODEL_A1 || model == MODEL_A6 || model == MODEL_A5 || model == MODEL_AA || model == MODEL_AC) {
#elif BOARD_MODEL == BOARD_HMBRW
if (model == MODEL_FF || model == MODEL_FE) {
#elif BOARD_MODEL == BOARD_TBEAM
if (model == MODEL_E4 || model == MODEL_E9 || model == MODEL_E3 || model == MODEL_E8) {
#elif BOARD_MODEL == BOARD_TECHO
if (model == MODEL_16 || model == MODEL_17) {
#elif BOARD_MODEL == BOARD_TDECK
if (model == MODEL_D4 || model == MODEL_D9) {
#elif BOARD_MODEL == BOARD_TECHO
if (model == MODEL_16 || model == MODEL_17) {
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
if (model == MODEL_DB || model == MODEL_DC) {
#elif BOARD_MODEL == BOARD_LORA32_V1_0
@ -1405,6 +1512,10 @@ bool eeprom_model_valid() {
if (model == MODEL_C4 || model == MODEL_C9) {
#elif BOARD_MODEL == BOARD_HELTEC32_V3
if (model == MODEL_C5 || model == MODEL_CA) {
#elif BOARD_MODEL == BOARD_H_W_PAPER
if (model == MODEL_C8) {
#elif BOARD_MODEL == BOARD_HELTEC_T114
if (model == MODEL_C6 || model == MODEL_C7) {
#elif BOARD_MODEL == BOARD_RAK4631
if (model == MODEL_11 || model == MODEL_12 || model == MODEL_13 || model == MODEL_14) {
#elif BOARD_MODEL == BOARD_OPENCOM_XL
@ -1497,13 +1608,28 @@ void db_conf_save(uint8_t val) {
display_blanking_enabled = false;
} else {
display_blanking_enabled = true;
//display_blanking_timeout = val*1000;
display_blanking_timeout = val*1000;
}
eeprom_update(eeprom_addr(ADDR_CONF_BSET), CONF_OK_BYTE);
eeprom_update(eeprom_addr(ADDR_CONF_DBLK), val);
#endif
}
void drot_conf_save(uint8_t val) {
#if HAS_DISPLAY
if (val >= 0x00 and val <= 0x03) {
eeprom_update(eeprom_addr(ADDR_CONF_DROT), val);
hard_reset();
}
#endif
}
void dia_conf_save(uint8_t val) {
if (val > 0x00) { eeprom_update(eeprom_addr(ADDR_CONF_DIA), 0x01); }
else { eeprom_update(eeprom_addr(ADDR_CONF_DIA), 0x00); }
hard_reset();
}
void np_int_conf_save(uint8_t p_int) {
eeprom_update(eeprom_addr(ADDR_CONF_PSET), CONF_OK_BYTE);
eeprom_update(eeprom_addr(ADDR_CONF_PINT), p_int);

@ -3,3 +3,4 @@ board_manager:
- https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
- https://liberatedsystems.co.uk/rnode-firmware-ce/esp-custom-package.json
- 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

@ -20,6 +20,7 @@ import sys
import RNS
import json
import hashlib
import subprocess
major_version = None
minor_version = None
@ -27,9 +28,23 @@ target_version = None
target_file = os.path.join(sys.argv[1])
if sys.argv[1] == "from_device":
from_device = True
else:
from_device = False
if not from_device:
firmware_data = open(target_file, "rb").read()
calc_hash = hashlib.sha256(firmware_data[0:-32]).digest()
part_hash = firmware_data[-32:]
if calc_hash == part_hash:
print(RNS.hexrep(part_hash, delimit=False))
else:
try:
cmdresult = subprocess.run(["rnodeconf", sys.argv[2], "-L"], stdout=subprocess.PIPE).stdout.decode('utf-8')
part_hash = cmdresult.split("The actual firmware hash is: ")[1].replace("\n", "")
print(part_hash)
except Exception as e:
print("Could not get partition hash from device: "+str(e))

@ -13,8 +13,6 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// This class is for BLE serial functionality on ESP32 boards ONLY
#include <Arduino.h>
#include "../../Boards.h"

@ -13,8 +13,6 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// This class is for BLE serial functionality on ESP32 boards ONLY
#include "../../Boards.h"
#if PLATFORM != PLATFORM_NRF52

@ -0,0 +1,440 @@
/**
* The MIT License (MIT)
*
* Copyright (c) 2018 by ThingPulse, Daniel Eichhorn
* Copyright (c) 2018 by Fabrice Weinberg
* Copyright (c) 2024 by Heltec AutoMation
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* ThingPulse invests considerable time and money to develop these open source libraries.
* Please support us by buying our products (and not the clones) from
* https://thingpulse.com
*
*/
#ifndef ST7789Spi_h
#define ST7789Spi_h
#include "OLEDDisplay.h"
#include <SPI.h>
#define ST_CMD_DELAY 0x80 // special signifier for command lists
#define ST77XX_NOP 0x00
#define ST77XX_SWRESET 0x01
#define ST77XX_RDDID 0x04
#define ST77XX_RDDST 0x09
#define ST77XX_SLPIN 0x10
#define ST77XX_SLPOUT 0x11
#define ST77XX_PTLON 0x12
#define ST77XX_NORON 0x13
#define ST77XX_INVOFF 0x20
#define ST77XX_INVON 0x21
#define ST77XX_DISPOFF 0x28
#define ST77XX_DISPON 0x29
#define ST77XX_CASET 0x2A
#define ST77XX_RASET 0x2B
#define ST77XX_RAMWR 0x2C
#define ST77XX_RAMRD 0x2E
#define ST77XX_PTLAR 0x30
#define ST77XX_TEOFF 0x34
#define ST77XX_TEON 0x35
#define ST77XX_MADCTL 0x36
#define ST77XX_COLMOD 0x3A
#define ST77XX_MADCTL_MY 0x80
#define ST77XX_MADCTL_MX 0x40
#define ST77XX_MADCTL_MV 0x20
#define ST77XX_MADCTL_ML 0x10
#define ST77XX_MADCTL_RGB 0x00
#define ST77XX_RDID1 0xDA
#define ST77XX_RDID2 0xDB
#define ST77XX_RDID3 0xDC
#define ST77XX_RDID4 0xDD
// Some ready-made 16-bit ('565') color settings:
#define ST77XX_BLACK 0x0000
#define ST77XX_WHITE 0xFFFF
#define ST77XX_RED 0xF800
#define ST77XX_GREEN 0x07E0
#define ST77XX_BLUE 0x001F
#define ST77XX_CYAN 0x07FF
#define ST77XX_MAGENTA 0xF81F
#define ST77XX_YELLOW 0xFFE0
#define ST77XX_ORANGE 0xFC00
#define LED_A_ON LOW
#ifdef ESP_PLATFORM
#undef LED_A_ON
#define LED_A_ON HIGH
#define rtos_free free
#define rtos_malloc malloc
//SPIClass SPI1(HSPI);
#endif
class ST7789Spi : public OLEDDisplay {
private:
uint8_t _rst;
uint8_t _dc;
uint8_t _cs;
uint8_t _ledA;
int _miso;
int _mosi;
int _clk;
SPIClass * _spi;
SPISettings _spiSettings;
uint16_t _RGB=0xFFFF;
uint8_t _buffheight;
public:
/* pass _cs as -1 to indicate "do not use CS pin", for cases where it is hard wired low */
ST7789Spi(SPIClass *spiClass,uint8_t _rst, uint8_t _dc, uint8_t _cs, OLEDDISPLAY_GEOMETRY g = GEOMETRY_RAWMODE,uint16_t width=240,uint16_t height=320,int mosi=-1,int miso=-1,int clk=-1) {
this->_spi = spiClass;
this->_rst = _rst;
this->_dc = _dc;
this->_cs = _cs;
this->_mosi=mosi;
this->_miso=miso;
this->_clk=clk;
//this->_ledA = _ledA;
_spiSettings = SPISettings(40000000, MSBFIRST, SPI_MODE0);
setGeometry(g,width,height);
}
bool connect(){
this->_buffheight=displayHeight / 8;
this->_buffheight+=displayHeight % 8 ? 1:0;
pinMode(_cs, OUTPUT);
pinMode(_dc, OUTPUT);
//pinMode(_ledA, OUTPUT);
if (_cs != (uint8_t) -1) {
pinMode(_cs, OUTPUT);
}
pinMode(_rst, OUTPUT);
#ifdef ESP_PLATFORM
_spi->begin(_clk,_miso,_mosi,-1);
#else
_spi->begin();
#endif
_spi->setClockDivider (SPI_CLOCK_DIV2);
// Pulse Reset low for 10ms
digitalWrite(_rst, HIGH);
delay(1);
digitalWrite(_rst, LOW);
delay(10);
digitalWrite(_rst, HIGH);
_spi->begin ();
//digitalWrite(_ledA, LED_A_ON);
return true;
}
void display(void) {
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
uint16_t minBoundY = UINT16_MAX;
uint16_t maxBoundY = 0;
uint16_t minBoundX = UINT16_MAX;
uint16_t maxBoundX = 0;
uint16_t x, y;
// Calculate the Y bounding box of changes
// and copy buffer[pos] to buffer_back[pos];
for (y = 0; y < _buffheight; y++) {
for (x = 0; x < displayWidth; x++) {
//Serial.printf("x %d y %d\r\n",x,y);
uint16_t pos = x + y * displayWidth;
if (buffer[pos] != buffer_back[pos]) {
minBoundY = min(minBoundY, y);
maxBoundY = max(maxBoundY, y);
minBoundX = min(minBoundX, x);
maxBoundX = max(maxBoundX, x);
}
buffer_back[pos] = buffer[pos];
}
yield();
}
// If the minBoundY wasn't updated
// we can savely assume that buffer_back[pos] == buffer[pos]
// holdes true for all values of pos
if (minBoundY == UINT16_MAX) return;
set_CS(LOW);
_spi->beginTransaction(_spiSettings);
for (y = minBoundY; y <= maxBoundY; y++)
{
for(int temp = 0; temp<8;temp++)
{
//setAddrWindow(minBoundX,y*8+temp,maxBoundX-minBoundX+1,1);
setAddrWindow(minBoundX,y*8+temp,maxBoundX-minBoundX+1,1);
//setAddrWindow(y*8+temp,minBoundX,1,maxBoundX-minBoundX+1);
uint32_t const pixbufcount = maxBoundX-minBoundX+1;
uint16_t *pixbuf = (uint16_t *)rtos_malloc(2 * pixbufcount);
for (x = minBoundX; x <= maxBoundX; x++)
{
pixbuf[x-minBoundX] = ((buffer[x + y * displayWidth]>>temp)&0x01)==1?_RGB:0;
}
#ifdef ESP_PLATFORM
_spi->transferBytes((uint8_t *)pixbuf, NULL, 2 * pixbufcount);
#else
_spi->transfer(pixbuf, NULL, 2 * pixbufcount);
#endif
rtos_free(pixbuf);
}
}
_spi->endTransaction();
set_CS(HIGH);
#else
set_CS(LOW);
_spi->beginTransaction(_spiSettings);
uint8_t x, y;
for (y = 0; y < _buffheight; y++)
{
for(int temp = 0; temp<8;temp++)
{
//setAddrWindow(minBoundX,y*8+temp,maxBoundX-minBoundX+1,1);
//setAddrWindow(minBoundX,y*8+temp,maxBoundX-minBoundX+1,1);
setAddrWindow(y*8+temp,0,1,displayWidth);
uint32_t const pixbufcount = displayWidth;
uint16_t *pixbuf = (uint16_t *)rtos_malloc(2 * pixbufcount);
for (x = 0; x < displayWidth; x++)
{
pixbuf[x] = ((buffer[x + y * displayWidth]>>temp)&0x01)==1?_RGB:0;
}
#ifdef ESP_PLATFORM
_spi->transferBytes((uint8_t *)pixbuf, NULL, 2 * pixbufcount);
#else
_spi->transfer(pixbuf, NULL, 2 * pixbufcount);
#endif
rtos_free(pixbuf);
}
}
_spi->endTransaction();
set_CS(HIGH);
#endif
}
virtual void resetOrientation() {
uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MX;
sendCommand(ST77XX_MADCTL);
WriteData(madctl);
delay(10);
}
virtual void flipScreenVertically() {
uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MY;
sendCommand(ST77XX_MADCTL);
WriteData(madctl);
delay(10);
}
virtual void mirrorScreen() {
uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MX|ST77XX_MADCTL_MY;
sendCommand(ST77XX_MADCTL);
WriteData(madctl);
delay(10);
}
virtual void setRotation(uint8_t r) {
uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MX;
if (r == 1) { madctl = 0xC0; }
if (r == 2) { madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MY; }
if (r == 3) { madctl = 0x00; }
sendCommand(ST77XX_MADCTL);
WriteData(madctl);
delay(10);
}
void setRGB(uint16_t c)
{
this->_RGB=0x00|c>>8|c<<8&0xFF00;
}
void displayOn(void) {
//sendCommand(DISPLAYON);
}
void displayOff(void) {
//sendCommand(DISPLAYOFF);
}
//#define ST77XX_MADCTL_MY 0x80
//#define ST77XX_MADCTL_MX 0x40
//#define ST77XX_MADCTL_MV 0x20
//#define ST77XX_MADCTL_ML 0x10
protected:
// Send all the init commands
virtual void sendInitCommands()
{
sendCommand(ST77XX_SWRESET); // 1: Software reset, no args, w/delay
delay(150);
sendCommand(ST77XX_SLPOUT); // 2: Out of sleep mode, no args, w/delay
delay(10);
sendCommand(ST77XX_COLMOD); // 3: Set color mode, 16-bit color
WriteData(0x55);
delay(10);
sendCommand(ST77XX_MADCTL); // 4: Mem access ctrl (directions), Row/col addr, bottom-top refresh
WriteData(0x08);
sendCommand(ST77XX_CASET); // 5: Column addr set,
WriteData(0x00);
WriteData(0x00); // XSTART = 0
WriteData(0x00);
WriteData(240); // XEND = 240
sendCommand(ST77XX_RASET); // 6: Row addr set,
WriteData(0x00);
WriteData(0x00); // YSTART = 0
WriteData(320>>8);
WriteData(320&0xFF); // YSTART = 320
sendCommand(ST77XX_SLPOUT); // 7: hack
delay(10);
sendCommand(ST77XX_NORON); // 8: Normal display on, no args, w/delay
delay(10);
sendCommand(ST77XX_DISPON); // 9: Main screen turn on, no args, delay
delay(10);
sendCommand(ST77XX_INVON); // 10: invert
delay(10);
//uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MX;
uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MX;
sendCommand(ST77XX_MADCTL);
WriteData(madctl);
delay(10);
setRGB(ST77XX_GREEN);
}
private:
void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
x += (320-displayWidth)/2;
y += (240-displayHeight)/2;
uint32_t xa = ((uint32_t)x << 16) | (x + w - 1);
uint32_t ya = ((uint32_t)y << 16) | (y + h - 1);
writeCommand(ST77XX_CASET); // Column addr set
SPI_WRITE32(xa);
writeCommand(ST77XX_RASET); // Row addr set
SPI_WRITE32(ya);
writeCommand(ST77XX_RAMWR); // write to RAM
}
int getBufferOffset(void) {
return 0;
}
inline void set_CS(bool level) {
if (_cs != (uint8_t) -1) {
digitalWrite(_cs, level);
}
};
inline void sendCommand(uint8_t com) __attribute__((always_inline)){
set_CS(HIGH);
digitalWrite(_dc, LOW);
set_CS(LOW);
_spi->beginTransaction(_spiSettings);
_spi->transfer(com);
_spi->endTransaction();
set_CS(HIGH);
digitalWrite(_dc, HIGH);
}
inline void WriteData(uint8_t data) __attribute__((always_inline)){
digitalWrite(_cs, LOW);
_spi->beginTransaction(_spiSettings);
_spi->transfer(data);
_spi->endTransaction();
digitalWrite(_cs, HIGH);
}
void SPI_WRITE32(uint32_t l)
{
_spi->transfer(l >> 24);
_spi->transfer(l >> 16);
_spi->transfer(l >> 8);
_spi->transfer(l);
}
void writeCommand(uint8_t cmd) {
digitalWrite(_dc, LOW);
_spi->transfer(cmd);
digitalWrite(_dc, HIGH);
}
// Private functions
void setGeometry(OLEDDISPLAY_GEOMETRY g, uint16_t width, uint16_t height) {
this->geometry = g;
switch (g) {
case GEOMETRY_128_128:
this->displayWidth = 128;
this->displayHeight = 128;
break;
case GEOMETRY_128_64:
this->displayWidth = 128;
this->displayHeight = 64;
break;
case GEOMETRY_128_32:
this->displayWidth = 128;
this->displayHeight = 32;
break;
case GEOMETRY_64_48:
this->displayWidth = 64;
this->displayHeight = 48;
break;
case GEOMETRY_64_32:
this->displayWidth = 64;
this->displayHeight = 32;
break;
case GEOMETRY_RAWMODE:
this->displayWidth = width > 0 ? width : 128;
this->displayHeight = height > 0 ? height : 64;
break;
}
uint8_t tmp=displayHeight % 8;
uint8_t _buffheight=displayHeight / 8;
if(tmp!=0)
_buffheight++;
this->displayBufferSize = displayWidth * _buffheight ;
}
};
#endif
Loading…
Cancel
Save