Compare commits

..

No commits in common. "master" and "false_preamble" have entirely different histories.

26 changed files with 295 additions and 1521 deletions

View file

@ -96,17 +96,6 @@ void BLESerial::flush() {
}
}
void BLESerial::disconnect() {
if (ble_server->getConnectedCount() > 0) {
uint16_t conn_id = ble_server->getConnId();
// Serial.printf("Have connected: %d\n", conn_id);
ble_server->disconnect(conn_id);
// Serial.println("Disconnected");
} else {
// Serial.println("No connected");
}
}
void BLESerial::begin(const char *name) {
ConnectedDeviceCount = 0;
BLEDevice::init(name);
@ -121,10 +110,7 @@ void BLESerial::begin(const char *name) {
BLEDevice::setSecurityCallbacks(this);
SetupSerialService();
this->startAdvertising();
}
void BLESerial::startAdvertising() {
ble_adv = BLEDevice::getAdvertising();
ble_adv->addServiceUUID(BLE_SERIAL_SERVICE_UUID);
ble_adv->setMinPreferred(0x20);
@ -133,11 +119,6 @@ void BLESerial::startAdvertising() {
ble_adv->start();
}
void BLESerial::stopAdvertising() {
ble_adv = BLEDevice::getAdvertising();
ble_adv->stop();
}
void BLESerial::end() { BLEDevice::deinit(); }
void BLESerial::onWrite(BLECharacteristic *characteristic) {

View file

@ -78,9 +78,6 @@ public:
void begin(const char *name);
void end();
void disconnect();
void startAdvertising();
void stopAdvertising();
void onWrite(BLECharacteristic *characteristic);
int available();
int peek();

View file

@ -38,7 +38,6 @@
BLEUart SerialBT(BLE_RX_BUF);
BLEDis bledis;
BLEBas blebas;
bool SerialBT_init = false;
#endif
#define BT_PAIRING_TIMEOUT 35000
@ -170,42 +169,31 @@ char bt_devname[11];
}
#elif HAS_BLE == true
bool bt_setup_hw(); void bt_security_setup();
BLESecurity *ble_security = new BLESecurity();
bool ble_authenticated = false;
uint32_t pairing_pin = 0;
void bt_flush() { if (bt_state == BT_STATE_CONNECTED) { SerialBT.flush(); } }
void bt_start() {
// Serial.println("BT start");
void bt_disable_pairing() {
display_unblank();
if (bt_state == BT_STATE_OFF) {
bt_state = BT_STATE_ON;
SerialBT.begin(bt_devname);
SerialBT.setTimeout(10);
}
bt_allow_pairing = false;
bt_ssp_pin = 0;
bt_state = BT_STATE_ON;
}
void bt_stop() {
// Serial.println("BT stop");
display_unblank();
if (bt_state != BT_STATE_OFF) {
bt_allow_pairing = false;
bt_state = BT_STATE_OFF;
SerialBT.end();
}
void bt_passkey_notify_callback(uint32_t passkey) {
// Serial.printf("Got passkey notification: %d\n", passkey);
bt_ssp_pin = passkey;
bt_state = BT_STATE_PAIRING;
bt_allow_pairing = true;
bt_pairing_started = millis();
kiss_indicate_btpin();
}
bool bt_init() {
// Serial.println("BT init");
bt_state = BT_STATE_OFF;
if (bt_setup_hw()) {
if (bt_enabled && !console_active) bt_start();
return true;
} else {
return false;
}
bool bt_confirm_pin_callback(uint32_t pin) {
// Serial.printf("Confirm PIN callback: %d\n", pin);
return true;
}
void bt_debond_all() {
@ -217,44 +205,6 @@ char bt_devname[11];
free(dev_list);
}
void bt_enable_pairing() {
// Serial.println("BT enable pairing");
display_unblank();
if (bt_state == BT_STATE_OFF) bt_start();
bt_security_setup();
bt_allow_pairing = true;
bt_pairing_started = millis();
bt_state = BT_STATE_PAIRING;
bt_ssp_pin = pairing_pin;
}
void bt_disable_pairing() {
// Serial.println("BT disable pairing");
display_unblank();
bt_allow_pairing = false;
bt_ssp_pin = 0;
bt_state = BT_STATE_ON;
}
void bt_passkey_notify_callback(uint32_t passkey) {
// Serial.printf("Got passkey notification: %d\n", passkey);
if (bt_allow_pairing) {
bt_ssp_pin = passkey;
bt_pairing_started = millis();
kiss_indicate_btpin();
} else {
// Serial.println("Pairing not allowed, re-init");
SerialBT.disconnect();
}
}
bool bt_confirm_pin_callback(uint32_t pin) {
// Serial.printf("Confirm PIN callback: %d\n", pin);
return true;
}
void bt_update_passkey() {
// Serial.println("Updating passkey");
pairing_pin = random(899999)+100000;
@ -271,6 +221,31 @@ char bt_devname[11];
return ble_authenticated;
}
void bt_security_setup() {
uint32_t passkey = bt_passkey_callback();
// Serial.printf("Executing BT security setup, passkey is %d\n", passkey);
uint8_t key_size = 16;
uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND;
uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_ENABLE;
uint8_t oob_support = ESP_BLE_OOB_DISABLE;
esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT;
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, &auth_option, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t));
}
bool bt_security_request_callback() {
if (bt_allow_pairing) {
// Serial.println("Accepting security request");
@ -285,15 +260,11 @@ char bt_devname[11];
if (auth_result.success == true) {
// Serial.println("Authentication success");
ble_authenticated = true;
if (bt_state == BT_STATE_PAIRING) {
// Serial.println("Pairing complete, disconnecting");
delay(2000); SerialBT.disconnect();
} else { bt_state = BT_STATE_CONNECTED; }
bt_state = BT_STATE_CONNECTED;
} else {
// Serial.println("Authentication fail");
ble_authenticated = false;
bt_state = BT_STATE_ON;
bt_update_passkey();
bt_security_setup();
}
bt_allow_pairing = false;
@ -301,16 +272,16 @@ char bt_devname[11];
}
void bt_connect_callback(BLEServer *server) {
uint16_t conn_id = server->getConnId();
// uint16_t conn_id = server->getConnId();
// Serial.printf("Connected: %d\n", conn_id);
display_unblank();
ble_authenticated = false;
if (bt_state != BT_STATE_PAIRING) { bt_state = BT_STATE_CONNECTED; }
bt_state = BT_STATE_CONNECTED;
cable_state = CABLE_STATE_DISCONNECTED;
}
void bt_disconnect_callback(BLEServer *server) {
uint16_t conn_id = server->getConnId();
// uint16_t conn_id = server->getConnId();
// Serial.printf("Disconnected: %d\n", conn_id);
display_unblank();
ble_authenticated = false;
@ -318,7 +289,6 @@ char bt_devname[11];
}
bool bt_setup_hw() {
// Serial.println("BT setup hw");
if (!bt_ready) {
if (EEPROM.read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) {
bt_enabled = true;
@ -350,30 +320,45 @@ char bt_devname[11];
} else { return false; }
}
void bt_security_setup() {
// Serial.println("Executing BT security setup");
if (pairing_pin == 0) { bt_update_passkey(); }
uint32_t passkey = pairing_pin;
// Serial.printf("Passkey is %d\n", passkey);
void bt_start() {
display_unblank();
if (bt_state == BT_STATE_OFF) {
bt_state = BT_STATE_ON;
SerialBT.begin(bt_devname);
SerialBT.setTimeout(10);
}
}
uint8_t key_size = 16;
uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
void bt_stop() {
display_unblank();
if (bt_state != BT_STATE_OFF) {
bt_allow_pairing = false;
bt_state = BT_STATE_OFF;
SerialBT.end();
}
}
esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND;
uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_ENABLE;
uint8_t oob_support = ESP_BLE_OOB_DISABLE;
bool bt_init() {
bt_state = BT_STATE_OFF;
if (bt_setup_hw()) {
if (bt_enabled && !console_active) bt_start();
return true;
} else {
return false;
}
}
esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT;
void bt_enable_pairing() {
display_unblank();
if (bt_state == BT_STATE_OFF) bt_start();
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, &auth_option, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t));
bt_security_setup();
//bt_debond_all();
//bt_update_passkey();
bt_allow_pairing = true;
bt_pairing_started = millis();
bt_state = BT_STATE_PAIRING;
}
void update_bt() {
@ -389,12 +374,9 @@ 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() {
// Serial.println("BT Stop");
if (bt_state != BT_STATE_OFF) {
bt_allow_pairing = false;
bt_state = BT_STATE_OFF;
@ -404,19 +386,16 @@ char bt_devname[11];
void bt_flush() { if (bt_state == BT_STATE_CONNECTED) { SerialBT.flushTXD(); } }
void bt_disable_pairing() {
// Serial.println("BT Disable pairing");
bt_allow_pairing = false;
pairing_pin = 0;
bt_ssp_pin = 0;
bt_state = BT_STATE_ON;
}
void bt_pairing_complete(uint16_t conn_handle, uint8_t auth_status) {
// Serial.println("BT pairing complete");
BLEConnection* connection = Bluefruit.Connection(conn_handle);
if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) {
BLEConnection* connection = Bluefruit.Connection(conn_handle);
ble_gap_conn_sec_mode_t security = connection->getSecureMode();
// Serial.println("Bonding success");
// On the NRF52 it is not possible with the Arduino library to reject
// requests from devices with no IO capabilities, which would allow
@ -433,26 +412,26 @@ char bt_devname[11];
// Requires investigation.
if (security.sm == 1 && security.lv >= 3) {
// Serial.println("Auth level success");
bt_state = BT_STATE_CONNECTED;
cable_state = CABLE_STATE_DISCONNECTED;
connection->disconnect();
bt_disable_pairing();
} else {
// Serial.println("Auth level failure, debonding");
if (connection->bonded()) { connection->removeBondKey(); }
if (connection->bonded()) {
connection->removeBondKey();
}
connection->disconnect();
bt_disable_pairing();
}
} else {
// Serial.println("Bonding failure");
connection->disconnect();
bt_disable_pairing();
bt_ssp_pin = 0;
}
}
bool bt_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) {
// Serial.println("Passkey callback");
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;
}
@ -460,7 +439,6 @@ char bt_devname[11];
}
void bt_connect_callback(uint16_t conn_handle) {
// Serial.println("Connect callback");
bt_state = BT_STATE_CONNECTED;
cable_state = CABLE_STATE_DISCONNECTED;
@ -471,26 +449,12 @@ char bt_devname[11];
}
void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason) {
// Serial.println("Disconnect callback");
if (reason != BLE_GAP_SEC_STATUS_SUCCESS) {
bt_state = BT_STATE_ON;
}
}
void bt_update_passkey() {
// Serial.println("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() {
// Serial.println("Setup HW");
if (!bt_ready) {
#if HAS_EEPROM
if (EEPROM.read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) {
@ -504,10 +468,6 @@ char bt_devname[11];
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
@ -517,7 +477,6 @@ char bt_devname[11];
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
@ -545,24 +504,20 @@ char bt_devname[11];
}
void bt_start() {
// Serial.println("BT Start");
if (bt_state == BT_STATE_OFF) {
Bluefruit.setName(bt_devname);
bledis.setManufacturer(BLE_MANUFACTURER);
bledis.setModel(BLE_MODEL);
// start device information service
bledis.begin();
SerialBT.bufferTXD(true); // enable buffering
SerialBT.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); // enable encryption for BLE serial
SerialBT.begin();
blebas.begin();
// Guard to ensure SerialBT service is not duplicated through BT being power cycled
if (!SerialBT_init) {
SerialBT.bufferTXD(true); // enable buffering
SerialBT.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); // enable encryption for BLE serial
SerialBT.begin();
SerialBT_init = true;
}
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
@ -580,7 +535,6 @@ char bt_devname[11];
}
bool bt_init() {
// Serial.println("BT init");
bt_state = BT_STATE_OFF;
if (bt_setup_hw()) {
if (bt_enabled && !console_active) bt_start();
@ -591,22 +545,12 @@ char bt_devname[11];
}
void bt_enable_pairing() {
// Serial.println("BT enable pairing");
if (bt_state == BT_STATE_OFF) bt_start();
uint32_t pin = bt_get_passkey();
char pin_char[6];
sprintf(pin_char,"%lu", pin);
Bluefruit.Security.setPIN(pin_char);
bt_allow_pairing = true;
bt_pairing_started = millis();
bt_state = BT_STATE_PAIRING;
kiss_indicate_btpin();
}
void bt_debond_all() { }
void update_bt() {
if (bt_allow_pairing && millis()-bt_pairing_started >= BT_PAIRING_TIMEOUT) {
bt_disable_pairing();

133
Boards.h
View file

@ -65,11 +65,6 @@
#define MODEL_DB 0xDB // LilyGO T-Beam Supreme, 433 MHz
#define MODEL_DC 0xDC // LilyGO T-Beam Supreme, 868 MHz
#define PRODUCT_XIAO_S3 0xEB
#define BOARD_XIAO_S3 0x3E
#define MODEL_DE 0xDE // Xiao ESP32S3 with Wio-SX1262 module, 433 MHz
#define MODEL_DD 0xDD // Xiao ESP32S3 with Wio-SX1262 module, 868 MHz
#define PRODUCT_T32_10 0xB2
#define BOARD_LORA32_V1_0 0x39
#define MODEL_BA 0xBA // LilyGO T3 v1.0, 433 MHz
@ -95,10 +90,6 @@
#define MODEL_C5 0xC5 // Heltec Lora32 v3, 433 MHz
#define MODEL_CA 0xCA // Heltec Lora32 v3, 868 MHz
#define PRODUCT_H32_V4 0xC3
#define BOARD_HELTEC32_V4 0x3F
#define MODEL_C8 0xC8 // Heltec Lora32 v3, 850-950 MHz, 28dBm
#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
@ -149,22 +140,15 @@
#endif
#endif
#define LORA_PA_UNKNOWN 0x00
#define LORA_PA_GC1109 0x01
#define LORA_PA_KCT8103L 0x02
#define HAS_DISPLAY false
#define HAS_BLUETOOTH false
#define HAS_BLE false
#define HAS_WIFI false
#define HAS_TCXO false
#define HAS_PMU false
#define HAS_NP false
#define HAS_EEPROM false
#define HAS_INPUT false
#define HAS_SLEEP false
#define HAS_LORA_PA false
#define HAS_LORA_LNA false
#define PIN_DISP_SLEEP -1
#define VALIDATE_FIRMWARE true
@ -216,7 +200,6 @@
#define EEPROM_SIZE 1024
#define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
#define CONFIG_OFFSET 0
#define GPS_BAUD_RATE 9600
#define PIN_GPS_TX 12
@ -227,7 +210,7 @@
#define HAS_CONSOLE true
#define HAS_EEPROM true
const int pin_cs = 4;
const int pin_reset = 33;
const int pin_reset = 36;
const int pin_dio = 39;
const int pin_led_rx = 14;
const int pin_led_tx = 32;
@ -255,7 +238,7 @@
#define HAS_TCXO true
#define HAS_BUSY true
#define DIO2_AS_RF_SWITCH true
#define OCP_TUNED 0x28
#define OCP_TUNED 0x38
const int pin_busy = 32;
const int pin_dio = 33;
const int pin_tcxo_enable = -1;
@ -268,7 +251,7 @@
#define HAS_CONSOLE true
#define HAS_EEPROM true
const int pin_cs = 4;
const int pin_reset = 33;
const int pin_reset = 36;
const int pin_dio = 39;
const int pin_led_rx = 14;
const int pin_led_tx = 32;
@ -351,7 +334,6 @@
#elif BOARD_MODEL == BOARD_HELTEC32_V3
#define IS_ESP32S3 true
#define HAS_DISPLAY true
#define HAS_WIFI true
#define HAS_BLUETOOTH false
#define HAS_BLE true
#define HAS_PMU true
@ -361,7 +343,7 @@
#define HAS_SLEEP true
#define PIN_WAKEUP GPIO_NUM_0
#define WAKEUP_LEVEL 0
#define OCP_TUNED 0x28
#define OCP_TUNED 0x38
const int pin_btn_usr1 = 0;
@ -388,65 +370,6 @@
const int pin_miso = 11;
const int pin_sclk = 9;
#elif BOARD_MODEL == BOARD_HELTEC32_V4
#define IS_ESP32S3 true
#define HAS_DISPLAY true
#define HAS_BLUETOOTH false
#define HAS_BLE true
#define HAS_WIFI true
#define HAS_PMU true
#define HAS_CONSOLE true
#define HAS_EEPROM true
#define HAS_INPUT true
#define HAS_SLEEP true
#define HAS_LORA_PA true
#define HAS_LORA_LNA true
#define PIN_WAKEUP GPIO_NUM_0
#define WAKEUP_LEVEL 0
#define OCP_TUNED 0x28
#define Vext GPIO_NUM_36
#define LORA_PA_MODEL LORA_PA_UNKNOWN;
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
#define MODEM SX1262
#define HAS_TCXO true
const int pin_tcxo_enable = -1;
#define HAS_BUSY true
#define DIO2_AS_RF_SWITCH true
#define LNA_GD_THRSHLD (-109)
#define LNA_GD_LIMIT (-89)
#define LORA_LNA_GAIN 17
#define LORA_LNA_GVT 12
#define LORA_PA_PWR_EN 7
#define LORA_PA_CSD 2 // Same pin on GC1109
#define LORA_PA_CPS 46 // Same pin on GC1109
#define LORA_PA_CTX 5 // Only used on KCT8103
#define PA_MAX_OUTPUT 28
#define PA_GAIN_POINTS 22
#define LORA_LNA_KCT8103L_GAIN 21
const int PA_GC1109_VALUES[PA_GAIN_POINTS] = {11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 9, 8, 7};
const int PA_KCT8103L_VALUES[PA_GAIN_POINTS] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 11, 11, 10, 9, 8, 7};
const int pin_cs = 8;
const int pin_busy = 13;
const int pin_dio = 14;
const int pin_reset = 12;
const int pin_mosi = 10;
const int pin_miso = 11;
const int pin_sclk = 9;
#elif BOARD_MODEL == BOARD_RNODE_NG_20
#define HAS_DISPLAY true
#define HAS_BLUETOOTH true
@ -499,7 +422,6 @@
#define IS_ESP32S3 true
#define HAS_DISPLAY true
#define HAS_CONSOLE true
#define HAS_WIFI true
#define HAS_BLUETOOTH false
#define HAS_BLE true
#define HAS_PMU true
@ -573,7 +495,6 @@
#define HAS_DISPLAY false
#define HAS_CONSOLE false
#define HAS_WIFI true
#define HAS_BLUETOOTH false
#define HAS_BLE true
#define HAS_PMU true
@ -626,11 +547,10 @@
#define DIO2_AS_RF_SWITCH true
#define HAS_BUSY true
#define HAS_TCXO true
#define OCP_TUNED 0x28
#define OCP_TUNED 0x38
#define HAS_DISPLAY true
#define HAS_CONSOLE true
#define HAS_WIFI true
#define HAS_BLUETOOTH false
#define HAS_BLE true
#define HAS_PMU true
@ -673,47 +593,6 @@
#endif
#endif
#elif BOARD_MODEL == BOARD_XIAO_S3
#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
#define HAS_CONSOLE true
#define HAS_WIFI true
#define HAS_BLUETOOTH false
#define HAS_BLE true
#define HAS_NP false
#define HAS_SD false
#define HAS_EEPROM true
#define HAS_INPUT true
#define HAS_SLEEP true
#define PIN_WAKEUP GPIO_NUM_21
#define WAKEUP_LEVEL 0
const int pin_btn_usr1 = 21;
const int pin_cs = 41;
const int pin_reset = 42;
const int pin_sclk = 7;
const int pin_mosi = 9;
const int pin_miso = 8;
const int pin_tcxo_enable = -1;
const int pin_dio = 39;
const int pin_busy = 40;
#if HAS_NP == false
#if defined(EXTERNAL_LEDS)
const int pin_led_rx = 48;
const int pin_led_tx = 48;
#else
const int pin_led_rx = 48;
const int pin_led_tx = 48;
#endif
#endif
#else
#error An unsupported ESP32 board was selected. Cannot compile RNode firmware.
#endif
@ -929,7 +808,7 @@
// Default OCP value if not specified
// in board configuration
#ifndef OCP_TUNED
#define OCP_TUNED 0x28
#define OCP_TUNED 0x38
#endif
#ifndef NP_M

View file

@ -20,7 +20,7 @@
#define CONFIG_H
#define MAJ_VERS 0x01
#define MIN_VERS 0x56
#define MIN_VERS 0x51
#define MODE_HOST 0x11
#define MODE_TNC 0x12
@ -40,17 +40,6 @@
bool bt_enabled = false;
bool bt_allow_pairing = false;
#define WR_CHANNEL_DEFAULT 1
#define WR_WIFI_OFF 0x00
#define WR_WIFI_STA 0x01
#define WR_WIFI_AP 0x02
#define WR_STATE_NA 0xff
#define WR_STATE_OFF 0x00
#define WR_STATE_ON 0x01
#define WR_STATE_CONNECTED 0x02
uint8_t wr_state = WR_STATE_OFF;
uint8_t wr_channel = WR_CHANNEL_DEFAULT;
#define M_FRQ_S 27388122
#define M_FRQ_R 27388061
bool console_active = false;
@ -65,7 +54,6 @@
bool mw_radio_online = false;
#define eeprom_addr(a) (a+EEPROM_OFFSET)
#define config_addr(a) (a+CONFIG_OFFSET)
#if (MODEM == SX1262 || MODEM == SX1280) && defined(NRF52840_XXAA)
SPIClass spiModem(NRF_SPIM2, pin_miso, pin_sclk, pin_mosi);
@ -86,8 +74,6 @@
#define LORA_PREAMBLE_FAST_DELTA 18
#define LORA_FAST_THRESHOLD_BPS 30E3
#define LORA_LIMIT_THRESHOLD_BPS 60E3
#define LORA_GUARD_THRESHOLD_BPS 14E3
#define LORA_FAST_GUARD_MS 48
long lora_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN;
long lora_preamble_time_ms = 0;
long lora_header_time_ms = 0;
@ -96,7 +82,6 @@
float lora_us_per_byte = 0.0;
bool lora_low_datarate = false;
bool lora_limit_rate = false;
bool lora_guard_rate = false;
// CSMA Parameters
#define CSMA_SIFS_MS 0
@ -110,9 +95,7 @@
#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 11
#define CSMA_RFENV_RECAL_MS 2500
#define CSMA_RFENV_RECAL_LIMIT_DB -83
#define CSMA_INFR_THRESHOLD_DB 12
bool interference_detected = false;
bool avoid_interference = true;
int csma_slot_ms = CSMA_SLOT_MIN_MS;
@ -151,7 +134,7 @@
uint8_t model = 0x00;
uint8_t hwrev = 0x00;
#define NOISE_FLOOR_SAMPLES 128
#define NOISE_FLOOR_SAMPLES 64
int noise_floor = -292;
int current_rssi = -292;
int last_rssi = -292;
@ -159,7 +142,6 @@
uint8_t last_snr_raw = 0x80;
uint8_t seq = 0xFF;
uint16_t read_len = 0;
uint16_t host_write_len = 0;
// Incoming packet buffer
uint8_t pbuf[MTU];

View file

@ -4,10 +4,10 @@ import sys
import shutil
packages = {
"rns": "rns-1.1.9-py3-none-any.whl",
"nomadnet": "nomadnet-0.9.11-py3-none-any.whl",
"lxmf": "lxmf-0.9.6-py3-none-any.whl",
"rnsh": "rnsh-0.1.9-py3-none-any.whl",
"rns": "rns-0.8.9-py3-none-any.whl",
"nomadnet": "nomadnet-0.5.6-py3-none-any.whl",
"lxmf": "lxmf-0.5.8-py3-none-any.whl",
"rnsh": "rnsh-0.1.4-py3-none-any.whl",
}
DEFAULT_TITLE = "RNode Bootstrap Console"
@ -37,7 +37,7 @@ document_start = """
document_end = """</body></html>"""
menu_md = """<center markdown=\"1\"><span class="menu">[Start]({CONTENT_PATH}index.html) | [Replicate]({CONTENT_PATH}replicate.html) | [Software]({CONTENT_PATH}software.html) | [Learn]({CONTENT_PATH}learn.html) | [Help](help.html) | [Contribute]({CONTENT_PATH}contribute.html)</span></center>"""
menu_md = """<center><span class="menu">[Start]({CONTENT_PATH}index.html) | [Replicate]({CONTENT_PATH}replicate.html) | [Software]({CONTENT_PATH}software.html) | [Learn]({CONTENT_PATH}learn.html) | [Help](help.html) | [Contribute]({CONTENT_PATH}contribute.html)</span></center>"""
manual_redirect = """
<!DOCTYPE html>
@ -150,8 +150,8 @@ def generate_html(f, root_path):
print("Found topic: "+str(topic)+", rt "+str(rt))
md = md.replace(rt, tl)
menu_html = markdown.markdown(menu_md.replace("{CONTENT_PATH}", root_path), extensions=["md_in_html", "markdown.extensions.fenced_code", "sane_lists"]).replace("<p></p>", "")
page_html = markdown.markdown(md, extensions=["md_in_html", "markdown.extensions.fenced_code"]).replace("{ASSET_PATH}", root_path)
menu_html = markdown.markdown(menu_md.replace("{CONTENT_PATH}", root_path), extensions=["markdown.extensions.fenced_code", "sane_lists"]).replace("<p></p>", "")
page_html = markdown.markdown(md, extensions=["markdown.extensions.fenced_code"]).replace("{ASSET_PATH}", root_path)
page_html = page_html.replace("{LXMF_ADDRESS}", LXMF_ADDRESS)
for pkg_name in packages:
page_html = page_html.replace("{PKG_"+pkg_name+"}", "pkg/"+pkg_name+".zip")
@ -174,13 +174,12 @@ mf.write(help_redirect)
mf.close()
def optimise_manual(path):
pm = 180
pm = 45
scale_imgs = [
("_images/board_rnodev2.png", pm),
("_images/board_rnode.png", pm),
("_images/board_heltec32v20.png", pm),
("_images/board_heltec32v30.png", pm),
("_images/board_heltec32v4.png", pm),
("_images/board_t3v21.png", pm),
("_images/board_t3v20.png", pm),
("_images/board_t3v10.png", pm),
@ -194,41 +193,17 @@ def optimise_manual(path):
("_images/meshchat_1.webp", pm),
("_images/radio_is5ac.png", pm),
("_images/radio_rblhg5.png", pm),
("_images/rbrowser.webp", pm),
("_images/rnphone.webp", pm),
("_images/retibbs.webp", pm),
("_images/meshchatx.webp", pm),
("_images/lxst_phone.webp", pm),
("_images/columba.webp", pm),
("_static/rns_logo_512.png", 256),
("../images/bg_h_1.webp", pm),
("../../images/3_conv.webp", pm/2),
("../../images/an1.webp", pm/2),
("../../images/bg1ds1.webp", pm/2),
("../../images/bg1ds2.webp", pm/2),
("../../images/bg_h_1.webp", pm/2),
("../../images/bg_h_2.webp", pm/2),
("../../images/g1p.webp", pm/2),
("../../images/g2p.webp", pm/2),
("../../images/g3p.webp", pm/2),
("../../images/g4p.webp", pm/2),
("../../images/lora_rnodes.webp", pm/2),
("../../images/nn_an.webp", pm/2),
("../../images/nn_conv.webp", pm/2),
("../../images/nn_init.webp", pm/2),
]
import subprocess
import shlex
for i,s in scale_imgs:
fp = path+"/"+i
input_file = fp
output_file = input_file
resize = "convert "+input_file+" -quality 25 -resize "+str(s)+" "+output_file
resize = "convert "+fp+" -quality 25 -resize "+str(s)+" "+fp
print(resize)
subprocess.call(shlex.split(resize), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
# if output_file != input_file and os.path.isfile(input_file): os.unlink(input_file)
remove_files = [
"objects.inv",
@ -242,20 +217,6 @@ def optimise_manual(path):
"_static/_sphinx_javascript_frameworks_compat.js",
"_static/scripts/furo.js.LICENSE.txt",
"_static/styles/furo-extensions.css.map",
"_images/board_rak4631.png",
"_images/board_rnodev2.png",
"_images/board_t114.png",
"_images/board_t3s3.png",
"_images/board_t3v10.png",
"_images/board_t3v20.png",
"_images/board_t3v21.png",
"_images/board_tbeam.png",
"_images/board_tdeck.png",
"_images/board_techo.png",
"_images/board_tbeam_supreme.png",
"_images/board_opencomxl.png",
"_images/board_heltec32v20.png",
"_images/board_heltec32v30.png",
# "_static/pygments.css",
# "_static/language_data.js",
# "_static/searchtools.js",

View file

@ -2,6 +2,7 @@
[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.
@ -30,9 +31,10 @@ 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**, **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 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 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** (or other relevant) interrupt signal *from* the chip.
- The module must also expose the *reset* line of the chip, and provide the **DIO0** 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.
@ -54,17 +56,12 @@ 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](https://github.com/markqvist/RNode_Firmware/blob/master/Config.h) file of the [RNode Firmware](https://unsigned.io/rnode_firmware).
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).
### 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:
## 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).
```txt
pip install rns
```
If installation goes well, you can now move on to the next step.
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.
> *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!
@ -76,6 +73,24 @@ 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

View file

@ -1,8 +1,8 @@
[title]: <> (Sideband)
## Sideband
Sideband is an LXMF client for Android, Linux, Windows and macOS. It has built-in support for communicating over RNodes, and many other mediums, such as Packet Radio, WiFi, I2P, or anything else Reticulum supports.
Sideband is an LXMF client for Android, Linux and macOS. It has built-in support for communicating over RNodes, and many other mediums, such as Packet Radio, WiFi, I2P, or anything else Reticulum supports.
Sideband also supports voice calls, file transfers, and exchanging messages through encrypted QR-codes on paper, or through messages embedded directly in lxm:// links.
Sideband also supports exchanging messages through encrypted QR-codes on paper, or through messages embedded directly in lxm:// links.
![Screenshot]({ASSET_PATH}gfx/sideband.webp)
@ -10,3 +10,4 @@ The installation files for the Sideband program is too large to be included on t
- The [Sideband page](https://unsigned.io/sideband/) on [unsigned.io](https://unsigned.io/)
- The [GitHub release page for Sideband](https://github.com/markqvist/Sideband/releases/latest)
- The [IzzyOnDroid repository for F-Droid](https://android.izzysoft.de/repo/apk/io.unsigned.sideband)

140
Display.h
View file

@ -60,11 +60,6 @@
#define DISP_ADDR 0x3C
#define SCL_OLED 18
#define SDA_OLED 17
#elif BOARD_MODEL == BOARD_HELTEC32_V4
#define DISP_RST 21
#define DISP_ADDR 0x3C
#define SCL_OLED 18
#define SDA_OLED 17
#elif BOARD_MODEL == BOARD_RAK4631
// RAK1921/SSD1306
#define DISP_RST -1
@ -90,12 +85,6 @@
#define SCL_OLED 18
#define SDA_OLED 17
#define DISP_CUSTOM_ADDR false
#elif BOARD_MODEL == BOARD_XIAO_S3
#define DISP_RST -1
#define DISP_ADDR 0x3C
#define SCL_OLED 6
#define SDA_OLED 5
#define DISP_CUSTOM_ADDR true
#else
#define DISP_RST -1
#define DISP_ADDR 0x3C
@ -152,7 +141,6 @@ bool device_firmware_ok();
#define WATERFALL_SIZE 46
int waterfall[WATERFALL_SIZE];
int waterfall_meta[WATERFALL_SIZE];
int waterfall_head = 0;
int p_ad_x = 0;
@ -163,25 +151,6 @@ int p_as_y = 0;
GFXcanvas1 stat_area(64, 64);
GFXcanvas1 disp_area(64, 64);
static const uint8_t one_counts[256] = {
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 1, 1, 1,
1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1,
1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1,
1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1,
1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0,
0, 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0
};
void fillRect(int16_t x, int16_t y, int16_t width, int16_t height, uint16_t colour);
void update_area_positions() {
@ -290,18 +259,6 @@ bool display_init() {
digitalWrite(pin_display_en, HIGH);
delay(50);
Wire.begin(SDA_OLED, SCL_OLED);
#elif BOARD_MODEL == BOARD_HELTEC32_V4
// enable vext / pin 36
pinMode(Vext, OUTPUT);
digitalWrite(Vext, LOW);
delay(50);
int pin_display_en = 21;
pinMode(pin_display_en, OUTPUT);
digitalWrite(pin_display_en, LOW);
delay(50);
digitalWrite(pin_display_en, HIGH);
delay(50);
Wire.begin(SDA_OLED, SCL_OLED);
#elif BOARD_MODEL == BOARD_LORA32_V1_0
int pin_display_en = 16;
digitalWrite(pin_display_en, LOW);
@ -321,8 +278,6 @@ bool display_init() {
#endif
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
Wire.begin(SDA_OLED, SCL_OLED);
#elif BOARD_MODEL == BOARD_XIAO_S3
Wire.begin(SDA_OLED, SCL_OLED);
#endif
#if HAS_EEPROM
@ -419,9 +374,6 @@ bool display_init() {
#elif BOARD_MODEL == BOARD_HELTEC32_V3
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(1);
#elif BOARD_MODEL == BOARD_HELTEC32_V4
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(1);
#elif BOARD_MODEL == BOARD_HELTEC_T114
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(1);
@ -540,35 +492,12 @@ void drawBitmap(int16_t startX, int16_t startY, const uint8_t* bitmap, int16_t b
#endif
}
extern uint8_t wifi_mode;
extern bool wifi_is_connected();
extern bool wifi_host_is_connected();
void draw_cable_icon(int px, int py) {
#if HAS_WIFI
if (wifi_mode == WR_WIFI_OFF) {
if (cable_state == CABLE_STATE_DISCONNECTED) { stat_area.drawBitmap(px, py, bm_cable+0*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); }
else if (cable_state == CABLE_STATE_CONNECTED) { stat_area.drawBitmap(px, py, bm_cable+1*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); }
} else {
if (wifi_mode == WR_WIFI_STA) {
if (wifi_is_connected()) {
stat_area.drawBitmap(px, py, bm_wifi+3*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK);
if (!wifi_host_is_connected()) { stat_area.fillRect(px+5, py+12, 6, 3, SSD1306_BLACK); }
} else { stat_area.drawBitmap(px, py, bm_wifi+2*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); }
} else if (wifi_mode == WR_WIFI_AP) {
if (wifi_host_is_connected()) { stat_area.drawBitmap(px, py, bm_wifi+1*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); }
else { stat_area.drawBitmap(px, py, bm_wifi+0*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); }
} else {
if (cable_state == CABLE_STATE_DISCONNECTED) { stat_area.drawBitmap(px, py, bm_cable+0*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); }
else if (cable_state == CABLE_STATE_CONNECTED) { stat_area.drawBitmap(px, py, bm_cable+1*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); }
}
}
#else
if (cable_state == CABLE_STATE_DISCONNECTED) { stat_area.drawBitmap(px, py, bm_cable+0*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); }
else if (cable_state == CABLE_STATE_CONNECTED) { stat_area.drawBitmap(px, py, bm_cable+1*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); }
#endif
if (cable_state == CABLE_STATE_DISCONNECTED) {
stat_area.drawBitmap(px, py, bm_cable+0*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK);
} else if (cable_state == CABLE_STATE_CONNECTED) {
stat_area.drawBitmap(px, py, bm_cable+1*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK);
}
}
void draw_bt_icon(int px, int py) {
@ -617,9 +546,6 @@ void draw_battery_bars(int px, int py) {
}
if (battery_state == BATTERY_STATE_CHARGING && !disable_charge_status) {
float battery_prog = battery_percent;
if (battery_prog > 85) { battery_prog = 84; }
if (charge_tick < battery_prog ) { charge_tick = battery_prog; }
battery_value = charge_tick;
charge_tick += 3;
if (charge_tick > 100) charge_tick = 0;
@ -683,7 +609,7 @@ void draw_quality_bars(int px, int py) {
}
}
#if MODEM == SX1280
#if MODE == SX1280
#define S_RSSI_MIN -105.0
#define S_RSSI_MAX -65.0
#else
@ -723,24 +649,18 @@ void draw_signal_bars(int px, int py) {
#define WF_RSSI_MIN -135
#define WF_RSSI_SPAN (WF_RSSI_MAX-WF_RSSI_MIN)
#define WF_PIXEL_WIDTH 10
#define WF_M_RX 0x00
#define WF_M_TX 0x01
#define WF_M_NTFR 0x02
void draw_waterfall(int px, int py) {
int rssi_val = current_rssi;
if (rssi_val < WF_RSSI_MIN) rssi_val = WF_RSSI_MIN;
if (rssi_val > WF_RSSI_MAX) rssi_val = WF_RSSI_MAX;
int rssi_normalised = ((rssi_val - WF_RSSI_MIN)*(1.0/WF_RSSI_SPAN))*WF_PIXEL_WIDTH;
if (display_tx) {
for (uint8_t i = 0; i < WF_TX_SIZE; i++) {
waterfall_meta[waterfall_head] = WF_M_TX;
for (uint8_t i; i < WF_TX_SIZE; i++) {
waterfall[waterfall_head++] = -1;
if (waterfall_head >= WATERFALL_SIZE) waterfall_head = 0;
}
display_tx = false;
} else {
if (interference_detected) { waterfall_meta[waterfall_head] = WF_M_NTFR; }
else { waterfall_meta[waterfall_head] = WF_M_RX; }
waterfall[waterfall_head++] = rssi_normalised;
if (waterfall_head >= WATERFALL_SIZE) waterfall_head = 0;
}
@ -749,13 +669,8 @@ void draw_waterfall(int px, int py) {
for (int i = 0; i < WATERFALL_SIZE; i++){
int wi = (waterfall_head+i)%WATERFALL_SIZE;
int ws = waterfall[wi];
int wm = waterfall_meta[wi];
if (ws > 0) {
if (wm == WF_M_RX) { stat_area.drawLine(px, py+i, px+ws-1, py+i, SSD1306_WHITE); }
else if (wm == WF_M_NTFR) {
uint8_t o = 0;
for (uint8_t ti = 0; ti < WF_PIXEL_WIDTH/2; ti++) { stat_area.drawPixel(px+ti*2+o, py+i, SSD1306_WHITE); }
}
stat_area.drawLine(px, py+i, px+ws-1, py+i, SSD1306_WHITE);
} else if (ws == -1) {
uint8_t o = i%2;
for (uint8_t ti = 0; ti < WF_PIXEL_WIDTH/2; ti++) {
@ -812,11 +727,6 @@ void update_stat_area() {
#define START_PAGE 0
const uint8_t pages = 3;
uint8_t disp_page = START_PAGE;
extern char bt_devname[11];
extern char bt_dh[16];
#if HAS_WIFI
extern IPAddress wr_device_ip;
#endif
void draw_disp_area() {
if (!device_init_done || firmware_update_mode) {
uint8_t p_by = 37;
@ -830,7 +740,7 @@ void draw_disp_area() {
if (!disp_ext_fb or bt_ssp_pin != 0) {
if (radio_online && display_diagnostics) {
disp_area.fillRect(0,8,disp_area.width(),37, SSD1306_BLACK); disp_area.fillRect(0,37,disp_area.width(),27, SSD1306_WHITE);
disp_area.setFont(SMALL_FONT); disp_area.setTextWrap(false); disp_area.setTextColor(SSD1306_WHITE); disp_area.setTextSize(1);
disp_area.setFont(SMALL_FONT); disp_area.setTextWrap(false); disp_area.setTextColor(SSD1306_WHITE);
disp_area.setCursor(2, 13);
disp_area.print("On");
@ -891,34 +801,10 @@ void draw_disp_area() {
disp_area.drawBitmap(32+2, 50, bm_hg_high, 5, 9, SSD1306_BLACK, SSD1306_WHITE);
} else {
if (device_signatures_ok()) { disp_area.drawBitmap(0, 0, bm_def_lc, disp_area.width(), 23, SSD1306_WHITE, SSD1306_BLACK); }
else { disp_area.drawBitmap(0, 0, bm_def, disp_area.width(), 23, SSD1306_WHITE, SSD1306_BLACK); }
bool display_ip = false;
#if HAS_WIFI
if (wifi_is_connected() && disp_page%2 == 1) { display_ip = true; }
#endif
if (display_ip) {
#if HAS_WIFI
uint8_t ones = 3+one_counts[wr_device_ip[0]]+one_counts[wr_device_ip[1]]+one_counts[wr_device_ip[2]]+one_counts[wr_device_ip[3]];
uint8_t chars = 7;
for (uint8_t i = 0; i<4; i++) { if (wr_device_ip[i] > 9) { chars++; } if (wr_device_ip[i] > 99) { chars++; } }
uint8_t width = chars*6-(ones*4);
int alignment_offset = disp_area.width()-width;
int ipxpos = alignment_offset;
disp_area.setFont(SMALL_FONT); disp_area.setTextWrap(false); disp_area.setTextColor(SSD1306_WHITE); disp_area.setTextSize(1);
disp_area.fillRect(0, 20, disp_area.width(), 17, SSD1306_BLACK);
disp_area.setCursor(3, 34-8); disp_area.print("WiFi IP:");
disp_area.setCursor(ipxpos, 34); disp_area.print(wr_device_ip);
#endif
if (device_signatures_ok()) {
disp_area.drawBitmap(0, 0, bm_def_lc, disp_area.width(), 37, SSD1306_WHITE, SSD1306_BLACK);
} else {
disp_area.setFont(SMALL_FONT); disp_area.setTextWrap(false); disp_area.setTextColor(SSD1306_WHITE); disp_area.setTextSize(2);
disp_area.fillRect(0, 20, disp_area.width(), 17, SSD1306_BLACK); uint8_t ofsc = 0;
if ((bt_dh[14] & 0b00001111) == 0x01) { ofsc += 8; }
if ((bt_dh[14] >> 4) == 0x01) { ofsc += 8; }
if ((bt_dh[15] & 0b00001111) == 0x01) { ofsc += 8; }
if ((bt_dh[15] >> 4) == 0x01) { ofsc += 8; }
disp_area.setCursor(17+ofsc, 32); disp_area.printf("%02X%02X", bt_dh[14], bt_dh[15]);
disp_area.drawBitmap(0, 0, bm_def, disp_area.width(), 37, SSD1306_WHITE, SSD1306_BLACK);
}
}
@ -1071,7 +957,6 @@ void update_display(bool blank = false) {
#if BOARD_MODEL == BOARD_HELTEC_T114
display.clear();
display.display();
digitalWrite(PIN_T114_TFT_BLGT, HIGH);
#elif BOARD_MODEL != BOARD_TDECK && BOARD_MODEL != BOARD_TECHO
display.clearDisplay();
display.display();
@ -1092,7 +977,6 @@ void update_display(bool blank = false) {
#if BOARD_MODEL == BOARD_HELTEC_T114
display.clear();
digitalWrite(PIN_T114_TFT_BLGT, LOW);
#elif BOARD_MODEL != BOARD_TDECK && BOARD_MODEL != BOARD_TECHO
display.clearDisplay();
#endif

View file

@ -46,7 +46,6 @@
#define CMD_STAT_PHYPRM 0x26
#define CMD_STAT_BAT 0x27
#define CMD_STAT_CSMA 0x28
#define CMD_STAT_TEMP 0x29
#define CMD_BLINK 0x30
#define CMD_RANDOM 0x40
@ -62,21 +61,13 @@
#define CMD_DISP_RCND 0x68
#define CMD_NP_INT 0x65
#define CMD_BT_CTRL 0x46
#define CMD_BT_UNPAIR 0x70
#define CMD_BT_PIN 0x62
#define CMD_DIS_IA 0x69
#define CMD_WIFI_MODE 0x6A
#define CMD_WIFI_SSID 0x6B
#define CMD_WIFI_PSK 0x6C
#define CMD_WIFI_CHN 0x6E
#define CMD_WIFI_IP 0x84
#define CMD_WIFI_NM 0x85
#define CMD_BOARD 0x47
#define CMD_PLATFORM 0x48
#define CMD_MCU 0x49
#define CMD_FW_VERSION 0x50
#define CMD_CFG_READ 0x6D
#define CMD_ROM_READ 0x51
#define CMD_ROM_WRITE 0x52
#define CMD_CONF_SAVE 0x53
@ -91,11 +82,6 @@
#define CMD_RESET 0x55
#define CMD_RESET_BYTE 0xF8
#define CMD_LOG 0x80
#define CMD_TIME 0x81
#define CMD_MUX_CHAIN 0x82
#define CMD_MUX_DSCVR 0x83
#define DETECT_REQ 0x73
#define DETECT_RESP 0x46

View file

@ -31,17 +31,6 @@ const unsigned char bm_rf [] PROGMEM = {
0x31, 0x48, 0x61, 0xca, 0x74, 0x4e, 0x00, 0x00, 0x01, 0x80, 0x04, 0x20, 0x03, 0xc0, 0x00, 0x00
};
const unsigned char bm_wifi [] PROGMEM = {
0x00, 0x00, 0x07, 0xe0, 0x08, 0x10, 0x13, 0xc8, 0x14, 0x28, 0x01, 0x80, 0x00, 0x00, 0x04, 0x60,
0x0a, 0x50, 0x0e, 0x60, 0x0a, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0xe0, 0x08, 0x10, 0x13, 0xc8, 0x14, 0x28, 0x01, 0x80, 0x00, 0x00, 0x04, 0x60,
0x0a, 0x50, 0x0e, 0x60, 0x0a, 0x40, 0x00, 0x00, 0x01, 0x80, 0x04, 0x20, 0x03, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x74,
0x54, 0x40, 0x55, 0x64, 0x29, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0xe0, 0x08, 0x10, 0x13, 0xc8, 0x14, 0x28, 0x01, 0x80, 0x00, 0x00, 0x45, 0x74,
0x54, 0x40, 0x55, 0x64, 0x29, 0x44, 0x00, 0x00, 0x01, 0x80, 0x04, 0x20, 0x03, 0xc0, 0x00, 0x00
};
const unsigned char bm_bt [] PROGMEM = {
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x01, 0x40,
0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x01, 0x00,

View file

@ -1,33 +0,0 @@
This repository is a public mirror. All potential future development is happening elsewhere.
I am stepping back from all public-facing interaction with this project. Reticulum has always been primarily my work, and continuing in the current public, internet-facing model is no longer sustainable.
The software remains available for use as-is. Occasional updates may appear at unpredictable intervals, but there will be no support, no responses to issues, no discussions, and no community management in this or any other public venue. If it doesn't work for you, it doesn't work. That is the entire extent of available troubleshooting assistance I can offer you.
If you've followed this project for a while, you already know what this means. You know who designed, wrote and tested this, and you know how many years of my life it took. You'll also know about both my particular challenges and strengths, and how I believe anything worth building needs to be built and maintained with our own hands.
Seven months ago, I said I needed to step back, that I was exhausted, and that I needed to recover. I believed a public resolve would be enough to effectuate that, but while striving to get just a few more useful features and protocols out, the unproductive requests and demands also ramped up, and I got pulled back into the same patterns and draining interactions that I'd explicitly said I couldn't sustain anymore.
So here's what you might have already guessed: I'm done playing the game by rules I can't win at.
Everything you need is right here, and by any sensible measure, it's done. Anyone who wants to invest the time, skill and persistence can build on it, or completely re-imagine it with different priorities. That was always the point.
The people who actually contributed - you know who you are, and you know I mean it when I say: Thank you. All of you who've used this to build something real - that was the goal, and you did it without needing me to hold your hand.
The rest of you: You have what you need. Use it or don't. I am not going to be the person who explains it to you anymore.
This is not a temporary break. It's not "see you after some rest", but a recognition that the current model is fundamentally incompatible with my life, my health, and my reality.
If you want to support continued work, you can do so at the donation links listed in this repository. But please understand, that this is not purchasing support or guaranteeing updates. It is support for work that happens on my timeline, according to my capacity, which at the moment is not what it was.
If you want Reticulum to continue evolving, you have the power to make that happen. The protocol is public domain. The code is open source. Everything you need is right here. I've provided the tools, but building what comes next is not my responsibility anymore. It's yours.
To the small group of people who has actually been here, and understood what this work was and what it cost - you already know where to find me if it actually matters.
To everyone else: This is where we part ways. No hard feelings. It's just time.
---
असतो मा सद्गमय
तमसो मा ज्योतिर्गमय
मृत्योर्मा अमृतं गमय

View file

@ -16,9 +16,6 @@
# Version 2.0.17 of the Arduino ESP core is based on ESP-IDF v4.4.7
ARDUINO_ESP_CORE_VER = 2.0.17
# Version 3.2.0 of the Arduino ESP core is based on ESP-IDF v5.4.1
# ARDUINO_ESP_CORE_VER = 3.2.0
all: release
clean:
@ -30,6 +27,7 @@ prep: prep-avr prep-esp32 prep-samd
prep-avr:
arduino-cli core update-index --config-file arduino-cli.yaml
arduino-cli core install arduino:avr --config-file arduino-cli.yaml
arduino-cli core install unsignedio:avr --config-file arduino-cli.yaml
prep-esp32:
arduino-cli core update-index --config-file arduino-cli.yaml
@ -65,7 +63,7 @@ spiffs-image:
upload-spiffs:
@echo Deploying SPIFFS image...
python ./Release/esptool/esptool.py --chip esp32s3 --port /dev/ttyACM0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
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
check_bt_buffers:
@./esp32_btbufs.py ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/libraries/BluetoothSerial/src/BluetoothSerial.cpp
@ -124,9 +122,6 @@ firmware-heltec32_v2_extled: check_bt_buffers
firmware-heltec32_v3:
arduino-cli compile --log --fqbn esp32:esp32:heltec_wifi_lora_32_V3 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3A\""
firmware-heltec32_v4:
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3F\""
firmware-rnode_ng_20: check_bt_buffers
arduino-cli compile --log --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x40\""
@ -148,9 +143,6 @@ firmware-heltec_t114:
firmware-techo:
arduino-cli compile --log --fqbn adafruit:nrf52:pca10056 -e --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\""
firmware-xiao_s3:
arduino-cli compile --log --fqbn "esp32:esp32:XIAO_ESP32S3" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3E\""
upload:
arduino-cli upload -p /dev/ttyUSB0 --fqbn unsignedio:avr:rnode
@ -168,8 +160,8 @@ 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.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
#@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 /dev/ttyUSB0 --fqbn esp32:esp32:ttgo-lora32
@ -200,18 +192,11 @@ upload-heltec32_v2:
python ./Release/esptool/esptool.py --chip esp32 --port /dev/ttyUSB1 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
upload-heltec32_v3:
arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:heltec_wifi_lora_32_V3
arduino-cli upload -p /dev/ttyUSB1 --fqbn esp32:esp32:heltec_wifi_lora_32_V3
@sleep 1
rnodeconf /dev/ttyUSB0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware.ino.bin)
rnodeconf /dev/ttyUSB1 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware.ino.bin)
@sleep 3
python ./Release/esptool/esptool.py --chip esp32-s3 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
upload-heltec32_v4:
arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:esp32s3
@sleep 1
rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin)
@sleep 3
python ./Release/esptool/esptool.py --chip esp32-s3 --port /dev/ttyACM0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
python ./Release/esptool/esptool.py --chip esp32-s3 --port /dev/ttyUSB1 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
upload-tdeck:
arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:esp32s3
@ -270,16 +255,9 @@ upload-techo:
@sleep 6
rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes from_device /dev/ttyACM0)
upload-xiao_s3:
arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:XIAO_ESP32S3
@sleep 1
rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.XIAO_ESP32S3/RNode_Firmware.ino.bin)
@sleep 3
python ./Release/esptool/esptool.py --chip esp32s3 --port /dev/ttyACM0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
release: release-all
release-all: console-site spiffs-image release-tbeam release-tbeam_sx1262 release-lora32_v10 release-lora32_v20 release-lora32_v21 release-lora32_v10_extled release-lora32_v20_extled release-lora32_v21_extled release-lora32_v21_tcxo release-featheresp32 release-genericesp32 release-heltec32_v2 release-heltec32_v3 release-heltec32_v4 release-heltec32_v2_extled release-heltec_t114 release-techo release-rnode_ng_20 release-rnode_ng_21 release-t3s3 release-t3s3_sx127x release-t3s3_sx1280_pa release-tdeck release-tbeam_supreme release-rak4631 release-xiao_s3 release-hashes
release-all: console-site spiffs-image release-tbeam release-tbeam_sx1262 release-lora32_v10 release-lora32_v20 release-lora32_v21 release-lora32_v10_extled release-lora32_v20_extled release-lora32_v21_extled release-lora32_v21_tcxo release-featheresp32 release-genericesp32 release-heltec32_v2 release-heltec32_v3 release-heltec32_v2_extled release-heltec_t114 release-techo release-rnode_ng_20 release-rnode_ng_21 release-t3s3 release-t3s3_sx127x release-t3s3_sx1280_pa release-tdeck release-tbeam_supreme release-rak4631 release-hashes
release-hashes:
python ./release_hashes.py > ./Release/release.json
@ -379,7 +357,7 @@ release-heltec32_v2: check_bt_buffers
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-heltec32_v3: check_bt_buffers
release-heltec32_v3:
arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V3 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3A\""
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
@ -388,15 +366,6 @@ release-heltec32_v3: check_bt_buffers
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-heltec32_v4: check_bt_buffers
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=0x3F\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_heltec32v4pa.boot_app0
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin build/rnode_firmware_heltec32v4pa.bin
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_heltec32v4pa.bootloader
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_heltec32v4pa.partitions
zip --junk-paths ./Release/rnode_firmware_heltec32v4pa.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_heltec32v4pa.boot_app0 build/rnode_firmware_heltec32v4pa.bin build/rnode_firmware_heltec32v4pa.bootloader build/rnode_firmware_heltec32v4pa.partitions
rm -r build
release-heltec32_v2_extled: check_bt_buffers
arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V2 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x38\" \"-DEXTERNAL_LEDS=true\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_heltec32v2.boot_app0
@ -506,12 +475,3 @@ release-techo:
arduino-cli compile --log --fqbn adafruit:nrf52:pca10056 -e --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\""
cp build/adafruit.nrf52.pca10056/RNode_Firmware.ino.hex build/rnode_firmware_techo.hex
adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_techo.hex Release/rnode_firmware_techo.zip
release-xiao_s3:
arduino-cli compile --fqbn "esp32:esp32:XIAO_ESP32S3" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3E\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_xiao_esp32s3.boot_app0
cp build/esp32.esp32.XIAO_ESP32S3/RNode_Firmware.ino.bin build/rnode_firmware_xiao_esp32s3.bin
cp build/esp32.esp32.XIAO_ESP32S3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_xiao_esp32s3.bootloader
cp build/esp32.esp32.XIAO_ESP32S3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_xiao_esp32s3.partitions
zip --junk-paths ./Release/rnode_firmware_xiao_esp32s3.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_xiao_esp32s3.boot_app0 build/rnode_firmware_xiao_esp32s3.bin build/rnode_firmware_xiao_esp32s3.bootloader build/rnode_firmware_xiao_esp32s3.partitions
rm -r build

132
Power.h
View file

@ -13,12 +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/>.
#define PMU_TEMP_MIN -30
#define PMU_TEMP_MAX 90
#define PMU_TEMP_OFFSET 120
bool pmu_temp_sensor_ready = false;
float pmu_temperature = PMU_TEMP_MIN-1;
#if BOARD_MODEL == BOARD_TBEAM || BOARD_MODEL == BOARD_TBEAM_S_V1
#include <XPowersLib.h>
XPowersLibInterface* PMU = NULL;
@ -101,38 +95,8 @@ float pmu_temperature = PMU_TEMP_MIN-1;
float bat_delay_v = 0;
float bat_state_change_v = 0;
#elif BOARD_MODEL == BOARD_HELTEC32_V3
// Unless we implement some real voodoo
// on these boards, we can't say with
// any certainty whether we are actually
// charging and have reached a charge
// complete state. The *only* data point
// we have to go from is the bus voltage.
// The BAT_V_CHG and BAT_V_FLOAT values
// are set high here to avoid the display
// indication confusingly flapping
// between charge completed, charging and
// discharging states.
// Update: Vodoo implemented. Hopefully
// it will work accross different boards.
#define BAT_V_MIN 3.05
#define BAT_V_MAX 4.0
#define BAT_V_CHG 4.48
#define BAT_V_FLOAT 4.33
#define BAT_SAMPLES 7
const uint8_t pin_vbat = 1;
const uint8_t pin_ctrl = 37;
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_HELTEC32_V4
#define BAT_V_MIN 3.05
#define BAT_V_MAX 4.0
#define BAT_V_MIN 3.15
#define BAT_V_MAX 4.3
#define BAT_V_CHG 4.48
#define BAT_V_FLOAT 4.33
#define BAT_SAMPLES 7
@ -185,35 +149,17 @@ float pmu_temperature = PMU_TEMP_MIN-1;
uint32_t last_pmu_update = 0;
uint8_t pmu_target_pps = 1;
int pmu_update_interval = 1000/pmu_target_pps;
uint8_t pmu_charged_ascertain = 0;
uint8_t pmu_rc = 0;
uint8_t pmu_sc = 0;
float bat_delay_diff = 0;
bool bat_diff_positive = false;
#define PMU_R_INTERVAL 5
#define PMU_SCV_RESET_INTERVAL 3
void kiss_indicate_battery();
void kiss_indicate_temperature();
void measure_temperature() {
#if PLATFORM == PLATFORM_ESP32
if (pmu_temp_sensor_ready) { pmu_temperature = temperatureRead(); } else { pmu_temperature = PMU_TEMP_MIN-1; }
#endif
}
void measure_battery() {
#if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_HELTEC32_V4 || BOARD_MODEL == BOARD_TDECK || BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_HELTEC_T114 || BOARD_MODEL == BOARD_TECHO
#if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_TDECK || BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_HELTEC_T114 || BOARD_MODEL == BOARD_TECHO
battery_installed = true;
#if BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_HELTEC32_V4
battery_indeterminate = false;
#else
battery_indeterminate = true;
#endif
battery_indeterminate = true;
#if BOARD_MODEL == BOARD_HELTEC32_V3
float battery_measurement = (float)(analogRead(pin_vbat)) * 0.0041;
#elif BOARD_MODEL == BOARD_HELTEC32_V4
float battery_measurement = (float)(analogRead(pin_vbat)) * 0.00418;
#elif BOARD_MODEL == BOARD_T3S3
float battery_measurement = (float)(analogRead(pin_vbat)) / 4095.0*6.7828;
#elif BOARD_MODEL == BOARD_HELTEC_T114
@ -252,23 +198,23 @@ void measure_battery() {
if (battery_percent < 0.0) battery_percent = 0.0;
if (bat_samples_count%BAT_SAMPLES == 0) {
pmu_sc++;
bat_delay_diff = battery_voltage-bat_state_change_v;
float bat_delay_diff = bat_state_change_v-battery_voltage;
if (bat_delay_diff < 0) { bat_delay_diff *= -1; }
if (battery_voltage < bat_delay_v && battery_voltage < BAT_V_FLOAT) {
if (bat_voltage_dropping == false) {
if (bat_delay_diff < -0.008) {
if (bat_delay_diff > 0.008) {
bat_voltage_dropping = true;
bat_state_change_v = battery_voltage;
// SerialBT.printf("STATE CHANGE to DISCHARGE at delta=%.3fv. State change v is now %.3fv.\n", bat_delay_diff, bat_state_change_v);
}
} else {
if (pmu_sc%PMU_SCV_RESET_INTERVAL == 0) { bat_state_change_v = battery_voltage; }
}
} else {
if (bat_voltage_dropping == true) {
if (bat_delay_diff > 0.01) {
bat_voltage_dropping = false;
bat_state_change_v = battery_voltage;
// SerialBT.printf("STATE CHANGE to CHARGE at delta=%.3fv. State change v is now %.3fv.\n", bat_delay_diff, bat_state_change_v);
}
}
}
@ -277,33 +223,22 @@ void measure_battery() {
}
if (bat_voltage_dropping && battery_voltage < BAT_V_FLOAT) {
// if (battery_state != BATTERY_STATE_DISCHARGING) { SerialBT.printf("STATE CHANGE to DISCHARGING at delta=%.3fv. State change v is now %.3fv.\n", bat_delay_diff, bat_state_change_v); }
battery_state = BATTERY_STATE_DISCHARGING;
pmu_charged_ascertain = 0;
} else {
if (pmu_charged_ascertain < 8) { pmu_charged_ascertain++; }
else {
if (battery_percent < 100.0) {
// if (battery_state != BATTERY_STATE_CHARGING) { SerialBT.printf("STATE CHANGE to CHARGING at delta=%.3fv. State change v is now %.3fv.\n", bat_delay_diff, bat_state_change_v); }
battery_state = BATTERY_STATE_CHARGING;
} else {
// if (battery_state != BATTERY_STATE_CHARGED) { SerialBT.printf("STATE CHANGE to CHARGED at delta=%.3fv. State change v is now %.3fv.\n", bat_delay_diff, bat_state_change_v); }
battery_state = BATTERY_STATE_CHARGED;
}
if (battery_percent < 100.0) {
battery_state = BATTERY_STATE_CHARGING;
} else {
battery_state = BATTERY_STATE_CHARGED;
}
}
#if MCU_VARIANT == MCU_NRF52
if (bt_state != BT_STATE_OFF) { blebas.write(battery_percent); }
#endif
// if (bt_state == BT_STATE_CONNECTED) {
// SerialBT.printf("\nBus voltage %.3fv. Unfiltered %.3fv. Diff %.3f", battery_voltage, bat_v_samples[BAT_SAMPLES-1], bat_delay_diff);
// if (bat_voltage_dropping) { SerialBT.printf("\n Voltage is dropping. Percentage %.1f%%.", battery_percent); }
// else { SerialBT.printf("\n Voltage is not dropping. Percentage %.1f%%.", battery_percent); }
// if (battery_state == BATTERY_STATE_DISCHARGING) { SerialBT.printf("\n Battery discharging. delay_v %.3fv\nState change at %.3fv", bat_delay_v, bat_state_change_v); }
// if (battery_state == BATTERY_STATE_CHARGING) { SerialBT.printf("\n Battery charging. delay_v %.3fv\nState change at %.3fv", bat_delay_v, bat_state_change_v); }
// if (battery_state == BATTERY_STATE_CHARGED) { SerialBT.print("\n Battery is charged."); }
// 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 (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."); }
// SerialBT.print("\n");
// }
}
@ -393,7 +328,6 @@ void measure_battery() {
pmu_rc++;
if (pmu_rc%PMU_R_INTERVAL == 0) {
kiss_indicate_battery();
if (pmu_temp_sensor_ready) { kiss_indicate_temperature(); }
}
}
}
@ -401,43 +335,17 @@ void measure_battery() {
void update_pmu() {
if (millis()-last_pmu_update >= pmu_update_interval) {
measure_battery();
measure_temperature();
last_pmu_update = millis();
}
}
bool init_pmu() {
#if IS_ESP32S3
pmu_temp_sensor_ready = true;
#endif
#if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_TDECK || BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_TECHO
pinMode(pin_vbat, INPUT);
return true;
#elif BOARD_MODEL == BOARD_HELTEC32_V3
// there are three version of V3: V3, V3.1, and V3.2
// V3 and V3.1 have a pull up on pin_ctrl and are active low
// V3.2 has a transistor and active high
// put the pin input mode and read it. if it's high, we have V3 or V3.1
// other wise, it's a V3.2
uint16_t pin_ctrl_value;
uint8_t pin_ctrl_active = LOW;
pinMode(pin_ctrl, INPUT);
pin_ctrl_value = digitalRead(pin_ctrl);
if(pin_ctrl_value == HIGH) {
// We have either a V3 or V3.1
pin_ctrl_active = LOW;
}
else {
// We have a V3.2
pin_ctrl_active = HIGH;
}
pinMode(pin_ctrl,OUTPUT);
digitalWrite(pin_ctrl, pin_ctrl_active);
return true;
#elif BOARD_MODEL == BOARD_HELTEC32_V4
pinMode(pin_ctrl,OUTPUT);
digitalWrite(pin_ctrl, HIGH);
digitalWrite(pin_ctrl, LOW);
return true;
#elif BOARD_MODEL == BOARD_HELTEC_T114
pinMode(pin_ctrl,OUTPUT);

View file

@ -1,5 +1,3 @@
*This repository is [a public mirror](./MIRROR.md). All development is happening elsewhere.*
***Important!** This repository is currently functioning as a stable reference for the default RNode Firmware, and only receives bugfix and security updates. Further development, new features and expanded board support is now happening at the [RNode Firmware Community Edition](https://github.com/liberatedsystems/RNode_Firmware_CE) repository, and is maintained by [Liberated Embedded Systems](https://github.com/liberatedsystems). Thanks for all contributions so far!*
# RNode Firmware
@ -18,7 +16,7 @@ The RNode system is primarily software, which *transforms* different kinds of av
## Latest Release
The latest release, installable through `rnodeconf`, is version `1.86`. You must have at least version `2.4.1` of `rnodeconf` installed to update the RNode Firmware to version `1.86`. Get it by updating the `rns` package to at least version `1.1.9`.
The latest release, installable through `rnodeconf`, is version `1.80`. You must have at least version `2.3.0` of `rnodeconf` installed to update the RNode Firmware to version `1.80`. Get it by updating the `rns` package to at least version `0.8.9`.
## A Self-Replicating System
@ -74,20 +72,19 @@ The RNode Firmware supports the following boards:
- LilyGO T3S3 devices with SX1276/8 LoRa chips
- LilyGO T3S3 devices with SX1262/8 LoRa chips
- LilyGO T3S3 devices with SX1280 LoRa chips
- LilyGO T-Echo devices
- Heltec LoRa32 v2 devices
- Heltec LoRa32 v3 devices
- Heltec LoRa32 v4 devices
- Heltec T114 devices
- RAK4631 devices
- SeeedStudio XIAO ESP32S3 devices (with Wio-SX1262)
- Homebrew RNodes based on ATmega1284p boards
- Homebrew RNodes based on ATmega2560 boards
- Homebrew RNodes based on Adafruit Feather ESP32 boards
- Homebrew RNodes based on generic ESP32 boards
## Supported Transceiver Modules
The RNode Firmware supports all transceiver modules based on Semtech **SX1276**, **SX1278**, **SX1262**, **SX1268** and **SX1280** chips, that have an **SPI interface** and expose the relevant **DIO** interrupt pins from the chip.
The RNode Firmware supports all transceiver modules based on **Semtech SX1276** or **Semtech SX1278** chips, that have an **SPI interface** and expose the **DIO_0** interrupt pin from the chip.
Support for **SX1262**, **SX1268** and **SX1280** is being implemented. Please support the project with donations if you want this faster!
## Getting Started Fast
You can download and flash the firmware to all the supported boards using the [RNode Config Utility](https://github.com/markqvist/rnodeconfigutil). All firmware releases are now handled and installed directly through the `rnodeconf` utility, which is included in the `rns` package. It can be installed via `pip`:
@ -123,19 +120,16 @@ You can help support the continued development of open, free and private communi
```
84FpY1QbxHcgdseePYNmhTHcrgMX4nFfBYtz2GKYToqHVVhJp8Eaw1Z1EedRnKD19b3B8NiLCGVxzKV17UMmmeEsCrPyA5w
```
- Bitcoin
```
bc1pgqgu8h8xvj4jtafslq396v7ju7hkgymyrzyqft4llfslz5vp99psqfk3a6
```
- Ethereum
```
0x91C421DdfB8a30a49A71d63447ddb54cEBe3465E
0xFDabC71AC4c0C78C95aDDDe3B4FA19d6273c5E73
```
- Bitcoin
```
35G9uWVzrpJJibzUwpNUQGQNFzLirhrYAH
```
- Liberapay: https://liberapay.com/Reticulum/
- Ko-Fi: https://ko-fi.com/markqvist
## License & Use
The RNode Firmware is Copyright © 2024 Mark Qvist / [unsigned.io](https://unsigned.io), and is made available under the **GNU General Public License v3.0**. The source code includes an SX1276 driver that is released under MIT License, and Copyright © 2018 Sandeep Mistry / Mark Qvist.

View file

@ -42,7 +42,7 @@ volatile bool serial_buffering = false;
#endif
#if PLATFORM == PLATFORM_ESP32 || PLATFORM == PLATFORM_NRF52
#define MODEM_QUEUE_SIZE 8
#define MODEM_QUEUE_SIZE 4
typedef struct {
size_t len;
int rssi;
@ -94,24 +94,14 @@ void setup() {
#endif
// Seed the PRNG for CSMA R-value selection
#if MCU_VARIANT == MCU_ESP32
# if MCU_VARIANT == MCU_ESP32
// On ESP32, get the seed value from the
// hardware RNG
unsigned long seed_val = (unsigned long)esp_random();
#elif MCU_VARIANT == MCU_NRF52
// On nRF, get the seed value from the
// hardware RNG
unsigned long seed_val = get_rng_seed();
int seed_val = (int)esp_random();
#else
// Otherwise, get a pseudo-random seed
// value from an unconnected analog pin
//
// CAUTION! If you are implementing the
// firmware on a platform that does not
// have a hardware RNG, you MUST take
// care to get a seed value with enough
// entropy at each device reset!
unsigned long seed_val = analogRead(0);
int seed_val = analogRead(0);
#endif
randomSeed(seed_val);
@ -125,11 +115,7 @@ void setup() {
led_init();
#endif
#if MCU_VARIANT == MCU_NRF52 && HAS_NP == true
boot_seq();
#endif
#if BOARD_MODEL != BOARD_RAK4631 && BOARD_MODEL != BOARD_HELTEC_T114 && BOARD_MODEL != BOARD_TECHO && BOARD_MODEL != BOARD_T3S3 && BOARD_MODEL != BOARD_TBEAM_S_V1 && BOARD_MODEL != BOARD_HELTEC32_V4
#if BOARD_MODEL != BOARD_RAK4631 && BOARD_MODEL != BOARD_HELTEC_T114 && BOARD_MODEL != BOARD_TECHO && BOARD_MODEL != BOARD_T3S3 && BOARD_MODEL != BOARD_TBEAM_S_V1
// Some boards need to wait until the hardware UART is set up before booting
// the full firmware. In the case of the RAK4631 and Heltec T114, the line below will wait
// until a serial connection is actually established with a master. Thus, it
@ -193,13 +179,6 @@ void setup() {
#endif
#endif
#if BOARD_MODEL == BOARD_XIAO_S3
// Improve wakeup from sleep
delay(300);
LoRa->reset();
delay(100);
#endif
// Check installed transceiver chip and
// probe boot parameters.
if (LoRa->preInit()) {
@ -272,10 +251,6 @@ void setup() {
kiss_indicate_reset();
#endif
} else {
#if HAS_WIFI
wifi_mode = EEPROM.read(eeprom_addr(ADDR_CONF_WIFI));
if (wifi_mode == WR_WIFI_STA || wifi_mode == WR_WIFI_AP) { wifi_remote_init(); }
#endif
kiss_indicate_reset();
}
#endif
@ -314,7 +289,7 @@ inline void kiss_write_packet() {
serial_write(FEND);
serial_write(CMD_DATA);
for (uint16_t i = 0; i < host_write_len; i++) {
for (uint16_t i = 0; i < read_len; i++) {
#if MCU_VARIANT == MCU_NRF52
portENTER_CRITICAL();
uint8_t byte = pbuf[i];
@ -329,7 +304,7 @@ inline void kiss_write_packet() {
}
serial_write(FEND);
host_write_len = 0;
read_len = 0;
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
packet_ready = false;
@ -455,8 +430,7 @@ void ISR_VECT receive_callback(int packet_size) {
kiss_indicate_stat_snr();
// And then write the entire packet
host_write_len = read_len;
kiss_write_packet(); read_len = 0;
kiss_write_packet();
#else
// Allocate packet struct, but abort if there
@ -474,7 +448,7 @@ void ISR_VECT receive_callback(int packet_size) {
// allocated memory again if the queue is
// unable to receive the packet.
modem_packet->len = read_len;
memcpy(modem_packet->data, pbuf, read_len); read_len = 0;
memcpy(modem_packet->data, pbuf, read_len);
if (!modem_packet_queue || xQueueSendFromISR(modem_packet_queue, &modem_packet, NULL) != pdPASS) {
free(modem_packet);
}
@ -575,7 +549,7 @@ volatile bool queue_flushing = false;
void flush_queue(void) {
if (!queue_flushing) {
queue_flushing = true;
led_tx_on();
led_tx_on(); uint16_t processed = 0;
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
while (!fifo16_isempty(&packet_starts)) {
@ -592,7 +566,7 @@ void flush_queue(void) {
tbuf[i] = packet_queue[pos];
}
transmit(length);
transmit(length); processed++;
}
}
@ -615,7 +589,8 @@ void flush_queue(void) {
void pop_queue() {
if (!queue_flushing) {
queue_flushing = true; led_tx_on();
queue_flushing = true;
led_tx_on(); uint16_t processed = 0;
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
if (!fifo16_isempty(&packet_starts)) {
@ -631,9 +606,9 @@ void pop_queue() {
tbuf[i] = packet_queue[pos];
}
transmit(length);
transmit(length); processed++;
}
queue_height -= 1;
queue_height -= processed;
queued_bytes -= length;
}
@ -860,11 +835,7 @@ void serial_callback(uint8_t sbyte) {
} else {
int txp = sbyte;
#if MODEM == SX1262
#if HAS_LORA_PA
if (txp > PA_MAX_OUTPUT) txp = PA_MAX_OUTPUT;
#else
if (txp > 22) txp = 22;
#endif
if (txp > 22) txp = 22;
#elif MODEM == SX1280
#if HAS_PA
if (txp > 20) txp = 20;
@ -1016,8 +987,6 @@ void serial_callback(uint8_t sbyte) {
}
} else if (command == CMD_ROM_READ) {
kiss_dump_eeprom();
} else if (command == CMD_CFG_READ) {
kiss_dump_config();
} else if (command == CMD_ROM_WRITE) {
if (sbyte == FESC) {
ESCAPE = true;
@ -1140,84 +1109,6 @@ void serial_callback(uint8_t sbyte) {
device_save_firmware_hash();
}
#endif
} else if (command == CMD_WIFI_CHN) {
#if HAS_WIFI
if (sbyte > 0 && sbyte < 14) { eeprom_update(eeprom_addr(ADDR_CONF_WCHN), sbyte); }
#endif
} else if (command == CMD_WIFI_MODE) {
#if HAS_WIFI
if (sbyte == WR_WIFI_OFF || sbyte == WR_WIFI_STA || sbyte == WR_WIFI_AP) {
wr_conf_save(sbyte);
wifi_mode = sbyte;
wifi_remote_init();
}
#endif
} else if (command == CMD_WIFI_SSID) {
#if HAS_WIFI
if (sbyte == FESC) { ESCAPE = true; }
else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
if (frame_len < CMD_L) cmdbuf[frame_len++] = sbyte;
}
if (sbyte == 0x00) {
for (uint8_t i = 0; i<33; i++) {
if (i<frame_len && i<32) { eeprom_update(config_addr(ADDR_CONF_SSID+i), cmdbuf[i]); }
else { eeprom_update(config_addr(ADDR_CONF_SSID+i), 0x00); }
}
}
#endif
} else if (command == CMD_WIFI_PSK) {
#if HAS_WIFI
if (sbyte == FESC) { ESCAPE = true; }
else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
if (frame_len < CMD_L) cmdbuf[frame_len++] = sbyte;
}
if (sbyte == 0x00) {
for (uint8_t i = 0; i<33; i++) {
if (i<frame_len && i<32) { eeprom_update(config_addr(ADDR_CONF_PSK+i), cmdbuf[i]); }
else { eeprom_update(config_addr(ADDR_CONF_PSK+i), 0x00); }
}
}
#endif
} else if (command == CMD_WIFI_IP) {
#if HAS_WIFI
if (sbyte == FESC) { ESCAPE = true; }
else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
if (frame_len < CMD_L) cmdbuf[frame_len++] = sbyte;
}
if (frame_len == 4) { for (uint8_t i = 0; i<4; i++) { eeprom_update(config_addr(ADDR_CONF_IP+i), cmdbuf[i]); } }
#endif
} else if (command == CMD_WIFI_NM) {
#if HAS_WIFI
if (sbyte == FESC) { ESCAPE = true; }
else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
if (frame_len < CMD_L) cmdbuf[frame_len++] = sbyte;
}
if (frame_len == 4) { for (uint8_t i = 0; i<4; i++) { eeprom_update(config_addr(ADDR_CONF_NM+i), cmdbuf[i]); } }
#endif
} else if (command == CMD_BT_CTRL) {
#if HAS_BLUETOOTH || HAS_BLE
if (sbyte == 0x00) {
@ -1236,10 +1127,6 @@ void serial_callback(uint8_t sbyte) {
}
}
#endif
} else if (command == CMD_BT_UNPAIR) {
#if HAS_BLE
if (sbyte == 0x01) { bt_debond_all(); }
#endif
} else if (command == CMD_DISP_INT) {
#if HAS_DISPLAY
if (sbyte == FESC) {
@ -1358,26 +1245,15 @@ int noise_floor_buffer[NOISE_FLOOR_SAMPLES] = {0};
void update_noise_floor() {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
if (!dcd) {
#if BOARD_MODEL != BOARD_HELTEC32_V4
if (!noise_floor_sampled || current_rssi < noise_floor + CSMA_INFR_THRESHOLD_DB) {
#else
if ((!noise_floor_sampled || current_rssi < noise_floor + CSMA_INFR_THRESHOLD_DB) || (noise_floor_sampled && (noise_floor < LNA_GD_THRSHLD && current_rssi <= LNA_GD_LIMIT))) {
#endif
#if HAS_LORA_LNA
// Discard invalid samples due to gain variance
// during LoRa LNA re-calibration
if (current_rssi < noise_floor-LORA_LNA_GVT) { return; }
#endif
bool sum_noise_floor = false;
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;
sum_noise_floor = true;
}
if (noise_floor_sampled && sum_noise_floor) {
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;
@ -1389,8 +1265,6 @@ void update_noise_floor() {
#define LED_ID_TRIG 16
uint8_t led_id_filter = 0;
uint32_t interference_start = 0;
bool interference_persists = false;
void update_modem_status() {
#if MCU_VARIANT == MCU_ESP32
portENTER_CRITICAL(&update_lock);
@ -1408,26 +1282,10 @@ void update_modem_status() {
portEXIT_CRITICAL();
#endif
#if BOARD_MODEL == BOARD_HELTEC32_V4
if (noise_floor > LNA_GD_THRSHLD) { interference_detected = !carrier_detected && (current_rssi > (noise_floor+CSMA_INFR_THRESHOLD_DB)); }
else { interference_detected = !carrier_detected && (current_rssi > LNA_GD_LIMIT); }
#else
interference_detected = !carrier_detected && (current_rssi > (noise_floor+CSMA_INFR_THRESHOLD_DB));
#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; } }
// Handle potential false interference detection due to
// LNA recalibration, antenna swap, moving into new RF
// environment or similar.
if (interference_detected && current_rssi < CSMA_RFENV_RECAL_LIMIT_DB) {
if (!interference_persists) { interference_persists = true; interference_start = millis(); }
else {
if (millis()-interference_start >= CSMA_RFENV_RECAL_MS) { noise_floor_sampled = false; interference_persists = false; }
}
} else { interference_persists = false; }
if (carrier_detected) { dcd = true; } else { dcd = false; }
dcd_led = dcd;
@ -1641,8 +1499,7 @@ void tx_queue_handler() {
cw_wait_passed += millis()-cw_wait_start; cw_wait_start = millis();
if (cw_wait_passed < cw_wait_target) { return; } // Contention window wait time has not yet passed, continue waiting
else { // Wait time has passed, flush the queue
bool should_flush = !lora_limit_rate && !lora_guard_rate;
if (should_flush) { flush_queue(); } else { pop_queue(); }
if (!lora_limit_rate) { flush_queue(); } else { pop_queue(); }
cw_wait_passed = 0; csma_cw = -1; difs_wait_start = -1; }
}
}
@ -1658,9 +1515,9 @@ void loop() {
#if MCU_VARIANT == MCU_ESP32
modem_packet_t *modem_packet = NULL;
if(modem_packet_queue && xQueueReceive(modem_packet_queue, &modem_packet, 0) == pdTRUE && modem_packet) {
host_write_len = modem_packet->len;
last_rssi = modem_packet->rssi;
last_snr_raw = modem_packet->snr_raw;
read_len = modem_packet->len;
last_rssi = modem_packet->rssi;
last_snr_raw = modem_packet->snr_raw;
memcpy(&pbuf, modem_packet->data, modem_packet->len);
free(modem_packet);
modem_packet = NULL;
@ -1678,7 +1535,7 @@ void loop() {
modem_packet_t *modem_packet = NULL;
if(modem_packet_queue && xQueueReceive(modem_packet_queue, &modem_packet, 0) == pdTRUE && modem_packet) {
memcpy(&pbuf, modem_packet->data, modem_packet->len);
host_write_len = modem_packet->len;
read_len = modem_packet->len;
free(modem_packet);
modem_packet = NULL;
@ -1735,10 +1592,6 @@ void loop() {
if (!console_active && bt_ready) update_bt();
#endif
#if HAS_WIFI
if (wifi_initialized) update_wifi();
#endif
#if HAS_INPUT
input_read();
#endif
@ -1758,19 +1611,10 @@ void loop() {
void sleep_now() {
#if HAS_SLEEP == true
stopRadio(); // TODO: Check this on all platforms
#if PLATFORM == PLATFORM_ESP32
#if BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_XIAO_S3
#if HAS_DISPLAY
display_intensity = 0;
update_display(true);
#endif
#endif
#if BOARD_MODEL == BOARD_HELTEC32_V4
digitalWrite(LORA_PA_CPS, LOW);
digitalWrite(LORA_PA_CSD, LOW);
digitalWrite(LORA_PA_PWR_EN, LOW);
digitalWrite(Vext, HIGH);
#if BOARD_MODEL == BOARD_T3S3
display_intensity = 0;
update_display(true);
#endif
#if PIN_DISP_SLEEP >= 0
pinMode(PIN_DISP_SLEEP, OUTPUT);
@ -1872,11 +1716,7 @@ void buffer_serial() {
#if HAS_BLUETOOTH || HAS_BLE == true
while (
c < MAX_CYCLES &&
#if HAS_WIFI
( (bt_state != BT_STATE_CONNECTED && Serial.available()) || (bt_state == BT_STATE_CONNECTED && SerialBT.available()) || (wr_state >= WR_STATE_ON && wifi_remote_available()) )
#else
( (bt_state != BT_STATE_CONNECTED && Serial.available()) || (bt_state == BT_STATE_CONNECTED && SerialBT.available()) )
#endif
)
#else
while (c < MAX_CYCLES && Serial.available())
@ -1885,15 +1725,23 @@ void buffer_serial() {
c++;
#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52
if (!fifo_isfull_locked(&serialFIFO)) { fifo_push_locked(&serialFIFO, Serial.read()); }
#elif HAS_BLUETOOTH || HAS_BLE == true || HAS_WIFI
if (bt_state == BT_STATE_CONNECTED) { if (!fifo_isfull(&serialFIFO)) { fifo_push(&serialFIFO, SerialBT.read()); } }
#if HAS_WIFI
else if (wifi_host_is_connected()) { if (!fifo_isfull(&serialFIFO)) { fifo_push(&serialFIFO, wifi_remote_read()); } }
#endif
else { if (!fifo_isfull(&serialFIFO)) { fifo_push(&serialFIFO, Serial.read()); } }
if (!fifo_isfull_locked(&serialFIFO)) {
fifo_push_locked(&serialFIFO, Serial.read());
}
#elif HAS_BLUETOOTH || HAS_BLE == true
if (bt_state == BT_STATE_CONNECTED) {
if (!fifo_isfull(&serialFIFO)) {
fifo_push(&serialFIFO, SerialBT.read());
}
} else {
if (!fifo_isfull(&serialFIFO)) {
fifo_push(&serialFIFO, Serial.read());
}
}
#else
if (!fifo_isfull(&serialFIFO)) { fifo_push(&serialFIFO, Serial.read()); }
if (!fifo_isfull(&serialFIFO)) {
fifo_push(&serialFIFO, Serial.read());
}
#endif
}

8
ROM.h
View file

@ -44,20 +44,12 @@
#define ADDR_CONF_PINT 0xB6
#define ADDR_CONF_BSET 0xB7
#define ADDR_CONF_DIA 0xB9
#define ADDR_CONF_WIFI 0xBA
#define ADDR_CONF_WCHN 0xBB
#define INFO_LOCK_BYTE 0x73
#define CONF_OK_BYTE 0x73
#define BT_ENABLE_BYTE 0x73
#define EEPROM_RESERVED 200
#define CONFIG_SIZE 256
#define ADDR_CONF_SSID 0x00
#define ADDR_CONF_PSK 0x21
#define ADDR_CONF_IP 0x42
#define ADDR_CONF_NM 0x46
//////////////////////////////////
#endif

Binary file not shown.

213
Remote.h
View file

@ -1,213 +0,0 @@
// Copyright (C) 2024, Mark Qvist
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <WiFi.h>
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/rtc.h"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
#define WIFI_UPDATE_INTERVAL_MS 500
#define WR_SOCKET_TIMEOUT 6
#define WR_READ_TIMEOUT_MS 6500
#define WR_RECONNECT_INTERVAL_MS 10000
uint32_t wifi_update_interval_ms = WIFI_UPDATE_INTERVAL_MS;
uint32_t last_wifi_update = 0;
uint32_t wr_last_connect_try = 0;
uint32_t wr_last_read = 0;
WiFiClient connection;
WiFiServer remote_listener(7633, 1);
IPAddress ap_ip(10, 0, 0, 1);
IPAddress ap_nm(255, 255, 255, 0);
IPAddress wr_device_ip;
char wr_hostname[10];
wl_status_t wr_wifi_status = WL_IDLE_STATUS;
uint8_t wifi_mode = WIFI_OFF;
bool wifi_init_ran = false;
bool wifi_initialized = false;
char wr_ssid[33];
char wr_psk[33];
extern void host_disconnected();
void wifi_dbg(String msg) { Serial.print("[WiFi] "); Serial.println(msg); }
uint8_t wifi_remote_mode() { return wifi_mode; }
bool wifi_is_connected() { return (wr_wifi_status == WL_CONNECTED); }
bool wifi_host_is_connected() { if (connection) { return true; } else { return false; } }
void wifi_remote_start_ap() {
WiFi.mode(WIFI_AP);
if (wr_ssid[0] != 0x00) {
if (wr_psk[0] != 0x00) { WiFi.softAP(wr_ssid, wr_psk, wr_channel); }
else { WiFi.softAP(wr_ssid, NULL, wr_channel); }
} else {
if (wr_psk[0] != 0x00) { WiFi.softAP(bt_devname, wr_psk, wr_channel); }
else { WiFi.softAP(bt_devname, NULL, wr_channel); }
}
delay(150);
WiFi.softAPConfig(ap_ip, ap_ip, ap_nm);
wifi_initialized = true;
}
void wifi_remote_start_sta() {
WiFi.mode(WIFI_STA);
uint8_t ip[4]; bool ip_ok = true;
for (uint8_t i = 0; i < 4; i++) { ip[i] = EEPROM.read(config_addr(ADDR_CONF_IP+i)); }
if (ip[0]==0x00 && ip[1]==0x00 && ip[2]==0x00 && ip[3]==0x00) { ip_ok = false; }
if (ip[0]==0xFF && ip[1]==0xFF && ip[2]==0xFF && ip[3]==0xFF) { ip_ok = false; }
uint8_t nm[4]; bool nm_ok = true;
for (uint8_t i = 0; i < 4; i++) { nm[i] = EEPROM.read(config_addr(ADDR_CONF_NM+i)); }
if (nm[0]==0x00 && nm[1]==0x00 && nm[2]==0x00 && nm[3]==0x00) { nm_ok = false; }
if (nm[0]==0xFF && nm[1]==0xFF && nm[2]==0xFF && nm[3]==0xFF) { nm_ok = false; }
if (ip_ok && nm_ok) {
IPAddress sta_ip(ip[0], ip[1], ip[2], ip[3]);
IPAddress sta_nm(nm[0], nm[1], nm[2], nm[3]);
WiFi.config(sta_ip, sta_ip, sta_nm);
}
delay(100);
if (wr_ssid[0] != 0x00) {
if (wr_psk[0] != 0x00) { WiFi.begin(wr_ssid, wr_psk); }
else { WiFi.begin(wr_ssid); }
}
delay(500);
wr_wifi_status = WiFi.status();
wifi_initialized = true;
wr_last_connect_try = millis();
}
void wifi_remote_stop() {
WiFi.softAPdisconnect(true);
WiFi.disconnect(true, true);
WiFi.mode(WIFI_MODE_NULL);
wifi_initialized = false;
}
void wifi_remote_start() {
if (wifi_mode == WR_WIFI_AP) { wifi_remote_start_ap(); }
else if (wifi_mode == WR_WIFI_STA) { wifi_remote_start_sta(); }
else { wifi_remote_stop(); }
if (wifi_initialized == true) {
remote_listener.begin();
remote_listener.setTimeout(WR_SOCKET_TIMEOUT);
wr_state = WR_STATE_ON;
} else { remote_listener.end(); wr_state = WR_STATE_OFF; }
}
void wifi_remote_init() {
memcpy(wr_hostname, bt_devname, 5);
memcpy(wr_hostname+5, bt_devname+6, 4);
wr_hostname[9] = 0x00;
WiFi.softAPdisconnect(true);
WiFi.disconnect(true, true);
WiFi.mode(WIFI_MODE_NULL);
WiFi.setHostname(wr_hostname);
wr_ssid[32] = 0x00; wr_psk[32] = 0x00;
for (uint8_t i = 0; i < 32; i++) { wr_ssid[i] = EEPROM.read(config_addr(ADDR_CONF_SSID+i)); if (wr_ssid[i] == 0xFF) { wr_ssid[i] = 0x00; } }
for (uint8_t i = 0; i < 32; i++) { wr_psk[i] = EEPROM.read(config_addr(ADDR_CONF_PSK+i)); if (wr_psk[i] == 0xFF) { wr_psk[i] = 0x00; } }
wr_channel = EEPROM.read(eeprom_addr(ADDR_CONF_WCHN)); if (wr_channel < 1 || wr_channel > 14) { wr_channel = WR_CHANNEL_DEFAULT; }
wifi_remote_start();
wifi_init_ran = true;
}
void wifi_remote_close_all() {
// wifi_dbg("Close all"); // TODO: Remove debug
if (connection) { connection.stop(); }
WiFiClient client = remote_listener.available();
while (client) { client.stop(); client = remote_listener.available(); }
wr_state = WR_STATE_ON;
}
void wifi_remote_check_active() {
if (millis()-wr_last_read >= WR_READ_TIMEOUT_MS) {
// wifi_dbg("Connection activity timed out"); // TODO: Remove debug
if (connection && connection.connected()) {
connection.stop();
wifi_remote_close_all();
host_disconnected();
}
}
}
bool wifi_remote_available() {
if (connection) {
if (connection.connected()) {
if (connection.available()) { wr_last_read = millis(); return true; }
else { wifi_remote_check_active(); return false; }
} else {
// wifi_dbg("Client disconnected"); // TODO: Remove debug
wifi_remote_close_all();
return false;
}
} else {
WiFiClient client = remote_listener.available();
if (!client) { return false; }
else {
// wifi_dbg("Client connected"); // TODO: Remove debug
connection = client;
wr_state = WR_STATE_CONNECTED;
wr_last_read = millis();
if (connection.available()) { return true; }
else { return false; }
}
}
}
uint8_t wifi_remote_read() {
if (connection && connection.available()) { return connection.read(); }
else {
// wifi_dbg("Error: No data to read from TCP socket"); // TODO: Remove debug
if (connection) { wifi_remote_close_all(); }
return 0xC0;
}
}
void wifi_remote_write(uint8_t byte) { if (connection) { connection.write(byte); } }
void wifi_update_status() {
wr_wifi_status = WiFi.status();
if (wr_wifi_status == WL_CONNECTED) { wr_device_ip = WiFi.localIP(); }
if (wifi_mode == WR_WIFI_AP && wifi_initialized) { wr_device_ip = WiFi.softAPIP(); wr_wifi_status = WL_CONNECTED; }
if (wifi_init_ran && wifi_mode == WR_WIFI_STA && wr_wifi_status != WL_CONNECTED) {
if (millis()-wr_last_connect_try >= WR_RECONNECT_INTERVAL_MS) { wifi_remote_init(); }
}
}
void update_wifi() {
if (millis()-last_wifi_update >= wifi_update_interval_ms) {
wifi_update_status();
last_wifi_update = millis();
}
}

View file

@ -18,7 +18,6 @@
#if HAS_EEPROM
#include <EEPROM.h>
#elif PLATFORM == PLATFORM_NRF52
#include <hal/nrf_rng.h>
#include <Adafruit_LittleFS.h>
#include <InternalFileSystem.h>
using namespace Adafruit_LittleFS_Namespace;
@ -60,10 +59,6 @@ uint8_t eeprom_read(uint32_t mapped_addr);
#include "Bluetooth.h"
#endif
#if HAS_WIFI == true
#include "Remote.h"
#endif
#if HAS_PMU == true
#include "Power.h"
#endif
@ -76,8 +71,8 @@ uint8_t eeprom_read(uint32_t mapped_addr);
#include "Device.h"
#endif
#if MCU_VARIANT == MCU_ESP32
//https://github.com/espressif/esp-idf/issues/8855
#if BOARD_MODEL == BOARD_HELTEC32_V3
//https://github.com/espressif/esp-idf/issues/8855
#include "hal/wdt_hal.h"
#elif BOARD_MODEL == BOARD_T3S3
#include "hal/wdt_hal.h"
@ -108,28 +103,6 @@ uint8_t boot_vector = 0x00;
// TODO: Get NRF52 boot flags
#endif
#if MCU_VARIANT == MCU_NRF52
unsigned long get_rng_seed() {
nrf_rng_error_correction_enable(NRF_RNG);
nrf_rng_shorts_disable(NRF_RNG, NRF_RNG_SHORT_VALRDY_STOP_MASK);
nrf_rng_task_trigger(NRF_RNG, NRF_RNG_TASK_START);
while (!nrf_rng_event_check(NRF_RNG, NRF_RNG_EVENT_VALRDY));
uint8_t rb_a = nrf_rng_random_value_get(NRF_RNG);
nrf_rng_event_clear(NRF_RNG, NRF_RNG_EVENT_VALRDY);
while (!nrf_rng_event_check(NRF_RNG, NRF_RNG_EVENT_VALRDY));
uint8_t rb_b = nrf_rng_random_value_get(NRF_RNG);
nrf_rng_event_clear(NRF_RNG, NRF_RNG_EVENT_VALRDY);
while (!nrf_rng_event_check(NRF_RNG, NRF_RNG_EVENT_VALRDY));
uint8_t rb_c = nrf_rng_random_value_get(NRF_RNG);
nrf_rng_event_clear(NRF_RNG, NRF_RNG_EVENT_VALRDY);
while (!nrf_rng_event_check(NRF_RNG, NRF_RNG_EVENT_VALRDY));
uint8_t rb_d = nrf_rng_random_value_get(NRF_RNG);
nrf_rng_event_clear(NRF_RNG, NRF_RNG_EVENT_VALRDY);
nrf_rng_task_trigger(NRF_RNG, NRF_RNG_TASK_STOP);
return rb_a << 24 | rb_b << 16 | rb_c << 8 | rb_d;
}
#endif
#if HAS_NP == true
#include <Adafruit_NeoPixel.h>
#define NUMPIXELS 1
@ -305,13 +278,6 @@ uint8_t boot_vector = 0x00;
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
void led_id_on() { }
void led_id_off() { }
#elif BOARD_MODEL == BOARD_HELTEC32_V4
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); }
@ -319,13 +285,6 @@ uint8_t boot_vector = 0x00;
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
void led_id_on() { }
void led_id_off() { }
#elif BOARD_MODEL == BOARD_XIAO_S3
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() { }
#elif BOARD_MODEL == BOARD_HUZZAH32
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
@ -383,7 +342,7 @@ void hard_reset(void) {
#elif MCU_VARIANT == MCU_ESP32
ESP.restart();
#elif MCU_VARIANT == MCU_NRF52
NVIC_SystemReset();
NVIC_SystemReset();
#endif
}
@ -801,12 +760,7 @@ int8_t led_standby_direction = 0;
void serial_write(uint8_t byte) {
#if HAS_BLUETOOTH || HAS_BLE == true
if (bt_state != BT_STATE_CONNECTED) {
#if HAS_WIFI
if (wifi_host_is_connected()) { wifi_remote_write(byte); }
else { Serial.write(byte); }
#else
Serial.write(byte);
#endif
Serial.write(byte);
} else {
SerialBT.write(byte);
#if MCU_VARIANT == MCU_NRF52 && HAS_BLE
@ -1023,19 +977,6 @@ void kiss_indicate_battery() {
#endif
}
void kiss_indicate_temperature() {
#if HAS_PMU
#if MCU_VARIANT == MCU_ESP32
float pmu_temp = pmu_temperature+PMU_TEMP_OFFSET;
uint8_t temp = (uint8_t)pmu_temp;
serial_write(FEND);
serial_write(CMD_STAT_TEMP);
escaped_serial_write(pmu_temp);
serial_write(FEND);
#endif
#endif
}
void kiss_indicate_btpin() {
#if HAS_BLUETOOTH || HAS_BLE == true
serial_write(FEND);
@ -1239,7 +1180,6 @@ void updateBitrate() {
bool fast_rate = lora_bitrate > LORA_FAST_THRESHOLD_BPS;
lora_limit_rate = lora_bitrate > LORA_LIMIT_THRESHOLD_BPS;
lora_guard_rate = (!lora_limit_rate && lora_bitrate > LORA_GUARD_THRESHOLD_BPS);
int csma_slot_min_ms = CSMA_SLOT_MIN_MS;
float lora_preamble_target_ms = LORA_PREAMBLE_TARGET_MS;
@ -1286,125 +1226,51 @@ int getTxPower() {
return (int)txp;
}
#if HAS_LORA_PA
#if BOARD_MODEL == BOARD_HELTEC32_V4
bool pa_values_determined = false;
int tx_gain[PA_GAIN_POINTS] = {100};
#else
bool pa_values_determined = true;
const int tx_gain[PA_GAIN_POINTS] = {PA_GAIN_VALUES};
#endif
#endif
extern uint8_t lora_pa_model;
void determine_pa_values() {
#if BOARD_MODEL == BOARD_HELTEC32_V4
if (lora_pa_model == LORA_PA_GC1109) {
for (int i=0; i < PA_GAIN_POINTS; i++) { tx_gain[i] = PA_GC1109_VALUES[i]; }
pa_values_determined = true;
for (int i=0; i < PA_GAIN_POINTS; i++) { Serial.print(" "); Serial.printf("%d", tx_gain[i]); }
} else if (lora_pa_model == LORA_PA_KCT8103L) {
for (int i=0; i < PA_GAIN_POINTS; i++) { tx_gain[i] = PA_KCT8103L_VALUES[i]; }
pa_values_determined = true;
for (int i=0; i < PA_GAIN_POINTS; i++) { Serial.print(" "); Serial.printf("%d", tx_gain[i]); }
}
#endif
}
int map_target_power_to_modem_output(int target_tx_power) {
#if HAS_LORA_PA
if (!pa_values_determined) { determine_pa_values(); }
int modem_output_dbm = -9;
for (int i = 0; i < PA_GAIN_POINTS; i++) {
int gain = tx_gain[i];
int effective_output_dbm = i + gain;
if (effective_output_dbm > target_tx_power) {
int diff = effective_output_dbm - target_tx_power;
modem_output_dbm = -1*diff;
break;
} else if (effective_output_dbm == target_tx_power) {
modem_output_dbm = i; break;
} else if (i == PA_GAIN_POINTS-1) {
int diff = target_tx_power - effective_output_dbm;
modem_output_dbm = i+diff; break;
}
}
#else
int modem_output_dbm = target_tx_power;
#endif
return modem_output_dbm;
}
int map_modem_output_to_target_power(int modem_output_dbm) {
#if HAS_LORA_PA
if (modem_output_dbm < 0) { modem_output_dbm = 0; }
if (modem_output_dbm >= PA_GAIN_POINTS) { modem_output_dbm = PA_GAIN_POINTS-1; }
int gain = tx_gain[modem_output_dbm];
int target_tx_power = modem_output_dbm+gain;
#else
int target_tx_power = modem_output_dbm;
#endif
return target_tx_power;
}
void setTXPower() {
if (radio_online) {
int mapped_lora_txp = map_target_power_to_modem_output(lora_txp);
#if HAS_LORA_PA
int real_lora_txp = map_modem_output_to_target_power(mapped_lora_txp);
lora_txp = real_lora_txp;
#endif
if (model == MODEL_11) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_12) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_11) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_12) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_C6) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_C7) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_C6) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_C7) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_A1) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A2) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A3) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_A4) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_A5) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A6) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A7) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A8) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_AA) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_AC) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A1) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A2) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A3) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_A4) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_A5) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A6) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A7) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A8) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A9) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_AA) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_AC) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_BA) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_BB) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B3) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B8) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_BA) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_BB) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B3) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B4) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B8) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B9) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C5) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_CA) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C4) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C9) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C5) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_CA) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C8) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_D4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_D9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_D4) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_D9) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_DB) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_DC) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_DB) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_DC) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E3) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E8) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_DD) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_DE) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E4) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E9) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E3) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E8) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_FE) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_FF) LoRa->setTxPower(mapped_lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_FE) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_FF) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
}
}
@ -1521,15 +1387,6 @@ void eeprom_dump_all() {
}
}
void eeprom_config_dump_all() {
#if MCU_VARIANT == MCU_ESP32
for (int addr = 0; addr < CONFIG_SIZE; addr++) {
uint8_t byte = EEPROM.read(config_addr(addr));
escaped_serial_write(byte);
}
#endif
}
void kiss_dump_eeprom() {
serial_write(FEND);
serial_write(CMD_ROM_READ);
@ -1537,13 +1394,6 @@ void kiss_dump_eeprom() {
serial_write(FEND);
}
void kiss_dump_config() {
serial_write(FEND);
serial_write(CMD_CFG_READ);
eeprom_config_dump_all();
serial_write(FEND);
}
#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
void eeprom_flush() {
file.close();
@ -1617,7 +1467,7 @@ bool eeprom_product_valid() {
#if PLATFORM == PLATFORM_AVR
if (rval == PRODUCT_RNODE || rval == PRODUCT_HMBRW) {
#elif 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_H32_V4 || rval == PRODUCT_TDECK_V1 || rval == PRODUCT_TBEAM_S_V1 || rval == PRODUCT_XIAO_S3) {
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) {
#elif PLATFORM == PLATFORM_NRF52
if (rval == PRODUCT_RAK4631 || rval == PRODUCT_HELTEC_T114 || rval == PRODUCT_TECHO || rval == PRODUCT_HMBRW) {
#else
@ -1653,8 +1503,6 @@ bool eeprom_model_valid() {
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_XIAO_S3
if (model == MODEL_DD || model == MODEL_DE) {
#elif BOARD_MODEL == BOARD_LORA32_V1_0
if (model == MODEL_BA || model == MODEL_BB) {
#elif BOARD_MODEL == BOARD_LORA32_V2_0
@ -1665,12 +1513,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_HELTEC32_V4
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) {
#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) {
#elif BOARD_MODEL == BOARD_HUZZAH32
if (model == MODEL_FF) {
#elif BOARD_MODEL == BOARD_GENERIC_ESP32
@ -1727,14 +1573,6 @@ bool eeprom_checksum_valid() {
return checksum_valid;
}
void wr_conf_save(uint8_t mode) {
eeprom_update(eeprom_addr(ADDR_CONF_WIFI), mode);
#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
// have to do a flush because we're only writing 1 byte and it syncs after 8
eeprom_flush();
#endif
}
void bt_conf_save(bool is_enabled) {
if (is_enabled) {
eeprom_update(eeprom_addr(ADDR_CONF_BT), BT_ENABLE_BYTE);
@ -2032,13 +1870,3 @@ inline void fifo16_init(FIFOBuffer16 *f, uint16_t *buffer, uint16_t size) {
inline uint16_t fifo16_len(FIFOBuffer16 *f) {
return (f->end - f->begin);
}
extern void stopRadio();
void host_disconnected() {
stopRadio();
cable_state = CABLE_STATE_DISCONNECTED;
current_rssi = -292;
last_rssi = -292;
last_rssi_raw = 0x00;
last_snr_raw = 0x80;
}

View file

@ -4,3 +4,4 @@ board_manager:
- https://raw.githubusercontent.com/RAKwireless/RAKwireless-Arduino-BSP-Index/main/package_rakwireless_index.json
- https://github.com/HelTecAutomation/Heltec_nRF52/releases/download/1.7.0/package_heltec_nrf_index.json
- https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
- http://unsigned.io/arduino/package_unsignedio_UnsignedBoards_index.json

View file

@ -1,6 +1,5 @@
#!/usr/bin/env python3
import sys
import re
try:
target_path = sys.argv[1]
@ -13,7 +12,7 @@ try:
for line in sf:
line_index += 1
if line.startswith("#define RX_QUEUE_SIZE"):
ents = re.sub(" +", " ", line).split(" ")
ents = line.split(" ")
try:
rxbuf_size = int(ents[2])
rx_line_index = line_index
@ -21,12 +20,12 @@ try:
print(f"Could not parse Bluetooth RX_QUEUE_SIZE: {e}")
if line.startswith("#define TX_QUEUE_SIZE"):
ents = re.sub(" +", " ", line).split(" ")
ents = line.split(" ")
try:
txbuf_size = int(ents[2])
tx_line_index = line_index
except Exception as e:
print(f"Could not parse Bluetooth TX_QUEUE_SIZE: {e}")
print(f"Could not parse Bluetooth RX_QUEUE_SIZE: {e}")
if rxbuf_size != 0 and txbuf_size != 0:
break

View file

@ -96,14 +96,6 @@
#define SPI spiModem
#endif
#if HAS_LORA_PA
uint8_t lora_pa_model = LORA_PA_MODEL;
#endif
#if HAS_LORA_LNA
int lora_lna_gain = LORA_LNA_GAIN;
#endif
extern SPIClass SPI;
#define MAX_PKT_LENGTH 255
@ -133,7 +125,7 @@ bool sx126x::preInit() {
pinMode(_ss, OUTPUT);
digitalWrite(_ss, HIGH);
#if BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_HELTEC32_V4 || BOARD_MODEL == BOARD_TDECK || BOARD_MODEL == BOARD_XIAO_S3
#if BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_TDECK
SPI.begin(pin_sclk, pin_miso, pin_mosi, pin_cs);
#elif BOARD_MODEL == BOARD_TECHO
SPI.setPins(pin_miso, pin_sclk, pin_mosi);
@ -278,24 +270,9 @@ void sx126x::setPacketParams(long preamble_symbols, uint8_t headermode, uint8_t
buf[4] = crc;
buf[5] = 0x00; // standard IQ setting (no inversion)
buf[6] = 0x00; // unused params
buf[7] = 0x00;
buf[8] = 0x00;
buf[7] = 0x00;
buf[8] = 0x00;
executeOpcode(OP_PACKET_PARAMS_6X, buf, 9);
// SX1262 errata section 15.4: IQ polarity is inverted compared to
// SX1276. The SetPacketParams command resets register 0x0736 to an
// incorrect default. For standard IQ (no inversion), bit 2 must be
// SET after every SetPacketParams call. For inverted IQ, bit 2 must
// be CLEARED. Without this fix, LoRa RX demodulation fails silently
// while TX continues to work.
uint8_t iqreg = readRegister(0x0736);
if (buf[5] == 0x00) {
// Standard IQ: set bit 2
writeRegister(0x0736, iqreg | 0x04);
} else {
// Inverted IQ: clear bit 2
writeRegister(0x0736, iqreg & ~0x04);
}
}
void sx126x::reset(void) {
@ -365,87 +342,12 @@ int sx126x::begin(long frequency) {
setModulationParams(_sf, _bw, _cr, _ldro);
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
#if HAS_LORA_PA
if (lora_pa_model == LORA_PA_UNKNOWN) {
#if BOARD_MODEL == BOARD_HELTEC32_V4
pinMode(LORA_PA_PWR_EN, OUTPUT);
pinMode(LORA_PA_CSD, INPUT);
digitalWrite(LORA_PA_PWR_EN, HIGH); delay(5);
if (digitalRead(LORA_PA_CSD) == HIGH) {
lora_pa_model = LORA_PA_KCT8103L;
lora_lna_gain = LORA_LNA_KCT8103L_GAIN;
} else {
lora_pa_model = LORA_PA_GC1109;
}
#endif
}
if (lora_pa_model == LORA_PA_GC1109) {
// Enable Vfem_ctl for supply to
// PA power net.
pinMode(LORA_PA_PWR_EN, OUTPUT);
digitalWrite(LORA_PA_PWR_EN, HIGH);
// Enable PA LNA and TX standby
pinMode(LORA_PA_CSD, OUTPUT);
digitalWrite(LORA_PA_CSD, HIGH);
// Keep PA CPS low until actual
// transmit. Does it save power?
// Who knows? Will have to measure.
// Note from the future: Nope.
// Power consumption is the same,
// and turning it on and off is
// not something that it likes.
// Keeping it high for now.
pinMode(LORA_PA_CPS, OUTPUT);
digitalWrite(LORA_PA_CPS, HIGH);
// On Heltec V4, the PA CTX pin
// is driven by the SX1262 DIO2
// pin directly, so we do not
// need to manually raise this.
} else if (lora_pa_model == LORA_PA_KCT8103L) {
// Enable Vfem_ctl for supply to
// PA power net.
pinMode(LORA_PA_PWR_EN, OUTPUT);
digitalWrite(LORA_PA_PWR_EN, HIGH);
// Enable KCT8103L chip
pinMode(LORA_PA_CSD, OUTPUT);
digitalWrite(LORA_PA_CSD, HIGH);
// Enable receive LNA
pinMode(LORA_PA_CTX, OUTPUT);
digitalWrite(LORA_PA_CTX, LOW);
// On Heltec V4.3, the PA CPS pin
// is driven by the SX1262 DIO2
// pin directly, so we do not
// need to manually raise this.
}
#endif
return 1;
}
void sx126x::end() { sleep(); SPI.end(); _preinit_done = false; }
int sx126x::beginPacket(int implicitHeader) {
#if HAS_LORA_PA
if (lora_pa_model == LORA_PA_GC1109) {
// Enable PA CPS for transmit
// digitalWrite(LORA_PA_CPS, HIGH);
// Disabled since we're keeping it
// on permanently as long as the
// radio is powered up.
} else if (lora_pa_model == LORA_PA_KCT8103L) {
digitalWrite(LORA_PA_CTX, HIGH);
}
#endif
standby();
if (implicitHeader) { implicitHeaderMode(); }
else { explicitHeaderMode(); }
@ -530,9 +432,6 @@ int ISR_VECT sx126x::currentRssi() {
uint8_t byte = 0;
executeOpcodeRead(OP_CURRENT_RSSI_6X, &byte, 1);
int rssi = -(int(byte)) / 2;
#if HAS_LORA_LNA
rssi -= lora_lna_gain;
#endif
return rssi;
}
@ -543,12 +442,10 @@ uint8_t sx126x::packetRssiRaw() {
}
int ISR_VECT sx126x::packetRssi() {
// TODO: May need more calculations here
uint8_t buf[3] = {0};
executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3);
int pkt_rssi = -buf[0] / 2;
#if HAS_LORA_LNA
pkt_rssi -= lora_lna_gain;
#endif
return pkt_rssi;
}
@ -653,20 +550,6 @@ void sx126x::onReceive(void(*callback)(int)){
}
void sx126x::receive(int size) {
#if HAS_LORA_PA
if (lora_pa_model == LORA_PA_GC1109) {
// Disable PA CPS for receive
// digitalWrite(LORA_PA_CPS, LOW);
// That turned out to be a bad idea.
// The LNA goes wonky if it's toggled
// on and off too quickly. We'll keep
// it on permanently, as long as the
// radio is powered up.
} else if (lora_pa_model == LORA_PA_KCT8103L) {
digitalWrite(LORA_PA_CTX, LOW);
}
#endif
if (size > 0) {
implicitHeaderMode();
_payloadLength = size;
@ -687,7 +570,7 @@ void sx126x::sleep() { uint8_t byte = 0x00; executeOpcode(OP_SLEEP_6X, &byte, 1)
void sx126x::enableTCXO() {
#if HAS_TCXO
#if BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_XIAO_S3
#if BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_HELTEC32_V3
uint8_t buf[4] = {MODE_TCXO_3_3V_6X, 0x00, 0x00, 0xFF};
#elif BOARD_MODEL == BOARD_TBEAM
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
@ -701,8 +584,6 @@ void sx126x::enableTCXO() {
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
#elif BOARD_MODEL == BOARD_TECHO
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
#elif BOARD_MODEL == BOARD_HELTEC32_V4
uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};
#endif
executeOpcode(OP_DIO3_TCXO_CTRL_6X, buf, 4);
#endif
@ -790,17 +671,7 @@ void sx126x::handleLowDataRate() {
}
// TODO: Check if there's anything the sx1262 can do here
// SX1262 errata section 15.1: Modulation quality with 500 kHz LoRa BW.
// Register 0x0889 bit 2 must be cleared for 500 kHz, set for all other
// bandwidths. Improves receiver sensitivity at non-500 kHz bandwidths.
void sx126x::optimizeModemSensitivity(){
uint8_t reg = readRegister(0x0889);
if (getSignalBandwidth() == 500E3) {
writeRegister(0x0889, reg & 0xFB); // clear bit 2
} else {
writeRegister(0x0889, reg | 0x04); // set bit 2
}
}
void sx126x::optimizeModemSensitivity(){ }
void sx126x::setSignalBandwidth(long sbw) {
if (sbw <= 7.8E3) { _bw = 0x00; }

View file

@ -56,7 +56,6 @@ public:
void receive(int size = 0);
void standby();
void sleep();
void reset(void);
bool preInit();
uint8_t getTxPower();
@ -112,6 +111,7 @@ private:
void handleLowDataRate();
void optimizeModemSensitivity();
void reset(void);
void calibrate(void);
void calibrate_image(long frequency);

View file

@ -134,7 +134,7 @@ bool sx128x::preInit() {
// TODO: Check if this change causes issues on any platforms
#if MCU_VARIANT == MCU_ESP32
#if BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_HELTEC32_V4 || BOARD_MODEL == BOARD_TDECK
#if BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_TDECK
SPI.begin(pin_sclk, pin_miso, pin_mosi, pin_cs);
#else
SPI.begin();