Add a saved override to keep USB packet logging continuous

This commit is contained in:
mikecarper committed 2026-10-27 18:47:05 -07:00
1 parent 1f2fcfc449
commit 05679aa741
18 files changed
+382 -39

No files matched your search

+42 -3
View File
@@ -1055,6 +1055,7 @@ void CommonCLI::loadPrefs(FILESYSTEM* fs) {
_prefs->usb_logging_enabled = 1;
#endif
_prefs->usb_debug_enabled = 0;
_prefs->usb_logging_always = 0;
_prefs->trace_when_repeat_off = 0;
_prefs->discovery_responses = mesh::discovery::DEFAULT_RESPONSES;
_prefs->ota_channel = 0;
@@ -1295,6 +1296,7 @@ void CommonCLI::loadPrefs(FILESYSTEM* fs) {
#endif
#if MESH_USB_LOGGING_AVAILABLE
mesh::setUsbDebugEnabled(_prefs->usb_debug_enabled != 0);
mesh::setUsbPacketLoggingAlways(_prefs->usb_logging_always != 0);
mesh::setUsbLoggingEnabled(_prefs->usb_logging_enabled != 0);
#endif
_radio_profiles.adoptPrimaryPreamble(_prefs->primary_radio_preamble);
@@ -1329,6 +1331,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
// Older or truncated preference images must never inherit these opt-ins
// from a previous load of a newer image.
_prefs->usb_debug_enabled = 0;
_prefs->usb_logging_always = 0;
_prefs->trace_when_repeat_off = 0;
_prefs->discovery_responses = mesh::discovery::DEFAULT_RESPONSES;
_prefs->gps_sync_interval_hours = 0;
@@ -1408,7 +1411,9 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
file.read((uint8_t *)&_prefs->agc_reset_interval, sizeof(_prefs->agc_reset_interval)); // 120
file.read((uint8_t *)&_prefs->path_hash_mode, sizeof(_prefs->path_hash_mode)); // 121
file.read((uint8_t *)&_prefs->loop_detect, sizeof(_prefs->loop_detect)); // 122
file.read(pad, 1); // 123
uint8_t usb_logging_policy = 0;
file.read(&usb_logging_policy, 1); // 123: formerly padding
_prefs->usb_logging_always = usb_logging_policy == 0xA1 ? 1 : 0;
file.read((uint8_t *)&_prefs->flood_max, sizeof(_prefs->flood_max)); // 124
file.read((uint8_t *)&_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 125
file.read((uint8_t *)&_prefs->interference_threshold, sizeof(_prefs->interference_threshold)); // 126
@@ -1963,6 +1968,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
_prefs->usb_logging_enabled = constrain(_prefs->usb_logging_enabled, 0, 1); // boolean
// Only a deliberately saved 1 enables diagnostics; corrupted bytes are OFF.
_prefs->usb_debug_enabled = _prefs->usb_debug_enabled == 1 ? 1 : 0;
_prefs->usb_logging_always = _prefs->usb_logging_always == 1 ? 1 : 0;
// Corrupt or unknown values must not enable a repeat-off exception.
_prefs->trace_when_repeat_off = _prefs->trace_when_repeat_off == 1 ? 1 : 0;
_prefs->cad_enabled = constrain(_prefs->cad_enabled, 0, 1); // boolean
@@ -2093,7 +2099,8 @@ static bool writeCommonPrefsImage(Writer& writer, NodePrefs* prefs) {
WRITE_COMMON_PREFS(&prefs->agc_reset_interval); // 120
WRITE_COMMON_PREFS(&prefs->path_hash_mode); // 121
WRITE_COMMON_PREFS(&prefs->loop_detect); // 122
WRITE_COMMON_PREFS_BYTES(pad, 1); // 123
const uint8_t usb_logging_policy = prefs->usb_logging_always == 1 ? 0xA1 : 0;
WRITE_COMMON_PREFS(&usb_logging_policy); // 123: formerly padding
WRITE_COMMON_PREFS(&prefs->flood_max); // 124
WRITE_COMMON_PREFS(&prefs->flood_advert_interval); // 125
WRITE_COMMON_PREFS(&prefs->interference_threshold); // 126
@@ -2311,6 +2318,7 @@ void CommonCLI::savePrefs(FILESYSTEM* fs, PrefsSaveRouting::Scope scope) {
_common_save_result_known = true;
_common_save_succeeded = false;
_prefs->usb_debug_enabled = _prefs->usb_debug_enabled == 1 ? 1 : 0;
_prefs->usb_logging_always = _prefs->usb_logging_always == 1 ? 1 : 0;
_prefs->trace_when_repeat_off = _prefs->trace_when_repeat_off == 1 ? 1 : 0;
if (_prefs->discovery_responses > mesh::discovery::DEFAULT_RESPONSES)
_prefs->discovery_responses = mesh::discovery::DEFAULT_RESPONSES;
@@ -2373,7 +2381,8 @@ void CommonCLI::savePrefs(FILESYSTEM* fs, PrefsSaveRouting::Scope scope) {
file.write((uint8_t *)&_prefs->agc_reset_interval, sizeof(_prefs->agc_reset_interval)); // 120
file.write((uint8_t *)&_prefs->path_hash_mode, sizeof(_prefs->path_hash_mode)); // 121
file.write((uint8_t *)&_prefs->loop_detect, sizeof(_prefs->loop_detect)); // 122
file.write(pad, 1); // 123
const uint8_t usb_logging_policy = _prefs->usb_logging_always == 1 ? 0xA1 : 0;
file.write(&usb_logging_policy, 1); // 123: formerly padding
file.write((uint8_t *)&_prefs->flood_max, sizeof(_prefs->flood_max)); // 124
file.write((uint8_t *)&_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 125
file.write((uint8_t *)&_prefs->interference_threshold, sizeof(_prefs->interference_threshold)); // 126
@@ -2499,6 +2508,7 @@ void CommonCLI::savePrefs(FILESYSTEM* fs, PrefsSaveRouting::Scope scope) {
// Dynamic config imports use this path too. Do not enable diagnostics
// until the corresponding common preference image is committed.
mesh::setUsbDebugEnabled(_prefs->usb_debug_enabled != 0);
mesh::setUsbPacketLoggingAlways(_prefs->usb_logging_always != 0);
mesh::setUsbLoggingEnabled(_prefs->usb_logging_enabled != 0);
}
#endif
@@ -4438,6 +4448,29 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
}
#endif
#if MESH_USB_LOGGING_AVAILABLE
#if !defined(MESH_DUAL_CDC_LOGGING)
if (strncmp(config, "usb.logging.always", 18) == 0
&& (config[18] == 0 || config[18] == ' ' || config[18] == '\t')) {
const char* value = config + 18;
while (*value == ' ' || *value == '\t') value++;
bool enabled = false, reboot_if_needed = false;
if (!mesh::cli::parseLoggingToggle(value, enabled, reboot_if_needed)
|| reboot_if_needed) {
mesh::cli::formatError(reply, 160, "usage set usb.logging.always on|off");
return;
}
const uint8_t previous = _prefs->usb_logging_always;
_prefs->usb_logging_always = enabled ? 1 : 0;
if (!trySavePrefs()) {
_prefs->usb_logging_always = previous;
mesh::cli::formatError(reply, 160, "save unconfirmed; reboot may differ");
return;
}
mesh::setUsbPacketLoggingAlways(enabled);
snprintf(reply, 160, "OK - USB logging always %s (saved)", enabled ? "on" : "off");
return;
}
#endif
if (strncmp(config, "usb.logging", 11) == 0
&& (config[11] == 0 || config[11] == ' ' || config[11] == '\t')) {
const char* value = &config[11];
@@ -6035,6 +6068,12 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
}
#endif
#if MESH_USB_LOGGING_AVAILABLE
#if !defined(MESH_DUAL_CDC_LOGGING)
if (strcmp(config, "usb.logging.always") == 0) {
snprintf(reply, 160, "> %s", mesh::isUsbPacketLoggingAlways() ? "on" : "off");
return;
}
#endif
if (strcmp(config, "usb.logging") == 0) {
snprintf(reply, 160, "> %s",
mesh::isUsbLoggingEnabled() ? "on" : "off");
+3
View File
@@ -201,6 +201,8 @@ public:
// USB diagnostics are opt-in independently of the packet output gate.
// Appended after GPS sync cadence in /com_prefs, not beside usb_log.
uint8_t usb_debug_enabled = 0;
// Reuses reserved /com_prefs byte 123; 0xA1 on disk means enabled.
uint8_t usb_logging_always = 0;
// Repeater-only opt-in for routed trace diagnostics while repeat is off.
// Appended after usb_debug in /com_prefs; existing images stay disabled.
uint8_t trace_when_repeat_off = 0;
@@ -386,6 +388,7 @@ private:
def("format", _parent->bridge_format);
def("usb_log", _parent->usb_logging_enabled);
def("usb_dbg", _parent->usb_debug_enabled);
def("usb_always", _parent->usb_logging_always);
#ifdef WITH_RS232_BRIDGE
def("rs232_heartbeat", _parent->rs232_heartbeat);
def("rs232_autosleep", _parent->rs232_autosleep);
+13 -2
View File
@@ -96,6 +96,7 @@ static std::atomic<bool> usb_logging_preference_known{false};
static std::atomic<bool> usb_debug_enabled{false};
#if MESH_USB_LOGGING_AVAILABLE && !defined(MESH_DUAL_CDC_LOGGING)
static std::atomic<uint32_t> usb_packet_logging_quiet_until{0};
static std::atomic<bool> usb_packet_logging_always{false};
#endif
#if MESH_ENABLE_HOST_KISS
static std::atomic<bool> usb_binary_stream_owned{false};
@@ -1299,7 +1300,8 @@ bool isUsbLoggingEnabled() {
#if MESH_USB_LOGGING_AVAILABLE && !defined(MESH_DUAL_CDC_LOGGING)
void noteUsbConsoleCommand(const char* command) {
if (command == nullptr || hasDedicatedUsbLoggingPort() || isUsbLoggingPacketStream()) return;
if (command == nullptr || isUsbPacketLoggingAlways()
|| hasDedicatedUsbLoggingPort() || isUsbLoggingPacketStream()) return;
while (*command == ' ' || *command == '\t' || *command == '\r' || *command == '\n') ++command;
if (*command == 0 || isUsbLoggingStatsCommand(command)) return;
for (const unsigned char* p = reinterpret_cast<const unsigned char*>(command); *p; ++p) {
@@ -1314,6 +1316,15 @@ void resumeUsbPacketLogging() {
usb_packet_logging_quiet_until.store(0, std::memory_order_relaxed);
}
void setUsbPacketLoggingAlways(bool enabled) {
usb_packet_logging_always.store(enabled, std::memory_order_relaxed);
if (enabled) resumeUsbPacketLogging();
}
bool isUsbPacketLoggingAlways() {
return usb_packet_logging_always.load(std::memory_order_relaxed);
}
bool isUsbPacketLoggingAllowed() {
uint32_t deadline = usb_packet_logging_quiet_until.load(std::memory_order_relaxed);
bool quiet = deadline != 0;
@@ -1323,7 +1334,7 @@ bool isUsbPacketLoggingAllowed() {
deadline, 0, std::memory_order_relaxed) && deadline != 0;
}
return isUsbLoggingEnabled()
&& (hasDedicatedUsbLoggingPort() || isUsbLoggingPacketStream() || !quiet);
&& (isUsbPacketLoggingAlways() || hasDedicatedUsbLoggingPort() || isUsbLoggingPacketStream() || !quiet);
}
#endif
+7
View File
@@ -98,6 +98,8 @@ void setUsbLoggingEnabled(bool enabled);
inline void noteUsbConsoleCommand(const char*) {}
inline void resumeUsbPacketLogging() {}
inline bool isUsbPacketLoggingAllowed() { return isUsbLoggingEnabled(); }
inline void setUsbPacketLoggingAlways(bool) {}
inline bool isUsbPacketLoggingAlways() { return false; }
#elif MESH_USB_LOGGING_AVAILABLE
// Human console commands pause packet records for five minutes without
// changing the saved logging setting, functional replies, or debug output.
@@ -106,10 +108,15 @@ inline bool isUsbPacketLoggingAllowed() { return isUsbLoggingEnabled(); }
void noteUsbConsoleCommand(const char* command);
void resumeUsbPacketLogging();
bool isUsbPacketLoggingAllowed();
// The role persists this shared-port policy; it never enables the master gate.
void setUsbPacketLoggingAlways(bool enabled);
bool isUsbPacketLoggingAlways();
#else
inline void noteUsbConsoleCommand(const char*) {}
inline void resumeUsbPacketLogging() {}
inline bool isUsbPacketLoggingAllowed() { return false; }
inline void setUsbPacketLoggingAlways(bool) {}
inline bool isUsbPacketLoggingAlways() { return false; }
#endif
// Verbose diagnostics are opt-in and persisted by the role preferences.
// The requested setting survives switching the master USB output gate off.