mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-11-01 10:21:59 +00:00
refactor(companion): the app's links through upstream's MultiSerialInterface
- Bluetooth + USB (+ WiFi/Ethernet/UART per build) in one interface_manager,
as upstream; frames go to every enabled link, USB is read while BT is
connected. DUAL_SERIAL now means ENABLE_USB_INTERFACE.
- WiFi interface with upstream's wifi_* prefs and set/get wifi.* CLI.
- isClientConnected moved into ArduinoSerialInterface (DTR on nRF52 and
ESP32 native CDC).
- UI uses isBluetoothEnabled/enableBluetooth/disableBluetooth; turning BT
off leaves USB and the other links on.
- DualSerialInterface removed.
- Sim build gains DynamicConfigSerializer.cpp (broken since bd64c203).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
#include <helpers/ui/DisplayDriver.h>
|
#include <helpers/ui/DisplayDriver.h>
|
||||||
#include <helpers/ui/UIScreen.h>
|
#include <helpers/ui/UIScreen.h>
|
||||||
#include <helpers/SensorManager.h>
|
#include <helpers/SensorManager.h>
|
||||||
#include <helpers/BaseSerialInterface.h>
|
#include <helpers/MultiSerialInterface.h>
|
||||||
#include <helpers/BaseChatMesh.h> // MAX_TEXT_LEN
|
#include <helpers/BaseChatMesh.h> // MAX_TEXT_LEN
|
||||||
#include <helpers/TxtDataHelpers.h> // TXT_TYPE_*
|
#include <helpers/TxtDataHelpers.h> // TXT_TYPE_*
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
@@ -32,10 +32,10 @@ enum class UIEventType {
|
|||||||
class UITaskBase {
|
class UITaskBase {
|
||||||
protected:
|
protected:
|
||||||
mesh::MainBoard* _board;
|
mesh::MainBoard* _board;
|
||||||
BaseSerialInterface* _serial;
|
MultiSerialInterface* _serial; // the interface manager (main.cpp)
|
||||||
bool _connected;
|
bool _connected;
|
||||||
|
|
||||||
UITaskBase(mesh::MainBoard* board, BaseSerialInterface* serial) : _board(board), _serial(serial) {
|
UITaskBase(mesh::MainBoard* board, MultiSerialInterface* serial) : _board(board), _serial(serial) {
|
||||||
_connected = false;
|
_connected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,9 +94,10 @@ public:
|
|||||||
// open USB-CDC port). For app-connected behaviour like Auto buzzer mute.
|
// open USB-CDC port). For app-connected behaviour like Auto buzzer mute.
|
||||||
bool isClientConnected() const { return _serial->isClientConnected(); }
|
bool isClientConnected() const { return _serial->isClientConnected(); }
|
||||||
uint16_t getBattMilliVolts() const { return _board->getBattMilliVolts(); }
|
uint16_t getBattMilliVolts() const { return _board->getBattMilliVolts(); }
|
||||||
bool isSerialEnabled() const { return _serial->isEnabled(); }
|
// Bluetooth alone (USB and the rest stay on), remembered over a restart.
|
||||||
void enableSerial() { _serial->enable(); the_mesh.rememberBle(true); }
|
bool isBluetoothEnabled() const { return _serial->isBluetoothEnabled(); }
|
||||||
void disableSerial() { _serial->disable(); the_mesh.rememberBle(false); }
|
void enableBluetooth() { _serial->enableBluetooth(); the_mesh.rememberBle(true); }
|
||||||
|
void disableBluetooth() { _serial->disableBluetooth(); the_mesh.rememberBle(false); }
|
||||||
virtual void notify(UIEventType t = UIEventType::none) = 0;
|
virtual void notify(UIEventType t = UIEventType::none) = 0;
|
||||||
// Single choke point for every controlled power-down (low-battery auto-off,
|
// Single choke point for every controlled power-down (low-battery auto-off,
|
||||||
// long-press power-off, and every board.reboot() caller too): flush
|
// long-press power-off, and every board.reboot() caller too): flush
|
||||||
@@ -122,7 +123,7 @@ class AbstractUITask : public MyMesh::Listener, public UITaskBase {
|
|||||||
protected:
|
protected:
|
||||||
int _queue_len = 0; // last onQueueSizeChanged() -- newMsg()'s msgcount
|
int _queue_len = 0; // last onQueueSizeChanged() -- newMsg()'s msgcount
|
||||||
|
|
||||||
AbstractUITask(mesh::MainBoard* board, BaseSerialInterface* serial) : UITaskBase(board, serial) { }
|
AbstractUITask(mesh::MainBoard* board, MultiSerialInterface* serial) : UITaskBase(board, serial) { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// An end-to-end ACK (CRC) arrived for one of our sent messages — drives the
|
// An end-to-end ACK (CRC) arrived for one of our sent messages — drives the
|
||||||
|
|||||||
@@ -1372,6 +1372,9 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
|
|||||||
_prefs.clearFields();
|
_prefs.clearFields();
|
||||||
memset(_prefs.ch_scope_idx, NodePrefs::CH_SCOPE_DEFAULT, sizeof(_prefs.ch_scope_idx));
|
memset(_prefs.ch_scope_idx, NodePrefs::CH_SCOPE_DEFAULT, sizeof(_prefs.ch_scope_idx));
|
||||||
_prefs.airtime_factor = 1.0;
|
_prefs.airtime_factor = 1.0;
|
||||||
|
#ifdef ENABLE_WIFI_INTERFACE
|
||||||
|
_prefs.wifi_enabled = 1; // on, so a WiFi-only build works; it doesn't start without an SSID
|
||||||
|
#endif
|
||||||
_prefs.tx_delay_factor = 0.5f;
|
_prefs.tx_delay_factor = 0.5f;
|
||||||
_prefs.direct_tx_delay_factor = 0.2f;
|
_prefs.direct_tx_delay_factor = 0.2f;
|
||||||
strcpy(_prefs.node_name, "NONAME");
|
strcpy(_prefs.node_name, "NONAME");
|
||||||
@@ -1570,7 +1573,7 @@ bool MyMesh::isValidClientRepeatFreq(uint32_t f) const {
|
|||||||
|
|
||||||
void MyMesh::startInterface(BaseSerialInterface &serial) {
|
void MyMesh::startInterface(BaseSerialInterface &serial) {
|
||||||
_serial = &serial;
|
_serial = &serial;
|
||||||
if (!_prefs.ble_off) serial.enable();
|
serial.enable(); // main.cpp then turns Bluetooth off if the user left it off (ble_off)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isAllZero(const uint8_t* buf, size_t n) {
|
static bool isAllZero(const uint8_t* buf, size_t n) {
|
||||||
|
|||||||
@@ -76,6 +76,49 @@ bool MyMesh::handleCliCommand(const char* command, char* reply, int n) {
|
|||||||
else { _prefs.tz_offset_hours = (int8_t)tz; savePrefs(); snprintf(reply, n, "OK"); }
|
else { _prefs.tz_offset_hours = (int8_t)tz; savePrefs(); snprintf(reply, n, "OK"); }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#ifdef ENABLE_WIFI_INTERFACE
|
||||||
|
// The app over WiFi (upstream's commands; applied at the next start).
|
||||||
|
if (memcmp(command, "set wifi.ssid ", 14) == 0) {
|
||||||
|
StrHelper::strncpy(_prefs.wifi_ssid, &command[14], sizeof(_prefs.wifi_ssid));
|
||||||
|
savePrefs();
|
||||||
|
snprintf(reply, n, "> wifi.ssid is now %s (set wifi.pwd too, then reboot)", _prefs.wifi_ssid);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (memcmp(command, "set wifi.pwd ", 13) == 0) {
|
||||||
|
StrHelper::strncpy(_prefs.wifi_pwd, &command[13], sizeof(_prefs.wifi_pwd));
|
||||||
|
savePrefs();
|
||||||
|
snprintf(reply, n, "> wifi.pwd updated (reboot to apply)");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (strcmp(command, "get wifi.pwd") == 0) { snprintf(reply, n, "> %s", _prefs.wifi_pwd); return true; }
|
||||||
|
if (strcmp(command, "set wifi.clear") == 0) {
|
||||||
|
_prefs.wifi_ssid[0] = 0;
|
||||||
|
_prefs.wifi_pwd[0] = 0;
|
||||||
|
savePrefs();
|
||||||
|
snprintf(reply, n, "> wifi config cleared (reboot to apply)");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (strcmp(command, "get wifi.ssid") == 0) {
|
||||||
|
snprintf(reply, n, "> %s", _prefs.getWifiSSID()[0] ? _prefs.getWifiSSID() : "(not set)");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (memcmp(command, "set wifi.enabled ", 17) == 0) {
|
||||||
|
_prefs.wifi_enabled = atoi(&command[17]) ? 1 : 0;
|
||||||
|
savePrefs();
|
||||||
|
snprintf(reply, n, "> wifi.enabled is now %d (reboot to apply)", _prefs.wifi_enabled);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (strcmp(command, "get wifi.enabled") == 0) { snprintf(reply, n, "> %d", _prefs.wifi_enabled); return true; }
|
||||||
|
if (strcmp(command, "get wifi.status") == 0) {
|
||||||
|
snprintf(reply, n, WiFi.status() == WL_CONNECTED ? "> connected" : "> disconnected");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (strcmp(command, "get wifi.ip") == 0) {
|
||||||
|
if (WiFi.status() == WL_CONNECTED) snprintf(reply, n, "> %s", WiFi.localIP().toString().c_str());
|
||||||
|
else snprintf(reply, n, "> (not connected)");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// The position adverts carry while the GPS is off (Settings > Privacy > Position).
|
// The position adverts carry while the GPS is off (Settings > Privacy > Position).
|
||||||
if (strcmp(command, "get lat") == 0) { snprintf(reply, n, "> %.6f", sensors.node_lat); return true; }
|
if (strcmp(command, "get lat") == 0) { snprintf(reply, n, "> %.6f", sensors.node_lat); return true; }
|
||||||
if (strcmp(command, "get lon") == 0) { snprintf(reply, n, "> %.6f", sensors.node_lon); return true; }
|
if (strcmp(command, "get lon") == 0) { snprintf(reply, n, "> %.6f", sensors.node_lon); return true; }
|
||||||
|
|||||||
@@ -176,8 +176,14 @@ struct NodePrefsFields {
|
|||||||
// ── Connectivity (BLE) ────────────────────────────────────────────────
|
// ── Connectivity (BLE) ────────────────────────────────────────────────
|
||||||
uint32_t ble_pin;
|
uint32_t ble_pin;
|
||||||
// 1 = the user switched Bluetooth off: it stays off after a reboot or
|
// 1 = the user switched Bluetooth off: it stays off after a reboot or
|
||||||
// hibernate (MyMesh::startInterface). USB keeps working either way.
|
// hibernate (main.cpp). USB keeps working either way.
|
||||||
uint8_t ble_off;
|
uint8_t ble_off;
|
||||||
|
#ifdef ENABLE_WIFI_INTERFACE
|
||||||
|
// The app over WiFi (TCP), upstream's: an empty SSID uses the build's WIFI_SSID.
|
||||||
|
char wifi_ssid[33];
|
||||||
|
char wifi_pwd[64];
|
||||||
|
uint8_t wifi_enabled;
|
||||||
|
#endif
|
||||||
|
|
||||||
// ── Power & battery ───────────────────────────────────────────────────
|
// ── Power & battery ───────────────────────────────────────────────────
|
||||||
uint16_t low_batt_mv; // auto-shutdown threshold: 0=disabled, 3000-3500 mV
|
uint16_t low_batt_mv; // auto-shutdown threshold: 0=disabled, 3000-3500 mV
|
||||||
@@ -893,6 +899,13 @@ class NodePrefs : public NodePrefsFields, public ConfigSerializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void lockSolo(Section& s) { s.hex("hash", lock_screen_password); s.hex("salt", lock_screen_password_salt); }
|
void lockSolo(Section& s) { s.hex("hash", lock_screen_password); s.hex("salt", lock_screen_password_salt); }
|
||||||
|
#ifdef ENABLE_WIFI_INTERFACE
|
||||||
|
void wifiKeys(Section& s) {
|
||||||
|
s.def("ssid", wifi_ssid, sizeof(wifi_ssid));
|
||||||
|
s.def("pwd", wifi_pwd, sizeof(wifi_pwd));
|
||||||
|
s.def("enabled", wifi_enabled);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
void soloKeys(Section& s) {
|
void soloKeys(Section& s) {
|
||||||
s.sub("radio", radio_solo); s.sub("repeater", repeater_solo); s.sub("power", power_solo);
|
s.sub("radio", radio_solo); s.sub("repeater", repeater_solo); s.sub("power", power_solo);
|
||||||
s.sub("display", display_solo); s.sub("clock", clock_solo); s.sub("sound", sound_solo);
|
s.sub("display", display_solo); s.sub("clock", clock_solo); s.sub("sound", sound_solo);
|
||||||
@@ -902,6 +915,9 @@ class NodePrefs : public NodePrefsFields, public ConfigSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Section radio, gps, repeat, comp;
|
Section radio, gps, repeat, comp;
|
||||||
|
#ifdef ENABLE_WIFI_INTERFACE
|
||||||
|
Section wifi;
|
||||||
|
#endif
|
||||||
Section solo, radio_solo, preset[USER_RADIO_PRESET_MAX], repeater_solo, power_solo, display_solo,
|
Section solo, radio_solo, preset[USER_RADIO_PRESET_MAX], repeater_solo, power_solo, display_solo,
|
||||||
clock_solo, sound_solo, scope_solo, bot_solo, gps_solo, share_solo, locator_solo,
|
clock_solo, sound_solo, scope_solo, bot_solo, gps_solo, share_solo, locator_solo,
|
||||||
lists_solo, gpio_solo, msgs_solo, lock_solo;
|
lists_solo, gpio_solo, msgs_solo, lock_solo;
|
||||||
@@ -918,6 +934,9 @@ protected:
|
|||||||
def("repeat", repeat);
|
def("repeat", repeat);
|
||||||
def("comp", comp);
|
def("comp", comp);
|
||||||
def("custom", custom);
|
def("custom", custom);
|
||||||
|
#ifdef ENABLE_WIFI_INTERFACE
|
||||||
|
def("wifi", wifi);
|
||||||
|
#endif
|
||||||
def("solo", solo);
|
def("solo", solo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -929,6 +948,9 @@ public:
|
|||||||
NodePrefs()
|
NodePrefs()
|
||||||
: radio(this, &NodePrefs::radioKeys), gps(this, &NodePrefs::gpsKeys),
|
: radio(this, &NodePrefs::radioKeys), gps(this, &NodePrefs::gpsKeys),
|
||||||
repeat(this, &NodePrefs::repeatKeys), comp(this, &NodePrefs::compKeys),
|
repeat(this, &NodePrefs::repeatKeys), comp(this, &NodePrefs::compKeys),
|
||||||
|
#ifdef ENABLE_WIFI_INTERFACE
|
||||||
|
wifi(this, &NodePrefs::wifiKeys),
|
||||||
|
#endif
|
||||||
solo(this, &NodePrefs::soloKeys), radio_solo(this, &NodePrefs::radioSolo),
|
solo(this, &NodePrefs::soloKeys), radio_solo(this, &NodePrefs::radioSolo),
|
||||||
preset{ {this, &NodePrefs::presetKeys}, {this, &NodePrefs::presetKeys},
|
preset{ {this, &NodePrefs::presetKeys}, {this, &NodePrefs::presetKeys},
|
||||||
{this, &NodePrefs::presetKeys}, {this, &NodePrefs::presetKeys} },
|
{this, &NodePrefs::presetKeys}, {this, &NodePrefs::presetKeys} },
|
||||||
@@ -951,6 +973,13 @@ public:
|
|||||||
|
|
||||||
// The board's settings (upstream's getCustom()), for Board::attachDynamicPrefs().
|
// The board's settings (upstream's getCustom()), for Board::attachDynamicPrefs().
|
||||||
KeyValueStore* getCustom() { return &custom; }
|
KeyValueStore* getCustom() { return &custom; }
|
||||||
|
#ifdef ENABLE_WIFI_INTERFACE
|
||||||
|
#ifndef WIFI_SSID
|
||||||
|
#define WIFI_SSID ""
|
||||||
|
#endif
|
||||||
|
// use ssid from prefs, or fallback to ssid from build flags
|
||||||
|
const char* getWifiSSID() const { return wifi_ssid[0] ? wifi_ssid : WIFI_SSID; }
|
||||||
|
#endif
|
||||||
bool isRepeatEn() const { return client_repeat != 0; }
|
bool isRepeatEn() const { return client_repeat != 0; }
|
||||||
void setRepeatEn(bool en) { client_repeat = en ? 1 : 0; }
|
void setRepeatEn(bool en) { client_repeat = en ? 1 : 0; }
|
||||||
|
|
||||||
|
|||||||
+191
-116
@@ -65,72 +65,94 @@ static uint32_t _atoi(const char* sp) {
|
|||||||
DataStore store(sim_fs, rtc_clock);
|
DataStore store(sim_fs, rtc_clock);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ESP32
|
// The companion app's links (upstream's interface manager): Bluetooth, USB,
|
||||||
#ifdef WIFI_SSID
|
// WiFi, Ethernet, a UART, whichever the build has, all at once. DUAL_SERIAL
|
||||||
#include <helpers/esp32/SerialWifiInterface.h>
|
// (Solo's builds) is Bluetooth and USB.
|
||||||
SerialWifiInterface serial_interface;
|
#if defined(DUAL_SERIAL) && !defined(ENABLE_USB_INTERFACE)
|
||||||
#ifndef TCP_PORT
|
#define ENABLE_USB_INTERFACE
|
||||||
#define TCP_PORT 5000
|
#endif
|
||||||
#endif
|
#if !defined(BLE_PIN_CODE) && !defined(ENABLE_WIFI_INTERFACE) && !defined(ETHERNET_ENABLED) \
|
||||||
#elif defined(DUAL_SERIAL)
|
&& !defined(SERIAL_RX) && !defined(ENABLE_USB_INTERFACE) && !defined(SIM_PLATFORM)
|
||||||
#include <helpers/esp32/DualSerialInterface.h>
|
#define ENABLE_USB_INTERFACE // no other link: the app on USB, as before
|
||||||
DualSerialInterface serial_interface;
|
#endif
|
||||||
#elif defined(BLE_PIN_CODE)
|
#include <helpers/MultiSerialInterface.h>
|
||||||
|
MultiSerialInterface interface_manager;
|
||||||
|
|
||||||
|
// include bluetooth interface
|
||||||
|
#if defined(BLE_PIN_CODE)
|
||||||
|
#ifdef ESP32
|
||||||
#include <helpers/esp32/SerialBLEInterface.h>
|
#include <helpers/esp32/SerialBLEInterface.h>
|
||||||
SerialBLEInterface serial_interface;
|
SerialBLEInterface bluetooth_interface;
|
||||||
#elif defined(SERIAL_RX)
|
#elif defined(NRF52_PLATFORM)
|
||||||
#include <helpers/ArduinoSerialInterface.h>
|
|
||||||
ArduinoSerialInterface serial_interface;
|
|
||||||
HardwareSerial companion_serial(1);
|
|
||||||
#else
|
|
||||||
#include <helpers/ArduinoSerialInterface.h>
|
|
||||||
ArduinoSerialInterface serial_interface;
|
|
||||||
#endif
|
|
||||||
#elif defined(RP2040_PLATFORM)
|
|
||||||
//#ifdef WIFI_SSID
|
|
||||||
// #include <helpers/rp2040/SerialWifiInterface.h>
|
|
||||||
// SerialWifiInterface serial_interface;
|
|
||||||
// #ifndef TCP_PORT
|
|
||||||
// #define TCP_PORT 5000
|
|
||||||
// #endif
|
|
||||||
// #elif defined(BLE_PIN_CODE)
|
|
||||||
// #include <helpers/rp2040/SerialBLEInterface.h>
|
|
||||||
// SerialBLEInterface serial_interface;
|
|
||||||
#if defined(SERIAL_RX)
|
|
||||||
#include <helpers/ArduinoSerialInterface.h>
|
|
||||||
ArduinoSerialInterface serial_interface;
|
|
||||||
HardwareSerial companion_serial(1);
|
|
||||||
#else
|
|
||||||
#include <helpers/ArduinoSerialInterface.h>
|
|
||||||
ArduinoSerialInterface serial_interface;
|
|
||||||
#endif
|
|
||||||
#elif defined(NRF52_PLATFORM)
|
|
||||||
#ifdef DUAL_SERIAL
|
|
||||||
#include <helpers/nrf52/DualSerialInterface.h>
|
|
||||||
DualSerialInterface serial_interface;
|
|
||||||
#elif defined(BLE_PIN_CODE)
|
|
||||||
#include <helpers/nrf52/SerialBLEInterface.h>
|
#include <helpers/nrf52/SerialBLEInterface.h>
|
||||||
SerialBLEInterface serial_interface;
|
SerialBLEInterface bluetooth_interface;
|
||||||
|
#elif defined(RP2040_PLATFORM)
|
||||||
|
#include <helpers/rp2040/SerialBLEInterface.h>
|
||||||
|
SerialBLEInterface bluetooth_interface;
|
||||||
#else
|
#else
|
||||||
#include <helpers/ArduinoSerialInterface.h>
|
#error "SerialBLEInterface is not defined for this platform"
|
||||||
ArduinoSerialInterface serial_interface;
|
|
||||||
#endif
|
#endif
|
||||||
#elif defined(STM32_PLATFORM)
|
#endif
|
||||||
|
|
||||||
|
// include wifi interface
|
||||||
|
#ifdef ENABLE_WIFI_INTERFACE
|
||||||
|
#ifndef WIFI_SSID
|
||||||
|
#define WIFI_SSID ""
|
||||||
|
#endif
|
||||||
|
#ifndef WIFI_PWD
|
||||||
|
#define WIFI_PWD ""
|
||||||
|
#endif
|
||||||
|
#ifndef TCP_PORT
|
||||||
|
#define TCP_PORT 5000
|
||||||
|
#endif
|
||||||
|
#ifndef WIFI_RETRY_INTERVAL
|
||||||
|
#if defined(RP2040_PLATFORM)
|
||||||
|
#define WIFI_RETRY_INTERVAL 30000 // each attempt blocks loop(), so retry less often
|
||||||
|
#else
|
||||||
|
#define WIFI_RETRY_INTERVAL 10000 // millis between reconnect attempts
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifndef WIFI_RETRY_TIMEOUT
|
||||||
|
#define WIFI_RETRY_TIMEOUT 5000 // RP2040: cap on how long one join may block loop()
|
||||||
|
#endif
|
||||||
|
#if defined(ESP32) || defined(RP2040_PLATFORM)
|
||||||
|
#include <helpers/wifi/SerialWifiInterface.h>
|
||||||
|
SerialWifiInterface wifi_interface;
|
||||||
|
#else
|
||||||
|
#error "SerialWifiInterface is not defined for this platform"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// include usb interface
|
||||||
|
#if defined(ENABLE_USB_INTERFACE)
|
||||||
#include <helpers/ArduinoSerialInterface.h>
|
#include <helpers/ArduinoSerialInterface.h>
|
||||||
ArduinoSerialInterface serial_interface;
|
ArduinoSerialInterface usb_serial_interface;
|
||||||
#elif defined(SIM_PLATFORM)
|
#endif
|
||||||
// No real BLE/USB companion-app transport in Phase 1 -- always reports
|
|
||||||
// "not connected". See variants/sim/SimSerialInterface.h.
|
// include ethernet interface
|
||||||
|
#if defined(ETHERNET_ENABLED)
|
||||||
|
#include <helpers/ethernet/EthernetInterface.h>
|
||||||
|
ETHERNET_CLASS ethernet_interface;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// include hardware serial interface
|
||||||
|
#if defined(SERIAL_RX)
|
||||||
|
#include <helpers/ArduinoSerialInterface.h>
|
||||||
|
ArduinoSerialInterface hardware_serial_interface;
|
||||||
|
HardwareSerial companion_serial(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(SIM_PLATFORM)
|
||||||
|
// No real BLE/USB companion-app transport -- always reports "not
|
||||||
|
// connected". See variants/sim/SimSerialInterface.h.
|
||||||
#include <SimSerialInterface.h>
|
#include <SimSerialInterface.h>
|
||||||
SimSerialInterface serial_interface;
|
SimSerialInterface sim_serial_interface;
|
||||||
#else
|
|
||||||
#error "need to define a serial interface"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* GLOBAL OBJECTS */
|
/* GLOBAL OBJECTS */
|
||||||
#ifdef DISPLAY_CLASS
|
#ifdef DISPLAY_CLASS
|
||||||
#include "UITask.h"
|
#include "UITask.h"
|
||||||
UITask ui_task(&board, &serial_interface);
|
UITask ui_task(&board, &interface_manager);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
StdRNG fast_rng;
|
StdRNG fast_rng;
|
||||||
@@ -181,9 +203,13 @@ static void resolveBLEPin(bool has_display) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* WIFI RECONNECT TRACKERS */
|
/* WIFI RECONNECT TRACKERS */
|
||||||
#if defined(ESP32) && defined(WIFI_SSID)
|
#ifdef ENABLE_WIFI_INTERFACE
|
||||||
bool wifi_needs_reconnect = false;
|
bool wifi_needs_reconnect = false;
|
||||||
unsigned long last_wifi_reconnect_attempt = 0;
|
unsigned long last_wifi_reconnect_attempt = 0;
|
||||||
|
char wifi_ssid[33] = WIFI_SSID; // replaced by stored prefs at boot, if set
|
||||||
|
char wifi_pwd[64] = WIFI_PWD;
|
||||||
|
bool wifi_was_connected = false;
|
||||||
|
bool wifi_enabled = false; // set at boot from prefs; false also when the effective SSID is blank
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
@@ -239,14 +265,6 @@ void setup() {
|
|||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
#ifdef DUAL_SERIAL
|
|
||||||
serial_interface.begin(BLE_NAME_PREFIX, the_mesh.getNodePrefs()->node_name, the_mesh.getBLEPin(), Serial);
|
|
||||||
#elif defined(BLE_PIN_CODE)
|
|
||||||
serial_interface.begin(BLE_NAME_PREFIX, the_mesh.getNodePrefs()->node_name, the_mesh.getBLEPin());
|
|
||||||
#else
|
|
||||||
serial_interface.begin(Serial);
|
|
||||||
#endif
|
|
||||||
the_mesh.startInterface(serial_interface);
|
|
||||||
#elif defined(RP2040_PLATFORM)
|
#elif defined(RP2040_PLATFORM)
|
||||||
LittleFS.begin();
|
LittleFS.begin();
|
||||||
store.begin();
|
store.begin();
|
||||||
@@ -259,21 +277,6 @@ void setup() {
|
|||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
//#ifdef WIFI_SSID
|
|
||||||
// WiFi.begin(WIFI_SSID, WIFI_PWD);
|
|
||||||
// serial_interface.begin(TCP_PORT);
|
|
||||||
// #elif defined(BLE_PIN_CODE)
|
|
||||||
// char dev_name[32+16];
|
|
||||||
// sprintf(dev_name, "%s%s", BLE_NAME_PREFIX, the_mesh.getNodeName());
|
|
||||||
// serial_interface.begin(dev_name, the_mesh.getBLEPin());
|
|
||||||
#if defined(SERIAL_RX)
|
|
||||||
companion_serial.setPins(SERIAL_RX, SERIAL_TX);
|
|
||||||
companion_serial.begin(115200);
|
|
||||||
serial_interface.begin(companion_serial);
|
|
||||||
#else
|
|
||||||
serial_interface.begin(Serial);
|
|
||||||
#endif
|
|
||||||
the_mesh.startInterface(serial_interface);
|
|
||||||
#elif defined(ESP32)
|
#elif defined(ESP32)
|
||||||
ESP32_FS.begin(true);
|
ESP32_FS.begin(true);
|
||||||
store.begin();
|
store.begin();
|
||||||
@@ -286,34 +289,6 @@ void setup() {
|
|||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
#ifdef WIFI_SSID
|
|
||||||
board.setInhibitSleep(true); // prevent sleep when WiFi is active
|
|
||||||
WiFi.setAutoReconnect(true);
|
|
||||||
|
|
||||||
WiFi.onEvent([](WiFiEvent_t event, WiFiEventInfo_t info){
|
|
||||||
if (event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) {
|
|
||||||
WIFI_DEBUG_PRINTLN("WiFi disconnected. Flagging for reconnect...");
|
|
||||||
wifi_needs_reconnect = true;
|
|
||||||
} else if (event == ARDUINO_EVENT_WIFI_STA_GOT_IP) {
|
|
||||||
WIFI_DEBUG_PRINTLN("WiFi connected successfully!");
|
|
||||||
wifi_needs_reconnect = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
WiFi.begin(WIFI_SSID, WIFI_PWD);
|
|
||||||
serial_interface.begin(TCP_PORT);
|
|
||||||
#elif defined(DUAL_SERIAL)
|
|
||||||
serial_interface.begin(BLE_NAME_PREFIX, the_mesh.getNodePrefs()->node_name, the_mesh.getBLEPin(), Serial);
|
|
||||||
#elif defined(BLE_PIN_CODE)
|
|
||||||
serial_interface.begin(BLE_NAME_PREFIX, the_mesh.getNodePrefs()->node_name, the_mesh.getBLEPin());
|
|
||||||
#elif defined(SERIAL_RX)
|
|
||||||
companion_serial.setPins(SERIAL_RX, SERIAL_TX);
|
|
||||||
companion_serial.begin(115200);
|
|
||||||
serial_interface.begin(companion_serial);
|
|
||||||
#else
|
|
||||||
serial_interface.begin(Serial);
|
|
||||||
#endif
|
|
||||||
the_mesh.startInterface(serial_interface);
|
|
||||||
#elif defined(SIM_PLATFORM)
|
#elif defined(SIM_PLATFORM)
|
||||||
// sim_fs already exists/mkdir'd itself in its constructor above.
|
// sim_fs already exists/mkdir'd itself in its constructor above.
|
||||||
store.begin();
|
store.begin();
|
||||||
@@ -325,12 +300,90 @@ void setup() {
|
|||||||
false
|
false
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
serial_interface.begin();
|
|
||||||
the_mesh.startInterface(serial_interface);
|
|
||||||
#else
|
#else
|
||||||
#error "need to define filesystem"
|
#error "need to define filesystem"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// add bluetooth interface
|
||||||
|
#if defined(BLE_PIN_CODE)
|
||||||
|
bluetooth_interface.begin(BLE_NAME_PREFIX, the_mesh.getNodePrefs()->node_name, the_mesh.getBLEPin());
|
||||||
|
interface_manager.addInterface(InterfaceType::Bluetooth, &bluetooth_interface);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// add wifi interface
|
||||||
|
#ifdef ENABLE_WIFI_INTERFACE
|
||||||
|
// use wifi ssid and password from prefs if ssid is not empty, otherwise use the build flag defaults
|
||||||
|
if (the_mesh.getNodePrefs()->wifi_ssid[0]) {
|
||||||
|
strcpy(wifi_ssid, the_mesh.getNodePrefs()->wifi_ssid);
|
||||||
|
strcpy(wifi_pwd, the_mesh.getNodePrefs()->wifi_pwd);
|
||||||
|
}
|
||||||
|
// only start wifi if enabled and ssid is not empty
|
||||||
|
wifi_enabled = the_mesh.getNodePrefs()->wifi_enabled;
|
||||||
|
if (wifi_enabled && wifi_ssid[0]) {
|
||||||
|
#if defined(ESP32)
|
||||||
|
board.setInhibitSleep(true); // prevent sleep when WiFi is active
|
||||||
|
WiFi.setAutoReconnect(true);
|
||||||
|
|
||||||
|
WiFi.onEvent([](WiFiEvent_t event, WiFiEventInfo_t info){
|
||||||
|
if (event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) {
|
||||||
|
WIFI_DEBUG_PRINTLN("WiFi disconnected (reason=%s). Flagging for reconnect...",
|
||||||
|
WiFi.disconnectReasonName((wifi_err_reason_t)info.wifi_sta_disconnected.reason));
|
||||||
|
wifi_needs_reconnect = true;
|
||||||
|
} else if (event == ARDUINO_EVENT_WIFI_STA_GOT_IP) {
|
||||||
|
WIFI_DEBUG_PRINTLN("WiFi connected successfully!");
|
||||||
|
wifi_needs_reconnect = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
|
WIFI_DEBUG_PRINTLN("connecting to %s", wifi_ssid);
|
||||||
|
|
||||||
|
#if defined(RP2040_PLATFORM)
|
||||||
|
// the join itself blocks inside the core (CYW43::begin busy-waits for the
|
||||||
|
// association), so every attempt stalls the mesh loop. beginNoBlock() only skips the
|
||||||
|
// extra DHCP wait. Give the first connect a full window, then bound the retries below.
|
||||||
|
WiFi.beginNoBlock(wifi_ssid, wifi_pwd);
|
||||||
|
last_wifi_reconnect_attempt = millis(); // let DHCP finish before the poll can retry
|
||||||
|
#else
|
||||||
|
WiFi.begin(wifi_ssid, wifi_pwd);
|
||||||
|
#endif
|
||||||
|
wifi_interface.begin(TCP_PORT);
|
||||||
|
interface_manager.addInterface(InterfaceType::WiFi, &wifi_interface);
|
||||||
|
} else {
|
||||||
|
WIFI_DEBUG_PRINTLN("wifi disabled");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// add usb interface
|
||||||
|
#if defined(ENABLE_USB_INTERFACE)
|
||||||
|
usb_serial_interface.begin(Serial);
|
||||||
|
interface_manager.addInterface(InterfaceType::USB, &usb_serial_interface);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// add ethernet interface
|
||||||
|
#if defined(ETHERNET_ENABLED)
|
||||||
|
ethernet_interface.begin();
|
||||||
|
interface_manager.addInterface(InterfaceType::Ethernet, ðernet_interface);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// add hardware serial interface
|
||||||
|
#if defined(SERIAL_RX)
|
||||||
|
companion_serial.setPins(SERIAL_RX, SERIAL_TX);
|
||||||
|
companion_serial.begin(115200);
|
||||||
|
hardware_serial_interface.begin(companion_serial);
|
||||||
|
interface_manager.addInterface(InterfaceType::HardwareSerial, &hardware_serial_interface);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(SIM_PLATFORM)
|
||||||
|
sim_serial_interface.begin();
|
||||||
|
interface_manager.addInterface(InterfaceType::USB, &sim_serial_interface);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
the_mesh.startInterface(interface_manager);
|
||||||
|
// Bluetooth as the user left it (Settings, the quick panel): off stays off
|
||||||
|
// after a restart; the other links stay on.
|
||||||
|
if (the_mesh.getNodePrefs()->ble_off) interface_manager.disableBluetooth();
|
||||||
|
|
||||||
store.restoreRTCTime();
|
store.restoreRTCTime();
|
||||||
sensors.begin();
|
sensors.begin();
|
||||||
|
|
||||||
@@ -367,6 +420,7 @@ void loop() {
|
|||||||
NRF_WDT->RR[0] = 0x6E524635UL; // pet watchdog
|
NRF_WDT->RR[0] = 0x6E524635UL; // pet watchdog
|
||||||
#endif
|
#endif
|
||||||
the_mesh.loop();
|
the_mesh.loop();
|
||||||
|
interface_manager.loop();
|
||||||
sensors.loop();
|
sensors.loop();
|
||||||
#ifdef DISPLAY_CLASS
|
#ifdef DISPLAY_CLASS
|
||||||
ui_task.loop();
|
ui_task.loop();
|
||||||
@@ -390,13 +444,34 @@ void loop() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(ESP32) && defined(WIFI_SSID)
|
#ifdef ENABLE_WIFI_INTERFACE
|
||||||
// Safely attempt to reconnect every 10 seconds if flagged
|
if (wifi_enabled) {
|
||||||
if (wifi_needs_reconnect && (millis() - last_wifi_reconnect_attempt > 10000)) {
|
// RP2040 has no WiFi event callbacks, so poll the link state instead
|
||||||
WIFI_DEBUG_PRINTLN("Attempting manual WiFi reconnect...");
|
#if defined(RP2040_PLATFORM)
|
||||||
WiFi.disconnect();
|
wifi_needs_reconnect = (WiFi.status() != WL_CONNECTED);
|
||||||
WiFi.reconnect();
|
if (wifi_was_connected == wifi_needs_reconnect) { // link state changed
|
||||||
last_wifi_reconnect_attempt = millis();
|
wifi_was_connected = !wifi_needs_reconnect;
|
||||||
|
if (wifi_was_connected) {
|
||||||
|
WIFI_DEBUG_PRINTLN("connected, listening on %s:%d", WiFi.localIP().toString().c_str(), TCP_PORT);
|
||||||
|
} else {
|
||||||
|
WIFI_DEBUG_PRINTLN("link lost");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Safely attempt to reconnect if flagged. On RP2040 each attempt blocks the mesh loop
|
||||||
|
// for up to WIFI_RETRY_TIMEOUT, so retry less often and cap how long a join may stall.
|
||||||
|
if (wifi_needs_reconnect && (millis() - last_wifi_reconnect_attempt > WIFI_RETRY_INTERVAL)) {
|
||||||
|
WIFI_DEBUG_PRINTLN("Attempting manual WiFi reconnect to %s (status %d)...", wifi_ssid, WiFi.status());
|
||||||
|
#if defined(RP2040_PLATFORM)
|
||||||
|
WiFi.setTimeout(WIFI_RETRY_TIMEOUT);
|
||||||
|
WiFi.beginNoBlock(wifi_ssid, wifi_pwd); // no reconnect() on this platform
|
||||||
|
#else
|
||||||
|
WiFi.disconnect();
|
||||||
|
WiFi.reconnect();
|
||||||
|
#endif
|
||||||
|
last_wifi_reconnect_attempt = millis();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -314,7 +314,7 @@ bool UITask::quickPanelOpen() const { return qpanel::s_open; }
|
|||||||
void UITask::quickPanelRefresh() {
|
void UITask::quickPanelRefresh() {
|
||||||
using namespace qpanel;
|
using namespace qpanel;
|
||||||
if (!s_panel) return;
|
if (!s_panel) return;
|
||||||
tileSet(T_BT, LV_SYMBOL_BLUETOOTH, hasConnection() ? "Connected" : "Bluetooth", isSerialEnabled());
|
tileSet(T_BT, LV_SYMBOL_BLUETOOTH, hasConnection() ? "Connected" : "Bluetooth", isBluetoothEnabled());
|
||||||
tileSet(T_WIFI, LV_SYMBOL_WIFI, lvport::netRadio() == lvport::NET_UP ? "Online" : "WiFi", lvport::wifiAllowed());
|
tileSet(T_WIFI, LV_SYMBOL_WIFI, lvport::netRadio() == lvport::NET_UP ? "Online" : "WiFi", lvport::wifiAllowed());
|
||||||
int32_t lat, lon;
|
int32_t lat, lon;
|
||||||
const bool gps = _core->gpsEnabled();
|
const bool gps = _core->gpsEnabled();
|
||||||
@@ -357,7 +357,7 @@ void UITask::quickPanelTile(int t, bool hold) {
|
|||||||
}
|
}
|
||||||
// The tile shows what changed: no toast saying it again.
|
// The tile shows what changed: no toast saying it again.
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case T_BT: setBluetooth(!isSerialEnabled()); break;
|
case T_BT: setBluetooth(!isBluetoothEnabled()); break;
|
||||||
case T_WIFI: wifiSetAllowed(!lvport::wifiAllowed()); break;
|
case T_WIFI: wifiSetAllowed(!lvport::wifiAllowed()); break;
|
||||||
case T_GPS: if (_core->gpsAvailable()) setGps(!_core->gpsEnabled()); break;
|
case T_GPS: if (_core->gpsAvailable()) setGps(!_core->gpsEnabled()); break;
|
||||||
case T_SOUND:
|
case T_SOUND:
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ static void onQuickEditKb(lv_event_t* e) { s_ui->quickEditDone(lv_event_get_cod
|
|||||||
static void onQuickList(lv_event_t* e) { (void)e; s_ui->showQuickMsgs(); }
|
static void onQuickList(lv_event_t* e) { (void)e; s_ui->showQuickMsgs(); }
|
||||||
static void onAdvertGo(lv_event_t* e) { s_ui->advertSend((uintptr_t)lv_event_get_user_data(e) != 0); }
|
static void onAdvertGo(lv_event_t* e) { s_ui->advertSend((uintptr_t)lv_event_get_user_data(e) != 0); }
|
||||||
static void bluetoothHint(char* sub, size_t n) {
|
static void bluetoothHint(char* sub, size_t n) {
|
||||||
if (!s_ui->isSerialEnabled()) snprintf(sub, n, "Off");
|
if (!s_ui->isBluetoothEnabled()) snprintf(sub, n, "Off");
|
||||||
else if (s_ui->hasConnection()) snprintf(sub, n, "App connected");
|
else if (s_ui->hasConnection()) snprintf(sub, n, "App connected");
|
||||||
else if (the_mesh.getBLEPin()) snprintf(sub, n, "PIN %06lu", (unsigned long)the_mesh.getBLEPin());
|
else if (the_mesh.getBLEPin()) snprintf(sub, n, "PIN %06lu", (unsigned long)the_mesh.getBLEPin());
|
||||||
else snprintf(sub, n, "Waiting for the app");
|
else snprintf(sub, n, "Waiting for the app");
|
||||||
@@ -202,12 +202,12 @@ static void bluetoothRow(lv_obj_t* body) {
|
|||||||
char sub[48];
|
char sub[48];
|
||||||
qview::bluetoothHint(sub, sizeof(sub));
|
qview::bluetoothHint(sub, sizeof(sub));
|
||||||
lv_obj_t* sw = switchRow(body, LV_SYMBOL_BLUETOOTH " Bluetooth", sub, nullptr);
|
lv_obj_t* sw = switchRow(body, LV_SYMBOL_BLUETOOTH " Bluetooth", sub, nullptr);
|
||||||
if (s_ui->isSerialEnabled()) lv_obj_add_state(sw, LV_STATE_CHECKED);
|
if (s_ui->isBluetoothEnabled()) lv_obj_add_state(sw, LV_STATE_CHECKED);
|
||||||
lv_obj_add_event_cb(sw, qview::onBtSwitch, LV_EVENT_VALUE_CHANGED, NULL);
|
lv_obj_add_event_cb(sw, qview::onBtSwitch, LV_EVENT_VALUE_CHANGED, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UITask::setBluetooth(bool on) {
|
void UITask::setBluetooth(bool on) {
|
||||||
if (on) enableSerial(); else disableSerial();
|
if (on) enableBluetooth(); else disableBluetooth();
|
||||||
if (!on) showToast("Bluetooth off - USB still works", 1500);
|
if (!on) showToast("Bluetooth off - USB still works", 1500);
|
||||||
refreshStatusBar();
|
refreshStatusBar();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -750,7 +750,7 @@ void UITask::refreshStatusBar() {
|
|||||||
struct Icon { const char* sym; uint32_t col; };
|
struct Icon { const char* sym; uint32_t col; };
|
||||||
Icon icons[11];
|
Icon icons[11];
|
||||||
int n = 0;
|
int n = 0;
|
||||||
if (isSerialEnabled()) icons[n++] = { LV_SYMBOL_BLUETOOTH, hasConnection() ? theme::ACCENT : theme::TEXT_MUTED };
|
if (isBluetoothEnabled()) icons[n++] = { LV_SYMBOL_BLUETOOTH, hasConnection() ? theme::ACCENT : theme::TEXT_MUTED };
|
||||||
if (lvport::wifiAllowed()) // WiFi switched on: accent while connected (map tiles, update)
|
if (lvport::wifiAllowed()) // WiFi switched on: accent while connected (map tiles, update)
|
||||||
icons[n++] = { LV_SYMBOL_WIFI, lvport::netRadio() == lvport::NET_UP ? theme::ACCENT : theme::TEXT_MUTED };
|
icons[n++] = { LV_SYMBOL_WIFI, lvport::netRadio() == lvport::NET_UP ? theme::ACCENT : theme::TEXT_MUTED };
|
||||||
int32_t lat, lon;
|
int32_t lat, lon;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <helpers/ui/DisplayDriver.h>
|
#include <helpers/ui/DisplayDriver.h>
|
||||||
#include <helpers/SensorManager.h>
|
#include <helpers/SensorManager.h>
|
||||||
#include <helpers/BaseSerialInterface.h>
|
#include <helpers/MultiSerialInterface.h>
|
||||||
#include <lvgl.h>
|
#include <lvgl.h>
|
||||||
// A big zero-initialised static in PSRAM (ESP32): the internal RAM is what
|
// A big zero-initialised static in PSRAM (ESP32): the internal RAM is what
|
||||||
// WiFi starts and joins on. Not for what DMA or an interrupt touches.
|
// WiFi starts and joins on. Not for what DMA or an interrupt touches.
|
||||||
@@ -53,7 +53,7 @@ struct TextEntry {
|
|||||||
|
|
||||||
class UITask : public UITaskBase, public UiCoreHost {
|
class UITask : public UITaskBase, public UiCoreHost {
|
||||||
public:
|
public:
|
||||||
UITask(mesh::MainBoard* board, BaseSerialInterface* serial) : UITaskBase(board, serial) {}
|
UITask(mesh::MainBoard* board, MultiSerialInterface* serial) : UITaskBase(board, serial) {}
|
||||||
|
|
||||||
void begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* node_prefs);
|
void begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* node_prefs);
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ class HomeScreen : public UIScreen {
|
|||||||
add("All messages", Q_MORE, QA_MORE, 0);
|
add("All messages", Q_MORE, QA_MORE, 0);
|
||||||
n += recentChats(rows + n, quickFit() - 1);
|
n += recentChats(rows + n, quickFit() - 1);
|
||||||
} else if (page == BLUETOOTH) {
|
} else if (page == BLUETOOTH) {
|
||||||
const bool on = _task->isSerialEnabled();
|
const bool on = _task->isBluetoothEnabled();
|
||||||
add("Bluetooth", Q_SWITCH, QA_BT, on ? 1 : 0);
|
add("Bluetooth", Q_SWITCH, QA_BT, on ? 1 : 0);
|
||||||
add("Phone", Q_VALUE, QA_NONE, 0);
|
add("Phone", Q_VALUE, QA_NONE, 0);
|
||||||
char* v = rows[n - 1].value;
|
char* v = rows[n - 1].value;
|
||||||
@@ -440,7 +440,7 @@ class HomeScreen : public UIScreen {
|
|||||||
case QA_BRIGHTNESS:
|
case QA_BRIGHTNESS:
|
||||||
case QA_AUTO_ADVERT: _quick_edit = true; break; // Left/Right change it, Enter / Back keep it
|
case QA_AUTO_ADVERT: _quick_edit = true; break; // Left/Right change it, Enter / Back keep it
|
||||||
case QA_BT:
|
case QA_BT:
|
||||||
if (_task->isSerialEnabled()) _task->disableSerial(); else _task->enableSerial();
|
if (_task->isBluetoothEnabled()) _task->disableBluetooth(); else _task->enableBluetooth();
|
||||||
break;
|
break;
|
||||||
case QA_ADVERT:
|
case QA_ADVERT:
|
||||||
_task->notify(UIEventType::ack);
|
_task->notify(UIEventType::ack);
|
||||||
@@ -609,7 +609,7 @@ class HomeScreen : public UIScreen {
|
|||||||
struct Sicon { bool active; const MiniIcon* icon; };
|
struct Sicon { bool active; const MiniIcon* icon; };
|
||||||
const Sicon icons[] = {
|
const Sicon icons[] = {
|
||||||
{ board.isExternalPowered(), &ICON_CHARGE }, // USB power: next to the battery
|
{ board.isExternalPowered(), &ICON_CHARGE }, // USB power: next to the battery
|
||||||
{ _task->isSerialEnabled() && _task->isBLEConnected(), &ICON_BLUETOOTH },
|
{ _task->isBluetoothEnabled() && _task->isBLEConnected(), &ICON_BLUETOOTH },
|
||||||
{ gps_on, gps_fix ? &ICON_GPS : &ICON_GPS_SEARCH },
|
{ gps_on, gps_fix ? &ICON_GPS : &ICON_GPS_SEARCH },
|
||||||
{ _node_prefs && _node_prefs->alarm_on, &ICON_ALARM },
|
{ _node_prefs && _node_prefs->alarm_on, &ICON_ALARM },
|
||||||
{ mute_on, &ICON_MUTE },
|
{ mute_on, &ICON_MUTE },
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <helpers/ui/DisplayDriver.h>
|
#include <helpers/ui/DisplayDriver.h>
|
||||||
#include <helpers/ui/UIScreen.h>
|
#include <helpers/ui/UIScreen.h>
|
||||||
#include <helpers/SensorManager.h>
|
#include <helpers/SensorManager.h>
|
||||||
#include <helpers/BaseSerialInterface.h>
|
#include <helpers/MultiSerialInterface.h>
|
||||||
#include <helpers/ContactInfo.h>
|
#include <helpers/ContactInfo.h>
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <helpers/sensors/LPPDataHelpers.h>
|
#include <helpers/sensors/LPPDataHelpers.h>
|
||||||
@@ -284,7 +284,7 @@ public:
|
|||||||
void setNodeLockPassword(const char* plain);
|
void setNodeLockPassword(const char* plain);
|
||||||
bool passwordLockEnabled() const;
|
bool passwordLockEnabled() const;
|
||||||
|
|
||||||
UITask(mesh::MainBoard* board, BaseSerialInterface* serial) : UITaskBase(board, serial), _display(NULL), _sensors(NULL), _node_prefs(NULL) {
|
UITask(mesh::MainBoard* board, MultiSerialInterface* serial) : UITaskBase(board, serial), _display(NULL), _sensors(NULL), _node_prefs(NULL) {
|
||||||
next_batt_chck = _next_refresh = 0;
|
next_batt_chck = _next_refresh = 0;
|
||||||
ui_started_at = 0;
|
ui_started_at = 0;
|
||||||
_batt_mv = 0;
|
_batt_mv = 0;
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class UITask : public AbstractUITask {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
UITask(mesh::MainBoard* board, BaseSerialInterface* serial) : AbstractUITask(board, serial), _display(NULL), _sensors(NULL) {
|
UITask(mesh::MainBoard* board, MultiSerialInterface* serial) : AbstractUITask(board, serial), _display(NULL), _sensors(NULL) {
|
||||||
_next_refresh = 0;
|
_next_refresh = 0;
|
||||||
ui_started_at = 0;
|
ui_started_at = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ public:
|
|||||||
} else if (_page == HomePage::BLUETOOTH) {
|
} else if (_page == HomePage::BLUETOOTH) {
|
||||||
display.setColor(DisplayDriver::GREEN);
|
display.setColor(DisplayDriver::GREEN);
|
||||||
display.drawXbm((display.width() - 32) / 2, 8,
|
display.drawXbm((display.width() - 32) / 2, 8,
|
||||||
_task->isSerialEnabled() ? bluetooth_on : bluetooth_off,
|
_task->isBluetoothEnabled() ? bluetooth_on : bluetooth_off,
|
||||||
32, 32);
|
32, 32);
|
||||||
display.setTextSize(1);
|
display.setTextSize(1);
|
||||||
// display.drawTextCentered(display.width() / 2, 40 - 11, "toggle: " PRESS_LABEL);
|
// display.drawTextCentered(display.width() / 2, 40 - 11, "toggle: " PRESS_LABEL);
|
||||||
@@ -387,10 +387,10 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (c == KEY_ENTER && _page == HomePage::BLUETOOTH) {
|
if (c == KEY_ENTER && _page == HomePage::BLUETOOTH) {
|
||||||
if (_task->isSerialEnabled()) { // toggle Bluetooth on/off
|
if (_task->isBluetoothEnabled()) { // toggle Bluetooth on/off
|
||||||
_task->disableSerial();
|
_task->disableBluetooth();
|
||||||
} else {
|
} else {
|
||||||
_task->enableSerial();
|
_task->enableBluetooth();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -674,7 +674,7 @@ void UITask::loop() {
|
|||||||
_cached_batt_mv,
|
_cached_batt_mv,
|
||||||
isBuzzerQuiet(),
|
isBuzzerQuiet(),
|
||||||
getGPSState(),
|
getGPSState(),
|
||||||
isSerialEnabled());
|
isBluetoothEnabled());
|
||||||
|
|
||||||
bool status_dirty = _statusBar.needsRedraw();
|
bool status_dirty = _statusBar.needsRedraw();
|
||||||
bool content_dirty = (millis() >= _next_refresh && curr);
|
bool content_dirty = (millis() >= _next_refresh && curr);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <helpers/ui/DisplayDriver.h>
|
#include <helpers/ui/DisplayDriver.h>
|
||||||
#include <helpers/ui/UIScreen.h>
|
#include <helpers/ui/UIScreen.h>
|
||||||
#include <helpers/SensorManager.h>
|
#include <helpers/SensorManager.h>
|
||||||
#include <helpers/BaseSerialInterface.h>
|
#include <helpers/MultiSerialInterface.h>
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <helpers/sensors/LPPDataHelpers.h>
|
#include <helpers/sensors/LPPDataHelpers.h>
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ class UITask : public AbstractUITask {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
UITask(mesh::MainBoard* board, BaseSerialInterface* serial) : AbstractUITask(board, serial), _display(NULL), _sensors(NULL) {
|
UITask(mesh::MainBoard* board, MultiSerialInterface* serial) : AbstractUITask(board, serial), _display(NULL), _sensors(NULL) {
|
||||||
next_batt_chck = _next_refresh = 0;
|
next_batt_chck = _next_refresh = 0;
|
||||||
_cached_batt_mv = 0;
|
_cached_batt_mv = 0;
|
||||||
ui_started_at = 0;
|
ui_started_at = 0;
|
||||||
|
|||||||
@@ -22,6 +22,17 @@ bool ArduinoSerialInterface::isConnected() const {
|
|||||||
return true; // no way of knowing, so assume yes
|
return true; // no way of knowing, so assume yes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ArduinoSerialInterface::isClientConnected() const {
|
||||||
|
#if defined(NRF52_PLATFORM) || (defined(ARDUINO_USB_MODE) && ARDUINO_USB_MODE == 0 && defined(ARDUINO_USB_CDC_ON_BOOT) && ARDUINO_USB_CDC_ON_BOOT == 1)
|
||||||
|
// (bool)Serial: the host has the CDC port open (DTR) -- a serial monitor
|
||||||
|
// counts too, charging alone doesn't.
|
||||||
|
return _serial == (Stream*)&Serial && (bool)Serial;
|
||||||
|
#else
|
||||||
|
// A UART bridge: (bool)Serial is just "begun", always true.
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool ArduinoSerialInterface::isWriteBusy() const {
|
bool ArduinoSerialInterface::isWriteBusy() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ public:
|
|||||||
bool isEnabled() const override { return _isEnabled; }
|
bool isEnabled() const override { return _isEnabled; }
|
||||||
|
|
||||||
bool isConnected() const override;
|
bool isConnected() const override;
|
||||||
|
// A host holding the port open: native USB tells (DTR), a UART bridge
|
||||||
|
// can't, so it never counts as an app being there.
|
||||||
|
bool isClientConnected() const override;
|
||||||
|
|
||||||
bool isWriteBusy() const override;
|
bool isWriteBusy() const override;
|
||||||
size_t writeFrame(const uint8_t src[], size_t len) override;
|
size_t writeFrame(const uint8_t src[], size_t len) override;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ public:
|
|||||||
virtual bool isEnabled() const = 0;
|
virtual bool isEnabled() const = 0;
|
||||||
|
|
||||||
virtual bool isConnected() const = 0;
|
virtual bool isConnected() const = 0;
|
||||||
|
virtual void loop() {};
|
||||||
// Returns true when a BLE companion app is connected. Default delegates to
|
// Returns true when a BLE companion app is connected. Default delegates to
|
||||||
// isConnected(); override in dual-interface wrappers that always report
|
// isConnected(); override in dual-interface wrappers that always report
|
||||||
// isConnected()=true but still need to distinguish BLE from USB state.
|
// isConnected()=true but still need to distinguish BLE from USB state.
|
||||||
|
|||||||
@@ -131,6 +131,38 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A companion app on Bluetooth (the pairing PIN, the BT indicator).
|
||||||
|
bool isBLEConnected() const override {
|
||||||
|
for(auto iface : _interfaces){
|
||||||
|
if(iface.instance && iface.type == InterfaceType::Bluetooth && iface.instance->isEnabled() && iface.instance->isConnected()){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A companion app on any of them (each says how it knows).
|
||||||
|
bool isClientConnected() const override {
|
||||||
|
if(!_enabled){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for(auto iface : _interfaces){
|
||||||
|
if(iface.instance && iface.instance->isEnabled() && iface.instance->isClientConnected()){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasPendingFrames() const override {
|
||||||
|
for(auto iface : _interfaces){
|
||||||
|
if(iface.instance && iface.instance->isEnabled() && iface.instance->hasPendingFrames()){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// loop all interfaces
|
// loop all interfaces
|
||||||
void loop() override {
|
void loop() override {
|
||||||
for(auto iface : _interfaces){
|
for(auto iface : _interfaces){
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../BaseSerialInterface.h"
|
|
||||||
#include "../ArduinoSerialInterface.h"
|
|
||||||
#include "SerialBLEInterface.h"
|
|
||||||
|
|
||||||
// ESP32 counterpart of helpers/nrf52/DualSerialInterface.h: wraps BLE + USB
|
|
||||||
// serial so one build serves both companion transports. BLE takes priority when
|
|
||||||
// connected, USB is always ready as a fallback.
|
|
||||||
// enable()/disable() control BLE only — USB is always on.
|
|
||||||
// BLE state machine is only pumped when BLE is enabled; USB is not read while
|
|
||||||
// BLE is connected.
|
|
||||||
class DualSerialInterface : public BaseSerialInterface {
|
|
||||||
SerialBLEInterface _ble;
|
|
||||||
ArduinoSerialInterface _usb;
|
|
||||||
uint8_t _ble_buf[MAX_FRAME_SIZE];
|
|
||||||
uint8_t _usb_buf[MAX_FRAME_SIZE];
|
|
||||||
bool _ble_enabled;
|
|
||||||
bool _ble_was_connected;
|
|
||||||
|
|
||||||
public:
|
|
||||||
DualSerialInterface() : _ble_enabled(false), _ble_was_connected(false) {}
|
|
||||||
|
|
||||||
void begin(const char* ble_prefix, char* node_name, uint32_t pin_code, Stream& usb_stream) {
|
|
||||||
_ble.begin(ble_prefix, node_name, pin_code);
|
|
||||||
_usb.begin(usb_stream);
|
|
||||||
_usb.enable(); // USB is always on
|
|
||||||
}
|
|
||||||
|
|
||||||
void enable() override { _ble.enable(); _ble_enabled = true; }
|
|
||||||
void disable() override { _ble.disable(); _ble_enabled = false; }
|
|
||||||
bool isEnabled() const override { return _ble_enabled; }
|
|
||||||
|
|
||||||
// Always true — USB is always available as fallback, so the mesh can send.
|
|
||||||
bool isConnected() const override { return true; }
|
|
||||||
// True only when a BLE companion app is paired and connected.
|
|
||||||
bool isBLEConnected() const override { return _ble_enabled && _ble.isConnected(); }
|
|
||||||
#if defined(ARDUINO_USB_MODE) && ARDUINO_USB_MODE == 0 && defined(ARDUINO_USB_CDC_ON_BOOT) && ARDUINO_USB_CDC_ON_BOOT == 1
|
|
||||||
// Native USB CDC (e.g. Heltec V4): Serial's bool operator reflects whether
|
|
||||||
// the host actually has the port open, same DTR-style signal the nRF52
|
|
||||||
// version reads. Counts as a connected client same as BLE, matching that
|
|
||||||
// version's behaviour.
|
|
||||||
bool isClientConnected() const override { return isBLEConnected() || (bool)Serial; }
|
|
||||||
#else
|
|
||||||
// BLE only, unlike the nRF52 version, which also counts a USB host holding the
|
|
||||||
// CDC port open. These boards reach USB through a UART bridge rather than
|
|
||||||
// native CDC, so there is no DTR to read: (bool)Serial is a plain "is the
|
|
||||||
// peripheral initialised", i.e. always true once begin() has run, and
|
|
||||||
// ArduinoSerialInterface::isConnected() likewise hardcodes true. Reporting
|
|
||||||
// that as a connected client would permanently convince the UI an app is
|
|
||||||
// watching the device and stop it waking the display for new messages.
|
|
||||||
bool isClientConnected() const override { return isBLEConnected(); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// USB can't tell without reading it.
|
|
||||||
bool hasPendingFrames() const override {
|
|
||||||
return (_ble_enabled && _ble.isConnected()) ? _ble.hasPendingFrames() : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isWriteBusy() const override {
|
|
||||||
return (_ble_enabled && _ble.isConnected()) ? _ble.isWriteBusy() : _usb.isWriteBusy();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t writeFrame(const uint8_t src[], size_t len) override {
|
|
||||||
return (_ble_enabled && _ble.isConnected()) ? _ble.writeFrame(src, len) : _usb.writeFrame(src, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t checkRecvFrame(uint8_t dest[]) override {
|
|
||||||
if (_ble_enabled) {
|
|
||||||
size_t ble_len = _ble.checkRecvFrame(_ble_buf);
|
|
||||||
bool ble_now = _ble.isConnected();
|
|
||||||
|
|
||||||
if (ble_now) {
|
|
||||||
_ble_was_connected = true;
|
|
||||||
if (ble_len > 0) { memcpy(dest, _ble_buf, ble_len); return ble_len; }
|
|
||||||
return 0; // BLE active — don't read USB to keep its state machine clean
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_ble_was_connected) {
|
|
||||||
// BLE just disconnected — reset USB state machine so stale partial frames don't block it
|
|
||||||
_ble_was_connected = false;
|
|
||||||
_usb.enable();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t usb_len = _usb.checkRecvFrame(_usb_buf);
|
|
||||||
if (usb_len > 0) { memcpy(dest, _usb_buf, usb_len); return usb_len; }
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../BaseSerialInterface.h"
|
|
||||||
#include "../ArduinoSerialInterface.h"
|
|
||||||
#include "SerialBLEInterface.h"
|
|
||||||
|
|
||||||
// Wraps BLE + USB serial interfaces: BLE takes priority when connected,
|
|
||||||
// USB is always ready as a fallback.
|
|
||||||
// enable()/disable() control BLE only — USB is always on.
|
|
||||||
// BLE state machine is only pumped when BLE is enabled; USB is not read while BLE is connected.
|
|
||||||
class DualSerialInterface : public BaseSerialInterface {
|
|
||||||
SerialBLEInterface _ble;
|
|
||||||
ArduinoSerialInterface _usb;
|
|
||||||
uint8_t _ble_buf[MAX_FRAME_SIZE];
|
|
||||||
uint8_t _usb_buf[MAX_FRAME_SIZE];
|
|
||||||
bool _ble_enabled;
|
|
||||||
bool _ble_was_connected;
|
|
||||||
|
|
||||||
public:
|
|
||||||
DualSerialInterface() : _ble_enabled(false), _ble_was_connected(false) {}
|
|
||||||
|
|
||||||
void begin(const char* ble_prefix, char* node_name, uint32_t pin_code, Stream& usb_stream) {
|
|
||||||
_ble.begin(ble_prefix, node_name, pin_code);
|
|
||||||
_usb.begin(usb_stream);
|
|
||||||
_usb.enable(); // USB is always on
|
|
||||||
}
|
|
||||||
|
|
||||||
void enable() override { _ble.enable(); _ble_enabled = true; }
|
|
||||||
void disable() override { _ble.disable(); _ble_enabled = false; }
|
|
||||||
bool isEnabled() const override { return _ble_enabled; }
|
|
||||||
|
|
||||||
// Always true — USB is always available as fallback, so the mesh can send.
|
|
||||||
bool isConnected() const override { return true; }
|
|
||||||
// True only when a BLE companion app is paired and connected.
|
|
||||||
bool isBLEConnected() const override { return _ble_enabled && _ble.isConnected(); }
|
|
||||||
// A companion app is actually connected if BLE is bonded OR a host holds the
|
|
||||||
// USB-CDC port open. (bool)Serial == tud_cdc_n_connected() (DTR asserted) — a
|
|
||||||
// serial monitor counts too, but charging-only (no host) does not.
|
|
||||||
bool isClientConnected() const override { return isBLEConnected() || (bool)Serial; }
|
|
||||||
|
|
||||||
bool isWriteBusy() const override {
|
|
||||||
return (_ble_enabled && _ble.isConnected()) ? _ble.isWriteBusy() : _usb.isWriteBusy();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t writeFrame(const uint8_t src[], size_t len) override {
|
|
||||||
return (_ble_enabled && _ble.isConnected()) ? _ble.writeFrame(src, len) : _usb.writeFrame(src, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t checkRecvFrame(uint8_t dest[]) override {
|
|
||||||
if (_ble_enabled) {
|
|
||||||
size_t ble_len = _ble.checkRecvFrame(_ble_buf);
|
|
||||||
bool ble_now = _ble.isConnected();
|
|
||||||
|
|
||||||
if (ble_now) {
|
|
||||||
_ble_was_connected = true;
|
|
||||||
if (ble_len > 0) { memcpy(dest, _ble_buf, ble_len); return ble_len; }
|
|
||||||
return 0; // BLE active — don't read USB to keep its state machine clean
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_ble_was_connected) {
|
|
||||||
// BLE just disconnected — reset USB state machine so stale partial frames don't block it
|
|
||||||
_ble_was_connected = false;
|
|
||||||
_usb.enable();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t usb_len = _usb.checkRecvFrame(_usb_buf);
|
|
||||||
if (usb_len > 0) { memcpy(dest, _usb_buf, usb_len); return usb_len; }
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -85,6 +85,7 @@ SRCS=(
|
|||||||
src/helpers/ClientACL.cpp
|
src/helpers/ClientACL.cpp
|
||||||
src/helpers/CommonCLI.cpp
|
src/helpers/CommonCLI.cpp
|
||||||
src/helpers/ConfigSerializer.cpp
|
src/helpers/ConfigSerializer.cpp
|
||||||
|
src/helpers/DynamicConfigSerializer.cpp
|
||||||
src/helpers/DeviceDiag.cpp
|
src/helpers/DeviceDiag.cpp
|
||||||
src/helpers/IdentityStore.cpp
|
src/helpers/IdentityStore.cpp
|
||||||
src/helpers/RegionMap.cpp
|
src/helpers/RegionMap.cpp
|
||||||
|
|||||||
Reference in New Issue
Block a user