From 3b795f7abc6af5ea87608eb5040421ab6990c1b7 Mon Sep 17 00:00:00 2001 From: Jakub <106778416+MarekZegare4@users.noreply.github.com> Date: Fri, 5 Jun 2026 12:36:49 +0200 Subject: [PATCH] feat(ui): detect USB-CDC connection for Auto mute (BLE or USB) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit USB client presence IS detectable on nRF52 after all: (bool)Serial == tud_cdc_n_connected() (DTR — a host has the CDC port open). Add isClientConnected() = BLE-bonded OR USB-CDC-open; DualSerialInterface overrides it, base defaults to isConnected() (single-transport unchanged). Wire it so each consumer gets the right signal: - hasConnection() ← isClientConnected(): Auto buzzer mute + message-wake now trigger on BLE or an open USB port (PR #14's intent, done correctly), but not on charging-only (no host → DTR low). - BT status indicator + pairing PIN stay on isBLEConnected() (BLE-specific). Caveat: a plain serial monitor also asserts DTR, so it counts as connected. Co-Authored-By: Claude Opus 4.8 --- examples/companion_radio/MyMesh.cpp | 11 +++++------ examples/companion_radio/ui-new/UITask.cpp | 2 +- src/helpers/BaseSerialInterface.h | 6 ++++++ src/helpers/nrf52/DualSerialInterface.h | 4 ++++ 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 8d616de3..ca889598 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -2497,12 +2497,11 @@ void MyMesh::loop() { } #ifdef DISPLAY_CLASS - // Use BLE-bonded state, not isConnected(): on a dual (BLE+USB) interface - // isConnected() is hardcoded true (USB is always a send fallback), and USB - // client presence isn't detectable anyway. hasConnection() drives the BT - // status indicator, message-wake and the Auto buzzer mute — all of which - // mean "a companion app is connected", i.e. BLE bonded. - if (_ui) _ui->setHasConnection(_serial->isBLEConnected()); + // "a companion app is connected over any transport" — BLE bonded or a host + // holding the USB-CDC port open. Drives Auto buzzer mute + message-wake. + // (Not isConnected(): a dual interface hardcodes that true as a send + // fallback. The BT status indicator and pairing PIN use isBLEConnected().) + if (_ui) _ui->setHasConnection(_serial->isClientConnected()); #endif } diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index c4d7258e..1bc1b3fa 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -456,7 +456,7 @@ class HomeScreen : public UIScreen { int leftmostX = battLeftX; if (_task->isSerialEnabled()) { int btX = battLeftX - ind - ind_gap; - if (_task->hasConnection()) { + if (_task->isBLEConnected()) { // BT icon reflects BLE link, not USB display.setColor(DisplayDriver::LIGHT); display.fillRect(btX, 0, ind, ind_h); display.setColor(DisplayDriver::DARK); diff --git a/src/helpers/BaseSerialInterface.h b/src/helpers/BaseSerialInterface.h index 91d2c8c7..ba3f452a 100644 --- a/src/helpers/BaseSerialInterface.h +++ b/src/helpers/BaseSerialInterface.h @@ -18,6 +18,12 @@ public: // isConnected(); override in dual-interface wrappers that always report // isConnected()=true but still need to distinguish BLE from USB state. virtual bool isBLEConnected() const { return isConnected(); } + // True when a companion app is actually connected over *any* transport + // (BLE bonded or a host holding the USB-CDC port open). Distinct from + // isConnected(), which a dual interface hardcodes true as a send fallback. + // Used for app-connected UI (Auto buzzer mute, message-wake). Default = + // isConnected() so single-transport interfaces are unchanged. + virtual bool isClientConnected() const { return isConnected(); } virtual bool isWriteBusy() const = 0; virtual size_t writeFrame(const uint8_t src[], size_t len) = 0; diff --git a/src/helpers/nrf52/DualSerialInterface.h b/src/helpers/nrf52/DualSerialInterface.h index fe239552..67ddfe34 100644 --- a/src/helpers/nrf52/DualSerialInterface.h +++ b/src/helpers/nrf52/DualSerialInterface.h @@ -33,6 +33,10 @@ public: 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();