feat: consolidate full companion runtime profiles

This commit is contained in:
mikecarper committed 2026-08-28 08:47:26 -07:00
1 parent d17c250137
commit c6476b8ba8
42 files changed
+731 -561

No files matched your search

+2 -1
View File
@@ -6,6 +6,7 @@
#include "TxtDataHelpers.h"
#include "AdvertDataHelpers.h"
#include "AlertReporter.h" // for alertReporterBannedChannelMatch()
#include "sensors/EnvironmentI2CConfig.h"
#if defined(NRF52_PLATFORM)
#include "AtomicFileWriter.h"
#include "ota/OtaFlashLayout_nrf52.h"
@@ -2785,7 +2786,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
}
} else if (memcmp(command, "sensor", 6) == 0) {
// I2C
#if defined(ENV_PIN_SDA) && defined(ENV_PIN_SCL)
#if ENV_HAS_SECONDARY_I2C
sprintf(reply, "I2C Wire1: SDA=%s,SCL=%s\r\n", STR(ENV_PIN_SDA), STR(ENV_PIN_SCL));
#elif defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
sprintf(reply, "I2C Wire: SDA=%s, SCL=%s\r\n", STR(PIN_BOARD_SDA), STR(PIN_BOARD_SCL));
+6 -113
View File
@@ -3,32 +3,18 @@
#if defined(ARDUINO)
#include <Arduino.h>
#include <atomic>
#include <new>
#if defined(MESH_DUAL_CDC_LOGGING)
#if !defined(COMPANION_FEATURE_DEDICATED_USB_LOGGING) || \
!COMPANION_FEATURE_DEDICATED_USB_LOGGING
#error "MESH_DUAL_CDC_LOGGING requires its dedicated Companion capability"
#endif
#if defined(NRF52_PLATFORM)
#define MESH_NRF52_DUAL_CDC_LOGGING 1
#include <Adafruit_TinyUSB.h>
#if !defined(CFG_TUD_CDC) || CFG_TUD_CDC < 2
#error "MESH_DUAL_CDC_LOGGING requires CFG_TUD_CDC >= 2"
#endif
#elif defined(ESP32_PLATFORM) && defined(SOC_USB_OTG_SUPPORTED) && \
SOC_USB_OTG_SUPPORTED && !ARDUINO_USB_MODE
#define MESH_ESP32_DUAL_CDC_LOGGING 1
#include <USB.h>
#include <USBCDC.h>
#include <nvs.h>
#include <nvs_flash.h>
#if !defined(CONFIG_TINYUSB_CDC_MAX_PORTS) || \
CONFIG_TINYUSB_CDC_MAX_PORTS < 2
#error "MESH_DUAL_CDC_LOGGING requires two ESP32 TinyUSB CDC ports"
#endif
#else
#error "MESH_DUAL_CDC_LOGGING requires nRF52 or ESP32 native TinyUSB"
#if !defined(NRF52_PLATFORM)
#error "MESH_DUAL_CDC_LOGGING is supported only by nRF52 Full Companion"
#endif
#include <Adafruit_TinyUSB.h>
#if !defined(CFG_TUD_CDC) || CFG_TUD_CDC < 2
#error "MESH_DUAL_CDC_LOGGING requires CFG_TUD_CDC >= 2"
#endif
#endif
@@ -60,68 +46,7 @@ static NullUsbLoggingStream null_usb_logging_stream;
static bool dedicated_usb_logging_port_configured = false;
static bool dedicated_usb_logging_port_started = false;
static bool dedicated_usb_logging_port_connected = false;
#if defined(MESH_NRF52_DUAL_CDC_LOGGING)
static Adafruit_USBD_CDC dedicated_usb_logging_port;
#elif defined(MESH_ESP32_DUAL_CDC_LOGGING)
static constexpr char USB_LOGGING_NVS_NAMESPACE[] = "mesh_usb";
static constexpr char USB_LOGGING_NVS_KEY[] = "log_port";
alignas(USBCDC) static uint8_t dedicated_usb_logging_port_storage[
sizeof(USBCDC)];
static USBCDC* dedicated_usb_logging_port = nullptr;
static bool readEsp32UsbLoggingBootPreference() {
// Missing or unreadable state must stay protocol-safe: Full Companion then
// exposes only its primary framed CDC interface. The normal preference load
// below mirrors an explicitly enabled setting for the following reboot.
if (nvs_flash_init() != ESP_OK) return false;
nvs_handle_t handle;
if (nvs_open(USB_LOGGING_NVS_NAMESPACE, NVS_READONLY, &handle) != ESP_OK) {
return false;
}
uint8_t value = 0;
const esp_err_t result = nvs_get_u8(handle, USB_LOGGING_NVS_KEY, &value);
nvs_close(handle);
return result == ESP_OK && value != 0;
}
static bool writeEsp32UsbLoggingBootPreference(bool enabled) {
if (nvs_flash_init() != ESP_OK) return false;
nvs_handle_t handle;
if (nvs_open(USB_LOGGING_NVS_NAMESPACE, NVS_READWRITE, &handle) != ESP_OK) {
return false;
}
uint8_t current = 0;
esp_err_t result = nvs_get_u8(handle, USB_LOGGING_NVS_KEY, &current);
if (result == ESP_OK && current == (enabled ? 1 : 0)) {
nvs_close(handle);
return true;
}
result = nvs_set_u8(handle, USB_LOGGING_NVS_KEY, enabled ? 1 : 0);
if (result == ESP_OK) result = nvs_commit(handle);
nvs_close(handle);
return result == ESP_OK;
}
class Esp32UsbLoggingBootstrap {
public:
Esp32UsbLoggingBootstrap() {
const bool enabled = readEsp32UsbLoggingBootPreference();
usb_logging_enabled.store(enabled, std::memory_order_relaxed);
usb_logging_preference_known.store(true, std::memory_order_relaxed);
if (!enabled) return;
dedicated_usb_logging_port = new (dedicated_usb_logging_port_storage)
USBCDC(1);
dedicated_usb_logging_port_configured = true;
}
};
static Esp32UsbLoggingBootstrap esp32_usb_logging_bootstrap;
#endif
#endif
bool isUsbLoggingEnabled() {
@@ -134,12 +59,8 @@ void setUsbLoggingEnabled(bool enabled) {
}
bool saveUsbLoggingBootPreference(bool enabled) {
#if defined(MESH_ESP32_DUAL_CDC_LOGGING)
return writeEsp32UsbLoggingBootPreference(enabled);
#else
(void)enabled;
return true;
#endif
}
void beginUsbLoggingPort() {
@@ -150,27 +71,13 @@ void beginUsbLoggingPort() {
return;
}
#if defined(MESH_ESP32_DUAL_CDC_LOGGING)
// ESP32 registers its descriptor before app_main starts native USB. If the
// saved boot mirror omitted CDC 1, enabling logging takes effect after the
// next reboot instead of trying to mutate a live USB descriptor.
if (dedicated_usb_logging_port == nullptr) return;
// Only the Companion interface may use the CDC control-line reboot gesture.
// A terminal opening or closing the diagnostics interface must never reboot
// the node or put it into the ROM downloader.
dedicated_usb_logging_port->enableReboot(false);
dedicated_usb_logging_port->setTxTimeoutMs(0);
dedicated_usb_logging_port->begin(115200);
#elif defined(MESH_NRF52_DUAL_CDC_LOGGING)
dedicated_usb_logging_port.begin(115200);
// `begin()` installs the core's generic "TinyUSB Serial" name. Replace it
// before (re-)enumeration so host USB tools can distinguish the log endpoint.
dedicated_usb_logging_port.setStringDescriptor("MeshCore Logging");
dedicated_usb_logging_port_configured = true;
#endif
dedicated_usb_logging_port_started = true;
#if defined(MESH_NRF52_DUAL_CDC_LOGGING)
// The nRF52 core starts TinyUSB before setup(). If the host completed
// enumeration in that small window, reconnect once so it reads the expanded
// two-CDC descriptor. Usually enumeration has not completed and no reconnect
@@ -181,20 +88,13 @@ void beginUsbLoggingPort() {
TinyUSBDevice.attach();
}
#endif
#endif
}
void serviceUsbLoggingPort() {
#if defined(MESH_DUAL_CDC_LOGGING)
bool connected = false;
#if defined(MESH_NRF52_DUAL_CDC_LOGGING)
connected = dedicated_usb_logging_port_started
&& dedicated_usb_logging_port.dtr();
#elif defined(MESH_ESP32_DUAL_CDC_LOGGING)
connected = dedicated_usb_logging_port_started
&& dedicated_usb_logging_port != nullptr
&& (bool)*dedicated_usb_logging_port;
#endif
if (connected && !dedicated_usb_logging_port_connected
&& isUsbLoggingEnabled()) {
@@ -208,16 +108,9 @@ void serviceUsbLoggingPort() {
Stream& usbLoggingPort() {
#if defined(MESH_DUAL_CDC_LOGGING)
#if defined(MESH_NRF52_DUAL_CDC_LOGGING)
if (isUsbLoggingEnabled() && dedicated_usb_logging_port_started) {
return dedicated_usb_logging_port;
}
#elif defined(MESH_ESP32_DUAL_CDC_LOGGING)
if (isUsbLoggingEnabled() && dedicated_usb_logging_port_started
&& dedicated_usb_logging_port != nullptr) {
return *dedicated_usb_logging_port;
}
#endif
return null_usb_logging_stream;
#else
if (!isUsbLoggingEnabled()) return null_usb_logging_stream;
+4 -4
View File
@@ -21,13 +21,13 @@ namespace mesh {
bool isUsbLoggingEnabled();
void setUsbLoggingEnabled(bool enabled);
// ESP32 native USB starts before setup(), so its next-boot interface count is
// mirrored outside the normal role preferences. Other platforms need no
// mirror. Returns false only when that mirror could not be saved.
// Kept as a platform-neutral persistence hook. Single-TTY builds need no
// descriptor mirror; nRF52 selects its optional second interface after loading
// the normal role preferences.
bool saveUsbLoggingBootPreference(bool enabled);
// Start the optional dedicated USB logging interface. Ordinary and single-TTY
// builds use Serial; dual-CDC Full Companion builds use a second CDC ACM port.
// builds use Serial; nRF52 Full Companion uses a second CDC ACM port.
void beginUsbLoggingPort();
// Emit a short identity marker whenever a host opens the dedicated logging
// endpoint. The device can report its USB interface, but the host alone chooses
+3 -3
View File
@@ -3,6 +3,8 @@
#include <stddef.h>
#include <stdint.h>
#include "sensors/EnvironmentI2CConfig.h"
// Simulator targets do not include RadioLib, but board pin macros can still
// use its sentinel value. Keep the fallback local to this header.
#ifndef RADIOLIB_NC
@@ -150,10 +152,8 @@ inline bool isFirmwareReserved(uint8_t pin) {
#ifdef PIN_WIRE_SCL
PIN_WIRE_SCL,
#endif
#ifdef ENV_PIN_SDA
#if ENV_HAS_SECONDARY_I2C
ENV_PIN_SDA,
#endif
#ifdef ENV_PIN_SCL
ENV_PIN_SCL,
#endif
#ifdef I2C_SDA
+7 -1
View File
@@ -1292,7 +1292,11 @@ void MQTTBridge::initializeWiFiInTask() {
// Enable automatic reconnection - ESP32 will handle reconnection automatically
WiFi.setAutoReconnect(true);
#if !defined(ESP_ARDUINO_VERSION_MAJOR) || ESP_ARDUINO_VERSION_MAJOR < 3
// Arduino-ESP32 3.x removed setAutoConnect(); begin() plus
// setAutoReconnect() is the supported equivalent there.
WiFi.setAutoConnect(true);
#endif
// Set up WiFi event handlers for better diagnostics and immediate disconnection
// detection. Register ONCE - the bridge is reused across restarts (e.g. stopped
@@ -4098,7 +4102,9 @@ bool MQTTBridge::syncTimeWithNTP(bool force, bool primary_only) {
for (int s = 0; s < server_count && !ntp_ok; s++) {
const char* server = servers[s];
MQTT_DEBUG_PRINTLN("SNTP fallback trying %s...", server);
if (sntp_enabled()) sntp_stop();
// configTime() already stops and reconfigures an active SNTP client on
// both Arduino-ESP32 2.x and 3.x. Avoid the legacy unprefixed stop APIs,
// which are no longer exported by esp_sntp.h in Arduino 3.x.
sntp_set_sync_status(SNTP_SYNC_STATUS_RESET);
configTime(0, 0, server);
for (int i = 0; i < 20; i++) {
@@ -0,0 +1,11 @@
#pragma once
// ENV_PIN_SDA / ENV_PIN_SCL select a dedicated environmental-sensor bus.
// GPIO 0 is valid on supported targets, while negative values are the common
// disconnected-pin sentinel. Keep every consumer on the same validity rule.
#if defined(ENV_PIN_SDA) && defined(ENV_PIN_SCL) \
&& (ENV_PIN_SDA >= 0) && (ENV_PIN_SCL >= 0)
#define ENV_HAS_SECONDARY_I2C 1
#else
#define ENV_HAS_SECONDARY_I2C 0
#endif
@@ -1,8 +1,9 @@
#include "EnvironmentSensorManager.h"
#include "EnvironmentI2CConfig.h"
#include <Wire.h>
#if ENV_PIN_SDA && ENV_PIN_SCL
#if ENV_HAS_SECONDARY_I2C
#define TELEM_WIRE &Wire1 // Use Wire1 as the I2C bus for Environment Sensors
#else
#define TELEM_WIRE &Wire // Use default I2C bus for Environment Sensors
@@ -707,7 +708,7 @@ bool EnvironmentSensorManager::begin() {
#endif
#endif
#if ENV_PIN_SDA && ENV_PIN_SCL
#if ENV_HAS_SECONDARY_I2C
#ifdef NRF52_PLATFORM
Wire1.setPins(ENV_PIN_SDA, ENV_PIN_SCL);
Wire1.setClock(100000);