Fix BLE pairing display and RX gain defaults
This commit is contained in:
1 parent
968ca3363b
commit
2ff1166c15
22 files changed
+297
-39
No files matched your search
@@ -554,9 +554,14 @@ disabled.
|
||||
**Parameters:**
|
||||
- `state`: `on`|`off`
|
||||
|
||||
**Default:** `on`
|
||||
**Default:** Target-specific. Most SX1262 and LR1110 targets default to `on`;
|
||||
Station G2/G3 targets default to `off`.
|
||||
|
||||
**Temporary Note:** If you upgraded from an older version to 1.14.1 without erasing flash, this setting is `off` because of [#2118](https://github.com/meshcore-dev/MeshCore/issues/2118)
|
||||
**Notes:**
|
||||
- The saved setting is applied immediately and persists across reboots.
|
||||
- Periodic AGC resets restore the saved runtime setting; they do not replace it
|
||||
with the target's compile-time default.
|
||||
- Existing installations retain their previously saved value after an upgrade.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -676,7 +676,7 @@ Bytes 2+: Variable length based on firmware version
|
||||
For firmware version >= 3:
|
||||
Byte 2: Max Contacts Raw (uint8, actual = value * 2)
|
||||
Byte 3: Max Channels (uint8)
|
||||
Bytes 4-7: BLE PIN (32-bit little-endian)
|
||||
Bytes 4-7: Active BLE PIN (32-bit little-endian; includes a generated session PIN)
|
||||
Bytes 8-19: Firmware Build (12 bytes, UTF-8, null-padded)
|
||||
Bytes 20-59: Model (40 bytes, UTF-8, null-padded)
|
||||
Bytes 60-79: Version (20 bytes, UTF-8, null-padded)
|
||||
|
||||
@@ -80,7 +80,7 @@ are requested.
|
||||
| Platform | Interface | Purpose |
|
||||
| --- | --- | --- |
|
||||
| Both | USB, 115200 baud | Binary Companion by default; terminal switch available |
|
||||
| Both | BLE | Binary Companion; default pairing PIN `123456` |
|
||||
| Both | BLE | Binary Companion; display builds show a random session PIN, while headless builds default to `123456` |
|
||||
| ESP32 | TCP 5000 | Binary Companion over WiFi |
|
||||
| ESP32 | HTTP 80 | Companion WebConfig and first-boot WiFi setup |
|
||||
| ESP32 | TCP 5001 | Host `.mota` folder from `motatool serve --tcp` |
|
||||
@@ -91,6 +91,14 @@ Binary Companion replies are broadcast through the multi-interface manager,
|
||||
so use one active Companion application at a time. On nRF52, BLE remains
|
||||
available while USB is in terminal or mOTA mode.
|
||||
|
||||
When a BLE client requests pairing, a display-equipped build wakes the screen,
|
||||
switches to the first home page, and keeps the active six-digit PIN visible
|
||||
until Bluetooth connects or the two-minute pairing window expires. USB, WiFi,
|
||||
Ethernet, and hardware-serial connections do not suppress this screen. With no
|
||||
saved BLE PIN, display builds generate a new PIN at boot; builds without a
|
||||
physical display use `123456`. A PIN saved through the Companion protocol takes
|
||||
effect after reboot.
|
||||
|
||||
ESP32 ports 5000, 5001, 5002, and WebConfig have no independent login layer.
|
||||
Expose them only on a trusted LAN or temporary setup network. See
|
||||
[WiFi setup](./WiFi.md) for credential setup and reconnect behavior.
|
||||
|
||||
+4
-1
@@ -686,7 +686,10 @@ You can get the epoch time on <https://www.epochconverter.com> and use it to set
|
||||
**A:** Make sure that you flashed the Bluetooth companion firmware and not the USB-only companion firmware.
|
||||
|
||||
### 6.5. Q: I can't connect via Bluetooth, what is the Bluetooth pairing code?
|
||||
**A:** The default Bluetooth pairing code is `123456`
|
||||
**A:** The default Bluetooth pairing code is `123456` on builds without a
|
||||
physical display. Display-equipped Companion builds generate a six-digit PIN
|
||||
at boot and show it when a client requests pairing. The display stays awake on
|
||||
the PIN page until Bluetooth connects or the two-minute pairing window expires.
|
||||
|
||||
### 6.6. Q: My Heltec V3 keeps disconnecting from my smartphone. It can't hold a solid Bluetooth connection.
|
||||
**A:** Heltec V3 has a very small coil antenna on its PCB for Wi-Fi and Bluetooth connectivity. It has a very short range, only a few feet. It is possible to remove the coil antenna and replace it with a 31mm wire. The BT range is much improved with the modification.
|
||||
|
||||
@@ -53,6 +53,7 @@ protected:
|
||||
public:
|
||||
void setHasConnection(bool connected) { _connected = connected; }
|
||||
bool hasConnection() const { return _connected; }
|
||||
bool hasBluetoothConnection() const { return _interfaceManager->isBluetoothConnected(); }
|
||||
uint16_t getBattMilliVolts() const { return _board->getBattMilliVolts(); }
|
||||
bool isBluetoothEnabled() const { return _interfaceManager->isBluetoothEnabled(); }
|
||||
void enableBluetooth() { _interfaceManager->enableBluetooth(); }
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <Arduino.h> // needed for PlatformIO
|
||||
#include <Mesh.h>
|
||||
#include "helpers/radiolib/RXPowerSaving.h"
|
||||
#include "helpers/radiolib/RxBoostedGainDefaults.h"
|
||||
|
||||
#ifdef ENABLE_USB_INTERFACE
|
||||
#include <helpers/CLICommandUtils.h>
|
||||
@@ -1336,12 +1337,10 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
|
||||
_prefs.path_hash_mode = DEFAULT_PATH_HASH_MODE;
|
||||
//_prefs.rx_delay_base = 10.0f; enable once new algo fixed
|
||||
_prefs.setRepeatEn(false);
|
||||
#if defined(USE_SX1262) || defined(USE_SX1268)
|
||||
#ifdef SX126X_RX_BOOSTED_GAIN
|
||||
_prefs.rx_boosted_gain = SX126X_RX_BOOSTED_GAIN;
|
||||
#else
|
||||
_prefs.rx_boosted_gain = 1; // enabled by default
|
||||
#endif
|
||||
#if defined(USE_SX1262) || defined(USE_SX1268) || defined(USE_LR1110) \
|
||||
|| defined(USE_LR2021) || defined(SX126X_RX_BOOSTED_GAIN) \
|
||||
|| defined(RX_BOOSTED_GAIN)
|
||||
_prefs.rx_boosted_gain = mesh::radio::configuredRxBoostedGainDefault();
|
||||
#endif
|
||||
_prefs.radio_fem_rxgain = DEFAULT_FEM_RX_GAIN;
|
||||
|
||||
@@ -2257,7 +2256,7 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
out_frame[i++] = FIRMWARE_VER_CODE;
|
||||
out_frame[i++] = MAX_CONTACTS / 2; // v3+
|
||||
out_frame[i++] = MAX_GROUP_CHANNELS; // v3+
|
||||
memcpy(&out_frame[i], &_prefs.ble_pin, 4);
|
||||
memcpy(&out_frame[i], &_active_ble_pin, 4);
|
||||
i += 4;
|
||||
memset(&out_frame[i], 0, 12);
|
||||
strcpy((char *)&out_frame[i], FIRMWARE_BUILD_DATE);
|
||||
|
||||
@@ -239,7 +239,7 @@ public:
|
||||
display.setTextSize(1);
|
||||
display.drawTextCentered(display.width() / 2, 54, tmp);
|
||||
#endif
|
||||
if (_task->hasConnection()) {
|
||||
if (_task->hasBluetoothConnection()) {
|
||||
display.setColor(UIColor::warning_txt);
|
||||
display.setTextSize(1);
|
||||
display.drawTextCentered(display.width() / 2, 43, "< Connected >");
|
||||
@@ -725,7 +725,7 @@ void UITask::setCurrScreen(UIScreen* c) {
|
||||
|
||||
bool UITask::isPairingScreenActive() const {
|
||||
return _pairing_screen_until != 0
|
||||
&& !hasConnection()
|
||||
&& !hasBluetoothConnection()
|
||||
&& static_cast<int32_t>(millis() - _pairing_screen_until) < 0;
|
||||
}
|
||||
|
||||
@@ -805,7 +805,7 @@ void UITask::loop() {
|
||||
|
||||
if (_pairing_screen_until != 0) {
|
||||
const bool timed_out = static_cast<int32_t>(millis() - _pairing_screen_until) >= 0;
|
||||
if (hasConnection() || timed_out) {
|
||||
if (hasBluetoothConnection() || timed_out) {
|
||||
finishPairingScreen(timed_out);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
|
||||
#define AUTO_OFF_MILLIS 15000 // 15 seconds
|
||||
#define BOOT_SCREEN_MILLIS 3000 // 3 seconds
|
||||
#ifndef BLE_PAIRING_DISPLAY_MILLIS
|
||||
#define BLE_PAIRING_DISPLAY_MILLIS 120000UL
|
||||
#endif
|
||||
|
||||
#if defined(PIN_STATUS_LED) || defined(PIN_STATUS_LED_R)
|
||||
#define LED_ON_MILLIS 20
|
||||
@@ -104,7 +107,7 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
|
||||
|
||||
bool UITask::shouldPlayMessageTone() const {
|
||||
#ifdef BLE_PIN_CODE
|
||||
return !hasConnection();
|
||||
return !hasBluetoothConnection();
|
||||
#else
|
||||
// A USB or Ethernet companion connection is not a Bluetooth connection and
|
||||
// should not silence the standalone new-message alert.
|
||||
@@ -214,7 +217,8 @@ void UITask::renderCurrScreen() {
|
||||
if (_display == NULL) return; // assert() ??
|
||||
|
||||
char tmp[80];
|
||||
if (_alert[0]) {
|
||||
const bool pairing_screen_active = isPairingScreenActive();
|
||||
if (!pairing_screen_active && _alert[0]) {
|
||||
_display->setTextSize(1.4);
|
||||
uint16_t textWidth = _display->getTextWidth(_alert);
|
||||
_display->setCursor((_display->width() - textWidth) / 2, 22);
|
||||
@@ -223,7 +227,7 @@ void UITask::renderCurrScreen() {
|
||||
_alert[0] = 0;
|
||||
_need_refresh = true;
|
||||
return;
|
||||
} else if (_origin[0] && _msg[0]) { // message preview
|
||||
} else if (!pairing_screen_active && _origin[0] && _msg[0]) { // message preview
|
||||
// render message preview
|
||||
_display->setCursor(0, 0);
|
||||
_display->setTextSize(1);
|
||||
@@ -242,7 +246,7 @@ void UITask::renderCurrScreen() {
|
||||
sprintf(tmp, "%d", _msgcount);
|
||||
_display->print(tmp);
|
||||
_display->setColor(UIColor::secondary_txt); // last color will be kept on T114
|
||||
} else if ((millis() - ui_started_at) < BOOT_SCREEN_MILLIS) { // boot screen
|
||||
} else if (!pairing_screen_active && (millis() - ui_started_at) < BOOT_SCREEN_MILLIS) { // boot screen
|
||||
// meshcore logo
|
||||
_display->setColor(UIColor::corp_blue);
|
||||
int logoWidth = 128;
|
||||
@@ -276,7 +280,7 @@ void UITask::renderCurrScreen() {
|
||||
_display->print(tmp);
|
||||
|
||||
// BT pin
|
||||
if (!_connected && the_mesh.getBLEPin() != 0) {
|
||||
if (!hasBluetoothConnection() && the_mesh.getBLEPin() != 0) {
|
||||
_display->setColor(UIColor::warning_txt);
|
||||
_display->setTextSize(2);
|
||||
_display->setCursor(0, 43);
|
||||
@@ -447,7 +451,47 @@ void UITask::shutdown(bool restart){
|
||||
}
|
||||
}
|
||||
|
||||
bool UITask::isPairingScreenActive() const {
|
||||
return _pairing_screen_until != 0
|
||||
&& !hasBluetoothConnection()
|
||||
&& static_cast<int32_t>(millis() - _pairing_screen_until) < 0;
|
||||
}
|
||||
|
||||
void UITask::showPairingPin() {
|
||||
const unsigned long now = millis();
|
||||
_pairing_screen_until = now + BLE_PAIRING_DISPLAY_MILLIS;
|
||||
_need_refresh = true;
|
||||
_next_refresh = 0;
|
||||
if (_display != NULL && !_display->isOn()) {
|
||||
_display->turnOn();
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::finishPairingScreen(bool timed_out) {
|
||||
_pairing_screen_until = 0;
|
||||
_need_refresh = true;
|
||||
_next_refresh = 0;
|
||||
if (_display == NULL) return;
|
||||
|
||||
if (timed_out) {
|
||||
_display->turnOff();
|
||||
} else {
|
||||
_auto_off = millis() + AUTO_OFF_MILLIS;
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::loop() {
|
||||
if (_interfaceManager->takePairingRequest()) {
|
||||
showPairingPin();
|
||||
}
|
||||
|
||||
if (_pairing_screen_until != 0) {
|
||||
const bool timed_out = static_cast<int32_t>(millis() - _pairing_screen_until) >= 0;
|
||||
if (hasBluetoothConnection() || timed_out) {
|
||||
finishPairingScreen(timed_out);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PIN_USER_BTN
|
||||
if (_userButton) {
|
||||
_userButton->update();
|
||||
@@ -486,7 +530,7 @@ void UITask::loop() {
|
||||
_auto_off = millis() + AUTO_OFF_MILLIS;
|
||||
}
|
||||
#endif
|
||||
if (isDisplayAutoOffDue(_auto_off, AUTO_OFF_MILLIS)) {
|
||||
if (!isPairingScreenActive() && isDisplayAutoOffDue(_auto_off, AUTO_OFF_MILLIS)) {
|
||||
_display->turnOff();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ class UITask : public AbstractUITask {
|
||||
int _msgcount;
|
||||
bool _need_refresh = true;
|
||||
bool _displayWasOn = false; // Track display state before button press
|
||||
unsigned long _pairing_screen_until;
|
||||
unsigned long ui_started_at;
|
||||
|
||||
// Button handlers
|
||||
@@ -58,12 +59,16 @@ class UITask : public AbstractUITask {
|
||||
void handleButtonQuadruplePress();
|
||||
void handleButtonLongPress();
|
||||
bool shouldPlayMessageTone() const;
|
||||
bool isPairingScreenActive() const;
|
||||
void showPairingPin();
|
||||
void finishPairingScreen(bool timed_out);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
UITask(mesh::MainBoard* board, MultiSerialInterface* serial) : AbstractUITask(board, serial), _display(NULL), _sensors(NULL) {
|
||||
_next_refresh = 0;
|
||||
_pairing_screen_until = 0;
|
||||
ui_started_at = 0;
|
||||
}
|
||||
void begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* node_prefs);
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#ifndef AUTO_OFF_MILLIS
|
||||
#define AUTO_OFF_MILLIS 15000 // 15 seconds
|
||||
#endif
|
||||
#ifndef BLE_PAIRING_DISPLAY_MILLIS
|
||||
#define BLE_PAIRING_DISPLAY_MILLIS 120000UL
|
||||
#endif
|
||||
#define BOOT_SCREEN_MILLIS 4000 // 4 seconds
|
||||
|
||||
#ifdef PIN_STATUS_LED
|
||||
@@ -144,6 +147,8 @@ public:
|
||||
: _task(task), _rtc(rtc), _sensors(sensors), _node_prefs(node_prefs), _page(0),
|
||||
_shutdown_init(false), sensors_lpp(200) { }
|
||||
|
||||
void showFirstPage() { _page = HomePage::FIRST; }
|
||||
|
||||
void poll() override {
|
||||
if (_shutdown_init && !_task->isButtonPressed()) { // must wait for USR button to be released
|
||||
_task->shutdown();
|
||||
@@ -179,7 +184,7 @@ public:
|
||||
display.setTextSize(1);
|
||||
display.drawTextCentered(display.width() / 2, 54, tmp);
|
||||
#endif
|
||||
if (_task->hasConnection()) {
|
||||
if (_task->hasBluetoothConnection()) {
|
||||
display.setColor(UIColor::warning_txt);
|
||||
display.setTextSize(1);
|
||||
display.drawTextCentered(display.width() / 2, display.height()-8, "< Connected >");
|
||||
@@ -550,6 +555,36 @@ void UITask::setCurrScreen(UIScreen* c) {
|
||||
_next_refresh = 100;
|
||||
}
|
||||
|
||||
bool UITask::isPairingScreenActive() const {
|
||||
return _pairing_screen_until != 0
|
||||
&& !hasBluetoothConnection()
|
||||
&& static_cast<int32_t>(millis() - _pairing_screen_until) < 0;
|
||||
}
|
||||
|
||||
void UITask::showPairingPin() {
|
||||
const unsigned long now = millis();
|
||||
_pairing_screen_until = now + BLE_PAIRING_DISPLAY_MILLIS;
|
||||
static_cast<HomeScreen*>(home)->showFirstPage();
|
||||
setCurrScreen(home);
|
||||
|
||||
if (_display != NULL) {
|
||||
if (!_display->isOn()) _display->turnOn();
|
||||
_next_refresh = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void UITask::finishPairingScreen(bool timed_out) {
|
||||
_pairing_screen_until = 0;
|
||||
_next_refresh = 0;
|
||||
if (_display == NULL) return;
|
||||
|
||||
if (timed_out) {
|
||||
_display->turnOff();
|
||||
} else {
|
||||
_auto_off = millis() + AUTO_OFF_MILLIS;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
hardware-agnostic pre-shutdown activity should be done here
|
||||
*/
|
||||
@@ -585,6 +620,17 @@ bool UITask::isButtonPressed() const {
|
||||
}
|
||||
|
||||
void UITask::loop() {
|
||||
if (_interfaceManager->takePairingRequest()) {
|
||||
showPairingPin();
|
||||
}
|
||||
|
||||
if (_pairing_screen_until != 0) {
|
||||
const bool timed_out = static_cast<int32_t>(millis() - _pairing_screen_until) >= 0;
|
||||
if (hasBluetoothConnection() || timed_out) {
|
||||
finishPairingScreen(timed_out);
|
||||
}
|
||||
}
|
||||
|
||||
char c = 0;
|
||||
#if UI_HAS_JOYSTICK
|
||||
int ev = user_btn.check();
|
||||
@@ -657,6 +703,12 @@ void UITask::loop() {
|
||||
}
|
||||
#endif
|
||||
|
||||
if (isPairingScreenActive()) {
|
||||
static_cast<HomeScreen*>(home)->showFirstPage();
|
||||
if (curr != home) setCurrScreen(home);
|
||||
c = 0;
|
||||
}
|
||||
|
||||
if (c != 0 && curr) {
|
||||
curr->handleInput(c);
|
||||
_auto_off = millis() + AUTO_OFF_MILLIS; // extend auto-off timer
|
||||
@@ -693,7 +745,7 @@ void UITask::loop() {
|
||||
}
|
||||
}
|
||||
|
||||
if (millis() < _alert_expiry) { // render alert popup
|
||||
if (!isPairingScreenActive() && millis() < _alert_expiry) { // render alert popup
|
||||
_display->setTextSize(1);
|
||||
int y = _display->height() / 3;
|
||||
int p = _display->height() / 32;
|
||||
@@ -717,7 +769,7 @@ void UITask::loop() {
|
||||
_auto_off = millis() + AUTO_OFF_MILLIS;
|
||||
}
|
||||
#endif
|
||||
if (isDisplayAutoOffDue(_auto_off, AUTO_OFF_MILLIS)) {
|
||||
if (!isPairingScreenActive() && isDisplayAutoOffDue(_auto_off, AUTO_OFF_MILLIS)) {
|
||||
_display->turnOff();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -39,6 +39,7 @@ class UITask : public AbstractUITask {
|
||||
NodePrefs* _node_prefs;
|
||||
char _alert[80];
|
||||
unsigned long _alert_expiry;
|
||||
unsigned long _pairing_screen_until;
|
||||
int _msgcount;
|
||||
unsigned long ui_started_at, next_batt_chck;
|
||||
int next_backlight_btn_check = 0;
|
||||
@@ -68,12 +69,16 @@ class UITask : public AbstractUITask {
|
||||
char handleTripleClick(char c);
|
||||
|
||||
void setCurrScreen(UIScreen* c);
|
||||
bool isPairingScreenActive() const;
|
||||
void showPairingPin();
|
||||
void finishPairingScreen(bool timed_out);
|
||||
|
||||
public:
|
||||
|
||||
UITask(mesh::MainBoard* board, MultiSerialInterface* serial) : AbstractUITask(board, serial), _display(NULL), _sensors(NULL) {
|
||||
next_batt_chck = _next_refresh = 0;
|
||||
_cached_batt_mv = 0;
|
||||
_pairing_screen_until = 0;
|
||||
ui_started_at = 0;
|
||||
curr = NULL;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "MyMesh.h"
|
||||
#include <helpers/radiolib/RxBoostedGainDefaults.h>
|
||||
#include <algorithm>
|
||||
#include <stdlib.h> // for qsort()
|
||||
#include <helpers/CLICommandUtils.h>
|
||||
@@ -3023,12 +3024,10 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
|
||||
|
||||
_prefs.adc_multiplier = 0.0f; // 0.0f means use default board multiplier
|
||||
|
||||
#if defined(USE_SX1262) || defined(USE_SX1268)
|
||||
#ifdef SX126X_RX_BOOSTED_GAIN
|
||||
_prefs.rx_boosted_gain = SX126X_RX_BOOSTED_GAIN;
|
||||
#else
|
||||
_prefs.rx_boosted_gain = 1; // enabled by default;
|
||||
#endif
|
||||
#if defined(USE_SX1262) || defined(USE_SX1268) || defined(USE_LR1110) \
|
||||
|| defined(USE_LR2021) || defined(SX126X_RX_BOOSTED_GAIN) \
|
||||
|| defined(RX_BOOSTED_GAIN)
|
||||
_prefs.rx_boosted_gain = mesh::radio::configuredRxBoostedGainDefault();
|
||||
#endif
|
||||
_prefs.radio_fem_rxgain = 1; // LoRa FEM RX gain on by default (FEM boards)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "MyMesh.h"
|
||||
#include <helpers/radiolib/RxBoostedGainDefaults.h>
|
||||
#include <helpers/CLICommandUtils.h>
|
||||
#if defined(MESHCORE_ESP32_FULL_PROFILE)
|
||||
#include <helpers/FloodFilterPolicy.h>
|
||||
@@ -1157,12 +1158,10 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
|
||||
_prefs.gps_interval = 0;
|
||||
_prefs.advert_loc_policy = ADVERT_LOC_PREFS;
|
||||
|
||||
#if defined(USE_SX1262) || defined(USE_SX1268)
|
||||
#ifdef SX126X_RX_BOOSTED_GAIN
|
||||
_prefs.rx_boosted_gain = SX126X_RX_BOOSTED_GAIN;
|
||||
#else
|
||||
_prefs.rx_boosted_gain = 1; // enabled by default;
|
||||
#endif
|
||||
#if defined(USE_SX1262) || defined(USE_SX1268) || defined(USE_LR1110) \
|
||||
|| defined(USE_LR2021) || defined(SX126X_RX_BOOSTED_GAIN) \
|
||||
|| defined(RX_BOOSTED_GAIN)
|
||||
_prefs.rx_boosted_gain = mesh::radio::configuredRxBoostedGainDefault();
|
||||
#endif
|
||||
_prefs.radio_fem_rxgain = 1;
|
||||
|
||||
|
||||
@@ -90,6 +90,18 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isBluetoothConnected() const {
|
||||
if (!_enabled) return false;
|
||||
|
||||
for (auto iface : _interfaces) {
|
||||
if (iface.instance && iface.type == InterfaceType::Bluetooth
|
||||
&& iface.instance->isEnabled() && iface.instance->isConnected()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// enable all interfaces
|
||||
void enable() override {
|
||||
_enabled = true;
|
||||
@@ -181,7 +193,8 @@ public:
|
||||
|
||||
bool takePairingRequest() override {
|
||||
for (auto iface : _interfaces) {
|
||||
if (iface.instance && iface.instance->isEnabled()
|
||||
if (iface.instance && iface.type == InterfaceType::Bluetooth
|
||||
&& iface.instance->isEnabled()
|
||||
&& iface.instance->takePairingRequest()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ static bool isBondAuthenticationFailure(uint8_t reason) {
|
||||
void SerialBLEInterface::onConnect(uint16_t connection_handle) {
|
||||
BLE_DEBUG_PRINTLN("SerialBLEInterface: connected handle=0x%04X", connection_handle);
|
||||
if (instance) {
|
||||
instance->_pairingRequestPending.store(false, std::memory_order_release);
|
||||
instance->_conn_handle = connection_handle;
|
||||
instance->_isDeviceConnected = false;
|
||||
instance->_security_timer.start(millis());
|
||||
@@ -46,6 +47,7 @@ void SerialBLEInterface::onDisconnect(uint16_t connection_handle, uint8_t reason
|
||||
BLE_DEBUG_PRINTLN("SerialBLEInterface: disconnected handle=0x%04X reason=%u", connection_handle, reason);
|
||||
if (instance) {
|
||||
if (instance->_conn_handle == connection_handle) {
|
||||
instance->_pairingRequestPending.store(false, std::memory_order_release);
|
||||
instance->_conn_handle = BLE_CONN_HANDLE_INVALID;
|
||||
instance->_isDeviceConnected = false;
|
||||
instance->_security_timer.cancel();
|
||||
@@ -99,9 +101,11 @@ void SerialBLEInterface::onSecured(uint16_t connection_handle) {
|
||||
}
|
||||
|
||||
bool SerialBLEInterface::onPairingPasskey(uint16_t connection_handle, uint8_t const passkey[6], bool match_request) {
|
||||
(void)connection_handle;
|
||||
(void)passkey;
|
||||
BLE_DEBUG_PRINTLN("SerialBLEInterface: pairing passkey request match=%d", match_request);
|
||||
if (instance && instance->isValidConnection(connection_handle)) {
|
||||
instance->_pairingRequestPending.store(true, std::memory_order_release);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -397,6 +401,7 @@ bool SerialBLEInterface::isAdvertising() const {
|
||||
void SerialBLEInterface::enable() {
|
||||
if (_isEnabled) return;
|
||||
|
||||
_pairingRequestPending.store(false, std::memory_order_release);
|
||||
_isEnabled = true;
|
||||
clearBuffers();
|
||||
_last_health_check = millis();
|
||||
@@ -413,6 +418,7 @@ void SerialBLEInterface::disconnect() {
|
||||
|
||||
void SerialBLEInterface::disable() {
|
||||
_isEnabled = false;
|
||||
_pairingRequestPending.store(false, std::memory_order_release);
|
||||
BLE_DEBUG_PRINTLN("SerialBLEInterface: disable");
|
||||
|
||||
Bluefruit.Advertising.restartOnDisconnect(false);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "../BleTxStallWatchdog.h"
|
||||
#include "SecuritySessionTimer.h"
|
||||
#include <bluefruit.h>
|
||||
#include <atomic>
|
||||
|
||||
#ifndef BLE_TX_POWER
|
||||
#define BLE_TX_POWER 4
|
||||
@@ -20,6 +21,7 @@ class SerialBLEInterface : public BaseSerialInterface {
|
||||
ble_gap_addr_t _peer_address = {};
|
||||
bool _peer_address_valid;
|
||||
bool _bond_removed_for_connection;
|
||||
std::atomic<bool> _pairingRequestPending{false};
|
||||
SecuritySessionTimer _security_timer;
|
||||
mesh::BleTxStallWatchdog _tx_stall_watchdog;
|
||||
mesh::BleDisconnectRecovery _tx_disconnect_recovery;
|
||||
@@ -83,6 +85,9 @@ public:
|
||||
bool isReadBusy() const override;
|
||||
bool isWriteBusy() const override;
|
||||
bool hasPendingIO() const override;
|
||||
bool takePairingRequest() override {
|
||||
return _pairingRequestPending.exchange(false, std::memory_order_acq_rel);
|
||||
}
|
||||
size_t writeFrame(const uint8_t src[], size_t len) override;
|
||||
size_t checkRecvFrame(uint8_t dest[]) override;
|
||||
};
|
||||
|
||||
@@ -16,6 +16,8 @@ inline void lr11x0ResetAGC(LR11x0* radio, float freqMHz) {
|
||||
radio->calibrateImageRejection(freqMHz - 4.0f, freqMHz + 4.0f);
|
||||
|
||||
#ifdef RX_BOOSTED_GAIN
|
||||
// Fallback for callers without a runtime override. RadioLibWrapper::resetAGC()
|
||||
// reapplies its cached radio.rxgain selection before receive mode resumes.
|
||||
radio->setRxBoostedGainMode(RX_BOOSTED_GAIN);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mesh {
|
||||
namespace radio {
|
||||
|
||||
// SX126x targets use SX126X_RX_BOOSTED_GAIN while LR11xx and several other
|
||||
// radios use RX_BOOSTED_GAIN. Keep persisted first-install defaults aligned
|
||||
// with whichever target-level setting initialized the physical radio.
|
||||
constexpr uint8_t selectRxBoostedGainDefault(bool sx_configured,
|
||||
int sx_value,
|
||||
bool generic_configured,
|
||||
int generic_value,
|
||||
uint8_t fallback = 1) {
|
||||
return sx_configured ? (sx_value ? 1 : 0)
|
||||
: (generic_configured ? (generic_value ? 1 : 0)
|
||||
: (fallback ? 1 : 0));
|
||||
}
|
||||
|
||||
inline uint8_t configuredRxBoostedGainDefault() {
|
||||
#ifdef SX126X_RX_BOOSTED_GAIN
|
||||
return selectRxBoostedGainDefault(true, SX126X_RX_BOOSTED_GAIN,
|
||||
false, 0);
|
||||
#elif defined(RX_BOOSTED_GAIN)
|
||||
return selectRxBoostedGainDefault(false, 0, true, RX_BOOSTED_GAIN);
|
||||
#else
|
||||
return selectRxBoostedGainDefault(false, 0, false, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace radio
|
||||
} // namespace mesh
|
||||
@@ -26,6 +26,8 @@ inline void sx126xResetAGC(SX126x* radio) {
|
||||
radio->setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
|
||||
#endif
|
||||
#ifdef SX126X_RX_BOOSTED_GAIN
|
||||
// Fallback for callers without a runtime override. RadioLibWrapper::resetAGC()
|
||||
// reapplies its cached radio.rxgain selection before receive mode resumes.
|
||||
radio->setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
|
||||
#endif
|
||||
#ifdef SX126X_REGISTER_PATCH
|
||||
|
||||
+2
-1
@@ -31,6 +31,7 @@ does not reflect the GoogleTest count -- run the built binary directly
|
||||
| `test_mqtt_topic_router` | `src/helpers/MQTTTopicRouter.h` | complete preset/custom topic-routing contract; MeshRank packets-only behavior; required identifiers; invalid inputs/slots; exact buffer boundaries |
|
||||
| `test_mqtt_connection_policy` | `src/helpers/MQTTConnectionPolicy.h` | reconnect guard/backoff/stagger and breaker transitions; stable reset; JWT lifetime/renewal policy; exact timing boundaries and 32-bit `millis()` rollover |
|
||||
| `test_wifi_reconnect_policy` | `src/helpers/WiFiReconnectPolicy.h` | five-minute forced reconnect cadence, connection resets, duplicate disconnect observations, and 32-bit `millis()` rollover |
|
||||
| `test_radio_liveness` | `src/helpers/RadioLivenessTracker.h`, `src/helpers/radiolib/RxBoostedGainDefaults.h` | staged radio recovery, activity reset and rollover handling; target-specific RX boosted-gain defaults and SX126x precedence |
|
||||
| `test_lr1110_rx_recovery` | `src/helpers/radiolib/LR1110RxRecovery.h` | LR1110 four-byte RX-buffer shift signature; captured and accumulated shifts; ordinary/scoped packet exclusions |
|
||||
| `test_mqtt_packet_queue_policy` | `src/helpers/MQTTPacketQueuePolicy.h` | queue-full eviction; stale-disconnect flush; adaptive drain limits; bounded QoS0 retries; exact timing boundaries and 32-bit `millis()` rollover |
|
||||
| `test_mqtt_runtime_buffer_lifecycle` | `src/helpers/MQTTRuntimeBufferLifecycle.h` | idempotent allocation/release; partial-allocation degradation; retry of only missing buffers |
|
||||
@@ -43,7 +44,7 @@ does not reflect the GoogleTest count -- run the built binary directly
|
||||
| `test_logical_message_cache` | `src/helpers/LogicalMessageCache.h` | bounded logical-message mapping; stable retry timestamps; exact older retries after newer messages; stale and same-timestamp mismatch rejection |
|
||||
| `test_remote_cli_reply_cache` | `src/helpers/RemoteCliReplyCache.h`, `src/helpers/RemoteCliRequest.h` | authenticated logical-request matching; bounded recent-reply history; backward-compatible retry identity; empty-response completion; on-air truncation and clearing |
|
||||
| `test_companion_frame_queue` | `src/helpers/CompanionFrameQueue.h` | response/required/best-effort classification; reserved capacity; stable priority; safe eviction; message-waiting coalescing |
|
||||
| `test_serial_mode_switch` | `src/helpers/ArduinoSerialInterface.cpp` | independent terminal/seeder control-sequence recognition across reads and binary-frame boundaries; passthrough ownership of USB input and suppression of binary output |
|
||||
| `test_serial_mode_switch` | `src/helpers/ArduinoSerialInterface.cpp`, `src/helpers/MultiSerialInterface.h` | independent terminal/seeder control-sequence recognition across reads and binary-frame boundaries; passthrough ownership of USB input and suppression of binary output; Bluetooth-only connection and pairing-request routing |
|
||||
| `test_ble_tx_stall_watchdog` | `src/helpers/BleTxStallWatchdog.h` | exact BLE fragment progress; blocked-reply timeout; rollover-safe elapsed time; disconnect recovery retry and completion |
|
||||
| `test_utils` | `src/Utils.cpp` | `Utils::toHex` (upstream) |
|
||||
|
||||
|
||||
@@ -1,10 +1,28 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <helpers/RadioLivenessTracker.h>
|
||||
#include <helpers/radiolib/RxBoostedGainDefaults.h>
|
||||
|
||||
using mesh::RadioLivenessTracker;
|
||||
using mesh::RadioRecoveryAction;
|
||||
|
||||
TEST(RxBoostedGainDefaults, UsesTargetCompileTimeSetting) {
|
||||
using mesh::radio::selectRxBoostedGainDefault;
|
||||
|
||||
EXPECT_EQ(selectRxBoostedGainDefault(true, 0, false, 0), 0);
|
||||
EXPECT_EQ(selectRxBoostedGainDefault(true, 1, false, 0), 1);
|
||||
EXPECT_EQ(selectRxBoostedGainDefault(false, 0, true, 0), 0);
|
||||
EXPECT_EQ(selectRxBoostedGainDefault(false, 0, true, 1), 1);
|
||||
EXPECT_EQ(selectRxBoostedGainDefault(false, 0, false, 0), 1);
|
||||
}
|
||||
|
||||
TEST(RxBoostedGainDefaults, Sx126xSettingTakesPrecedence) {
|
||||
using mesh::radio::selectRxBoostedGainDefault;
|
||||
|
||||
EXPECT_EQ(selectRxBoostedGainDefault(true, 0, true, 1), 0);
|
||||
EXPECT_EQ(selectRxBoostedGainDefault(true, 1, true, 0), 1);
|
||||
}
|
||||
|
||||
TEST(RadioLivenessTracker, StagesSoftThenHardRecovery) {
|
||||
RadioLivenessTracker tracker;
|
||||
tracker.begin(1000);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "helpers/ArduinoSerialInterface.h"
|
||||
#include "helpers/MultiSerialInterface.h"
|
||||
|
||||
class BufferStream : public Stream {
|
||||
public:
|
||||
@@ -41,6 +42,63 @@ public:
|
||||
static const char START_TOKEN[] = "+++MESHCORE-TERM-START";
|
||||
static const char SEEDER_TOKEN[] = "ota folder on";
|
||||
|
||||
class FakeSerialInterface : public BaseSerialInterface {
|
||||
public:
|
||||
bool enabled = false;
|
||||
bool connected = false;
|
||||
bool pairing_request = false;
|
||||
|
||||
void enable() override { enabled = true; }
|
||||
void disable() override { enabled = false; }
|
||||
bool isEnabled() const override { return enabled; }
|
||||
bool isConnected() const override { return connected; }
|
||||
bool isReadBusy() const override { return false; }
|
||||
bool isWriteBusy() const override { return false; }
|
||||
bool takePairingRequest() override {
|
||||
bool pending = pairing_request;
|
||||
pairing_request = false;
|
||||
return pending;
|
||||
}
|
||||
size_t writeFrame(const uint8_t[], size_t len) override { return len; }
|
||||
size_t checkRecvFrame(uint8_t[]) override { return 0; }
|
||||
};
|
||||
|
||||
TEST(MultiSerialInterface, TracksBluetoothConnectionSeparately) {
|
||||
MultiSerialInterface manager;
|
||||
FakeSerialInterface usb;
|
||||
FakeSerialInterface bluetooth;
|
||||
usb.connected = true;
|
||||
|
||||
ASSERT_TRUE(manager.addInterface(InterfaceType::USB, &usb));
|
||||
ASSERT_TRUE(manager.addInterface(InterfaceType::Bluetooth, &bluetooth));
|
||||
manager.enable();
|
||||
|
||||
EXPECT_TRUE(manager.isConnected());
|
||||
EXPECT_FALSE(manager.isBluetoothConnected());
|
||||
|
||||
bluetooth.connected = true;
|
||||
EXPECT_TRUE(manager.isBluetoothConnected());
|
||||
|
||||
manager.disableBluetooth();
|
||||
EXPECT_FALSE(manager.isBluetoothConnected());
|
||||
}
|
||||
|
||||
TEST(MultiSerialInterface, PairingRequestsComeOnlyFromBluetooth) {
|
||||
MultiSerialInterface manager;
|
||||
FakeSerialInterface usb;
|
||||
FakeSerialInterface bluetooth;
|
||||
ASSERT_TRUE(manager.addInterface(InterfaceType::USB, &usb));
|
||||
ASSERT_TRUE(manager.addInterface(InterfaceType::Bluetooth, &bluetooth));
|
||||
manager.enable();
|
||||
|
||||
usb.pairing_request = true;
|
||||
EXPECT_FALSE(manager.takePairingRequest());
|
||||
|
||||
bluetooth.pairing_request = true;
|
||||
EXPECT_TRUE(manager.takePairingRequest());
|
||||
EXPECT_FALSE(manager.takePairingRequest());
|
||||
}
|
||||
|
||||
TEST(SerialModeSwitch, RecognizesControlSequenceAcrossReads) {
|
||||
BufferStream stream;
|
||||
ArduinoSerialInterface interface;
|
||||
|
||||
Reference in new issue
Block a user