Skip to content

Fix isExternalPowered(): use PHY-level USB detection, not CDC traffic - #3446

Open
shleepong wants to merge 2 commits into
meshcore-dev:devfrom
shleepong:upstream/esp32-external-powered-fix
Open

shleepong wants to merge 2 commits into
meshcore-dev:devfrom
shleepong:upstream/esp32-external-powered-fix

Conversation

@shleepong

Copy link
Copy Markdown

What

Overrides isExternalPowered() on ESP32Board to use PHY-level USB detection instead of relying on (bool)Serial.

Why

No ESP32-S3 board in this codebase overrode isExternalPowered() before (confirmed by grep; the base MainBoard default is return false;), unlike NRF52Board, which has a real VBUS-detect register (no ESP32-S3 equivalent exists). The obvious first attempt, (bool)Serial, is wrong on both USB stacks used in this codebase: HWCDC::isCDC_Connected() and USBCDC::operator bool() only report true once an actual terminal has exchanged data with the port (CDC TX/RX, or DTR/RTS), so the flag stays stuck false after a plain esp_restart() with no monitor attached, even though USB is genuinely powered. Confirmed on real V4.3 hardware: the companion display's charging icon vanished after a WiFi-toggle reboot and only came back after a manual RST where a terminal happened to be talking to the port.

How

Two USB stacks are in play depending on ARDUINO_USB_MODE:

  • Native USB-Serial-JTAG (HWCDC), e.g. Heltec V4.3: Serial.isPlugged(), public/static, purely SOF-frame-based (USB PHY level), tracked from early boot.
  • External USB-OTG via TinyUSB (USBCDC), e.g. Wireless Tracker V2: tud_mounted(), reflects real bus enumeration, independent of DTR/RTS.

Common limitation either way: a dumb charger with no data lines generates no SOF traffic and never enumerates, so it will not be seen as external power; only an active USB host (PC, OTG phone) will.

Testing

Compiled and validated on real hardware for both stacks (Heltec V4.3 and Wireless Tracker V2): the charging icon now reflects actual USB presence across WiFi-toggle reboots and manual resets.

(Generated with Claude Code)

GNB Build and others added 2 commits September 18, 2026 17:23
(bool)Serial was wrong: HWCDC::isCDC_Connected() and USBCDC::operator
bool() only report true once an actual terminal has exchanged data
with the port (CDC TX/RX, or DTR/RTS), so the flag stays stuck false
after a plain esp_restart() with no monitor attached, even though USB
is genuinely powered. Confirmed on real V4.3 hardware: the charging
icon vanished after WiFi-toggle reboots and only returned after a
manual RST where a tool happened to be talking to the port.

Two USB stacks are in play depending on ARDUINO_USB_MODE:
- Native USB-Serial-JTAG (HWCDC, V4.3): Serial.isPlugged(), public
  static, purely SOF-frame-based (USB PHY level).
- External USB-OTG via TinyUSB (USBCDC, Wireless Tracker V2):
  tud_mounted(), reflects real bus enumeration, independent of DTR/RTS.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant