Expand and harden full companion profiles

This commit is contained in:
mikecarper committed 2026-08-24 01:57:38 -07:00
1 parent f2d4ffbb7e
commit dc92ee61ef
44 files changed
+1522 -226

No files matched your search

+67 -11
View File
@@ -1376,6 +1376,9 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
command_radio_cr = 0;
command_radio_repeat = 0;
command_radio_apply_deadline = 0;
#if MESH_USB_LOGGING_AVAILABLE
_usb_logging_reboot_at = 0;
#endif
#if defined(COMPANION_RADIO_FULL)
_temp_radio_set_at = 0;
_temp_radio_revert_at = 0;
@@ -1437,7 +1440,13 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
_prefs.powersaving_enabled = 1;
_prefs.powersaving_policy_version = 0;
_prefs.wifi_enabled = 1;
#if defined(COMPANION_RADIO_FULL) && defined(MESH_DUAL_CDC_LOGGING)
// Keep the primary CDC stream exclusively framed unless the owner opts in
// to the separate plaintext logging interface and reboots.
_prefs.usb_logging_enabled = 0;
#else
_prefs.usb_logging_enabled = 1;
#endif
recalcRxPowerSavingFromLevel(_prefs.rx_ps_level, _prefs.sf, _prefs.bw,
_prefs.rx_ps_preamble, &_prefs.rx_ps_rx_us,
&_prefs.rx_ps_sleep_us);
@@ -1457,6 +1466,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
void MyMesh::begin(bool has_display, bool radio_available) {
_radio_available = radio_available;
setRadioAvailable(radio_available);
initializeContactStorage();
initializeOfflineQueue();
BaseChatMesh::begin();
@@ -1545,7 +1555,11 @@ void MyMesh::begin(bool has_display, bool radio_available) {
_store->savePrefs(_prefs, sensors.node_lat, sensors.node_lon);
}
#if MESH_USB_LOGGING_AVAILABLE
mesh::setUsbLoggingEnabled(_prefs.usb_logging_enabled != 0);
const bool usb_logging_enabled = _prefs.usb_logging_enabled != 0;
mesh::setUsbLoggingEnabled(usb_logging_enabled);
if (!mesh::saveUsbLoggingBootPreference(usb_logging_enabled)) {
MESH_DEBUG_PRINTLN("Unable to save next-boot USB logging interface state");
}
#endif
#ifdef BLE_PIN_CODE // 123456 by default
@@ -4925,8 +4939,11 @@ void MyMesh::handleTerminalCommand(char* command) {
_prefs.powersaving_enabled ? "on" : "off");
#if MESH_USB_LOGGING_AVAILABLE
} else if (strcmp(command, "get usb.logging") == 0) {
terminalOutput().printf(" usb.logging %s\r\n",
mesh::isUsbLoggingEnabled() ? "on" : "off");
terminalOutput().printf(
" usb.logging %s%s\r\n",
mesh::isUsbLoggingEnabled() ? "on" : "off",
mesh::usbLoggingInterfaceRestartRequired()
? " (reboot required to change USB interfaces)" : "");
#endif
} else if (strncmp(command, "powersaving ", 12) == 0) {
char reply[160];
@@ -4978,18 +4995,49 @@ void MyMesh::handleTerminalCommand(char* command) {
|| config[11] == '\t')) {
const char* value = config + 11;
while (*value == ' ' || *value == '\t') value++;
if (strcmp(value, "on") != 0 && strcmp(value, "off") != 0) {
terminalOutput().print(" ERROR: use set usb.logging <on|off>\r\n");
bool enabled = false;
bool reboot_if_needed = false;
bool valid = true;
if (strcmp(value, "on") == 0) {
enabled = true;
} else if (strcmp(value, "off") == 0) {
enabled = false;
} else if (strcmp(value, "on reboot") == 0) {
enabled = true;
reboot_if_needed = true;
} else if (strcmp(value, "off reboot") == 0) {
enabled = false;
reboot_if_needed = true;
} else {
valid = false;
}
if (!valid) {
terminalOutput().print(
" ERROR: use set usb.logging <on|off> [reboot]\r\n");
} else {
const bool enabled = strcmp(value, "on") == 0;
_prefs.usb_logging_enabled = enabled ? 1 : 0;
mesh::setUsbLoggingEnabled(enabled);
if (savePrefs()) {
terminalOutput().printf(" OK - USB logging %s (saved)\r\n",
enabled ? "on" : "off");
} else {
if (!savePrefs()) {
terminalOutput().print(
" ERROR: USB logging changed for this boot but save failed\r\n");
} else if (!mesh::saveUsbLoggingBootPreference(enabled)) {
terminalOutput().print(
" ERROR: setting saved, but next-boot USB interface state could not be saved\r\n");
} else if (mesh::usbLoggingInterfaceRestartRequired()) {
if (reboot_if_needed) {
terminalOutput().printf(
" OK - USB logging %s (saved); rebooting to change USB interfaces\r\n",
enabled ? "on" : "off");
_usb_logging_reboot_at = futureMillis(1000);
} else {
terminalOutput().printf(
" OK - USB logging %s (saved); reboot required to change USB interfaces\r\n",
enabled ? "on" : "off");
}
} else {
terminalOutput().printf(" OK - USB logging %s (saved)\r\n",
enabled ? "on" : "off");
}
}
} else
@@ -5090,7 +5138,7 @@ void MyMesh::handleTerminalCommand(char* command) {
terminalOutput().print(" powersaving [on|off]\r\n");
#if MESH_USB_LOGGING_AVAILABLE
terminalOutput().print(" get usb.logging\r\n");
terminalOutput().print(" set usb.logging <on|off>\r\n");
terminalOutput().print(" set usb.logging <on|off> [reboot]\r\n");
#endif
#if defined(ESP32) && defined(WIFI_SSID)
terminalOutput().print(" get wifi.powersave\r\n");
@@ -5361,6 +5409,14 @@ void MyMesh::checkSerialInterface() {
}
void MyMesh::loop() {
#if MESH_USB_LOGGING_AVAILABLE
if (_usb_logging_reboot_at != 0
&& millisHasNowPassed(_usb_logging_reboot_at)) {
_usb_logging_reboot_at = 0;
board.reboot();
return;
}
#endif
#if defined(COMPANION_RADIO_FULL)
serviceTempRadio();
#endif
+3
View File
@@ -415,6 +415,9 @@ private:
uint8_t command_radio_cr;
uint8_t command_radio_repeat;
unsigned long command_radio_apply_deadline;
#if MESH_USB_LOGGING_AVAILABLE
unsigned long _usb_logging_reboot_at;
#endif
#if defined(COMPANION_RADIO_FULL)
unsigned long _temp_radio_set_at;
unsigned long _temp_radio_revert_at;
+69 -24
View File
@@ -12,6 +12,13 @@
#else
#define COMPANION_IDF_PM_AVAILABLE 0
#endif
#if defined(BLE_PIN_CODE) && !CONFIG_IDF_TARGET_ESP32C6 \
&& (defined(CONFIG_BT_CTRL_MODEM_SLEEP) \
|| defined(CONFIG_BTDM_CTRL_MODEM_SLEEP))
#define COMPANION_BT_MODEM_SLEEP_AVAILABLE 1
#else
#define COMPANION_BT_MODEM_SLEEP_AVAILABLE 0
#endif
#if defined(COMPANION_RADIO_FULL)
#include <esp_heap_caps.h>
#endif
@@ -180,6 +187,22 @@ static uint32_t companionNominalCpuMhz() {
#endif
}
#if COMPANION_BT_MODEM_SLEEP_AVAILABLE
static void applyCompanionBluetoothSleep(bool enabled,
bool allow_uninitialized) {
esp_err_t result = enabled ? esp_bt_sleep_enable()
: esp_bt_sleep_disable();
if (result == ESP_OK
|| (allow_uninitialized && result == ESP_ERR_INVALID_STATE)) {
return;
}
mesh::usbLoggingPort().printf("Bluetooth sleep %s failed: %s\r\n",
enabled ? "enable" : "disable",
esp_err_to_name(result));
}
#endif
static bool applyCompanionPowerSaving(bool enabled) {
const uint32_t nominal_mhz = companionNominalCpuMhz();
const uint32_t max_mhz = enabled && nominal_mhz > 80 ? 80 : nominal_mhz;
@@ -224,14 +247,13 @@ static bool applyCompanionPowerSaving(bool enabled) {
}
#endif
#if defined(BLE_PIN_CODE) && !CONFIG_IDF_TARGET_ESP32C6
esp_err_t bt_result = enabled ? esp_bt_sleep_enable()
: esp_bt_sleep_disable();
if (bt_result != ESP_OK) {
mesh::usbLoggingPort().printf("Bluetooth sleep %s failed: %s\r\n",
enabled ? "enable" : "disable",
esp_err_to_name(bt_result));
}
#if COMPANION_BT_MODEM_SLEEP_AVAILABLE
// Power saving is applied before the wireless interfaces are constructed.
// An uninitialized controller is expected here; apply the saved setting
// again immediately after BLEDevice::init() below. Some prebuilt ESP-IDF
// targets omit Bluetooth modem sleep entirely; the compile-time guard avoids
// calling an API which can only return ESP_ERR_NOT_SUPPORTED in those builds.
applyCompanionBluetoothSleep(enabled, true);
#endif
#if COMPANION_IDF_PM_AVAILABLE
@@ -945,32 +967,47 @@ void halt() {
#if defined(BLE_PIN_CODE)
static bool companion_bluetooth_initialized = false;
#if defined(ESP32) && defined(COMPANION_RADIO_FULL) && defined(WIFI_SSID)
static uint32_t companion_bluetooth_start_at = 0;
#endif
static constexpr uint32_t COMPANION_BLUETOOTH_RETRY_MS = 5000UL;
static void scheduleCompanionBluetoothRetry() {
companion_bluetooth_start_at = millis() + COMPANION_BLUETOOTH_RETRY_MS;
if (companion_bluetooth_start_at == 0) companion_bluetooth_start_at = 1;
}
static void startCompanionBluetooth() {
if (companion_bluetooth_initialized) return;
companion_bluetooth_start_at = 0;
mesh::usbLoggingPort().println("Companion: starting Bluetooth");
bluetooth_interface.begin(BLE_NAME_PREFIX, the_mesh.getNodePrefs()->node_name,
the_mesh.getBLEPin());
if (!interface_manager.addInterface(InterfaceType::Bluetooth,
&bluetooth_interface)) {
mesh::usbLoggingPort().println(
"Companion: no interface slot available for Bluetooth");
"Companion: no interface slot available for Bluetooth; retrying");
scheduleCompanionBluetoothRetry();
return;
}
if (!bluetooth_interface.begin(BLE_NAME_PREFIX,
the_mesh.getNodePrefs()->node_name,
the_mesh.getBLEPin())) {
interface_manager.removeInterface(&bluetooth_interface);
mesh::usbLoggingPort().println(
"Companion: Bluetooth initialization failed; retrying in 5 seconds");
scheduleCompanionBluetoothRetry();
return;
}
#if defined(ESP32_PLATFORM) && COMPANION_BT_MODEM_SLEEP_AVAILABLE
applyCompanionBluetoothSleep(
the_mesh.getNodePrefs()->powersaving_enabled != 0, false);
#endif
companion_bluetooth_initialized = true;
if (interface_manager.isEnabled()) bluetooth_interface.enable();
}
static void serviceDeferredCompanionBluetooth() {
if (companion_bluetooth_initialized) return;
#if defined(ESP32) && defined(COMPANION_RADIO_FULL) && defined(WIFI_SSID)
if (companion_bluetooth_start_at == 0
|| (int32_t)(millis() - companion_bluetooth_start_at) < 0) return;
#endif
startCompanionBluetooth();
}
#endif
@@ -1109,6 +1146,11 @@ void setup() {
#error "need to define filesystem"
#endif
// nRF52 cannot decide whether to add its optional logging CDC interface
// until the saved Companion preferences above are available. ESP32 already
// fixed its descriptor from the early NVS mirror, so this is harmless there.
mesh::beginUsbLoggingPort();
// Load WiFi state before bringing up either wireless stack.
#ifdef WIFI_SSID
loadCompanionWiFiCredentials();
@@ -1118,6 +1160,14 @@ void setup() {
logFullCompanionMemory("before interfaces");
#endif
// NimBLE must reserve its internal controller/host memory before WiFi starts
// its AP and WebConfig services. Starting WiFi first can leave plenty of total
// heap but no internal block large enough for nimble_port_init().
#if defined(BLE_PIN_CODE) && defined(ESP32) \
&& defined(COMPANION_RADIO_FULL) && defined(WIFI_SSID)
startCompanionBluetooth();
#endif
// add wifi interface
#ifdef WIFI_SSID
WiFi.onEvent([](WiFiEvent_t event, WiFiEventInfo_t info){
@@ -1147,16 +1197,11 @@ void setup() {
logFullCompanionMemory("after WiFi start");
#endif
// The Full ESP32 profile starts WiFi/WebConfig first, gives its AP/server two
// seconds to settle and reserve heap, then starts BLE from loop(). Other BLE
// companions keep their existing immediate startup.
// Full ESP32 WiFi+BLE companions started BLE above so its controller memory
// could not be fragmented by WiFi. Other BLE companions start here.
#if defined(BLE_PIN_CODE)
#if defined(ESP32) && defined(COMPANION_RADIO_FULL) && defined(WIFI_SSID)
companion_bluetooth_start_at = millis() + 2000UL;
if (companion_bluetooth_start_at == 0) companion_bluetooth_start_at = 1;
mesh::usbLoggingPort().println(
"Companion: Bluetooth starts in 2 seconds");
#else
#if !(defined(ESP32) && defined(COMPANION_RADIO_FULL) \
&& defined(WIFI_SSID))
startCompanionBluetooth();
#endif
#endif