diff --git a/src/helpers/SerialPacketLog.h b/src/helpers/SerialPacketLog.h index e9d69d65..373657c0 100644 --- a/src/helpers/SerialPacketLog.h +++ b/src/helpers/SerialPacketLog.h @@ -130,7 +130,14 @@ class SerialLogLine { inline void serialLogBegin() { #if defined(ESP32_PLATFORM) && defined(ARDUINO_USB_CDC_ON_BOOT) && \ (ARDUINO_USB_CDC_ON_BOOT == 1) + #if defined(ARDUINO_USB_MODE) && ARDUINO_USB_MODE == 1 + // Arduino 2.0.17 HWCDC decrements an unsigned retry counter when its + // host stops reading. A zero timeout can underflow; retain the bounded + // timeout established by prepareUsbLoggingPort(). + Serial.setTxTimeoutMs(5); + #else Serial.setTxTimeoutMs(0); + #endif #endif } diff --git a/src/helpers/UsbLogging.cpp b/src/helpers/UsbLogging.cpp index 8c79b86c..43af9bf4 100644 --- a/src/helpers/UsbLogging.cpp +++ b/src/helpers/UsbLogging.cpp @@ -483,9 +483,16 @@ public: size_t write(const uint8_t* data, size_t size) override { if (data == nullptr || size == 0) return 0; + // The shared producer guard excludes other application writers here. + // The ISR can only free ring capacity, so one fresh capacity sample keeps + // HWCDC::write out of its wait-for-space remainder loop. + const int available = Serial.availableForWrite(); + if (available <= 0) return 0; + const size_t attempt = size < static_cast(available) + ? size : static_cast(available); noteUsbLoggingTxAttempt(); esp32_hwcdc_tx_kick_pending.store(true, std::memory_order_release); - return Serial.write(data, size); + return Serial.write(data, attempt); } private: diff --git a/variants/station_g2/platformio.ini b/variants/station_g2/platformio.ini index d902668b..81b8b7ad 100644 --- a/variants/station_g2/platformio.ini +++ b/variants/station_g2/platformio.ini @@ -355,6 +355,13 @@ build_src_filter = ${Station_G2.build_src_filter} [env:Station_G2_repeater_observer_mqtt] extends = Station_G2 +; The Full repeater needs a serial console, so use the S3's fixed hardware +; CDC/JTAG controller instead of TinyUSB's DTR-driven session quarantine. +; Companion and the other G2 roles retain their existing USB backend. +build_unflags = + ${Station_G2.build_unflags} + -DARDUINO_USB_MODE=0 +board_upload.use_1200bps_touch = false board_build.partitions = default_16MB.csv ; standard 16MB partition table extra_scripts = ${esp32_base.extra_scripts} @@ -363,6 +370,7 @@ board_ssl_cert_source = adafruit-full board_build.embed_files = src/certs/x509_crt_bundle.bin build_flags = ${Station_G2.build_flags} + -D ARDUINO_USB_MODE=1 ; The base observer disables LoRa OTA; build.sh promotes it to FULL and restores OTA. -UENABLE_OTA -D DISABLE_LORA_OTA=1