180 lines
8.4 KiB
C++
180 lines
8.4 KiB
C++
#pragma once
|
|
|
|
#include "UsbLoggingStatus.h"
|
|
|
|
// Canonical USB-capable images compile at least one of these two diagnostics.
|
|
// A master USB output gate and a separate debug-verbosity gate keep packet
|
|
// capture available without verbose diagnostics or a separate logging image.
|
|
#if !defined(MESH_USB_LOGGING_DISABLED) && defined(ARDUINO) && \
|
|
((defined(MESH_DEBUG) && MESH_DEBUG) || \
|
|
(defined(MESH_PACKET_LOGGING) && MESH_PACKET_LOGGING))
|
|
#define MESH_USB_LOGGING_AVAILABLE 1
|
|
#else
|
|
#define MESH_USB_LOGGING_AVAILABLE 0
|
|
#endif
|
|
|
|
#if defined(ARDUINO)
|
|
#include <Arduino.h>
|
|
|
|
// ESP32-S2/S3 native USB CDC uses USBCDC, not the hardware USB-Serial-JTAG
|
|
// driver. Its write timeout only bounds a mutex, not waiting for FIFO space.
|
|
// All roles sharing this CDC therefore need the single-attempt transport.
|
|
#if defined(ESP32) && defined(ARDUINO_USB_MODE) && ARDUINO_USB_MODE == 0 \
|
|
&& defined(ARDUINO_USB_CDC_ON_BOOT) && ARDUINO_USB_CDC_ON_BOOT
|
|
#define MESH_ESP32_TINYUSB_NONBLOCKING 1
|
|
#else
|
|
#define MESH_ESP32_TINYUSB_NONBLOCKING 0
|
|
#endif
|
|
|
|
// ESP32-S3 USB-Serial/JTAG (HWCDC) has a software TX ring which can retain a
|
|
// previous host's bytes across a USB bus reset. This capability is independent
|
|
// of the Companion role: room, repeater, and sensor consoles need the same
|
|
// session gate and bounded writes.
|
|
#if defined(ESP32) && defined(ARDUINO_USB_MODE) && ARDUINO_USB_MODE == 1 \
|
|
&& defined(ARDUINO_USB_CDC_ON_BOOT) && ARDUINO_USB_CDC_ON_BOOT
|
|
#define MESH_ESP32_HWCDC_SESSION_GUARD 1
|
|
#else
|
|
#define MESH_ESP32_HWCDC_SESSION_GUARD 0
|
|
#endif
|
|
|
|
#if MESH_ESP32_TINYUSB_NONBLOCKING || MESH_ESP32_HWCDC_SESSION_GUARD
|
|
#define MESH_ESP32_USB_CONSOLE_COOPERATIVE 1
|
|
#else
|
|
#define MESH_ESP32_USB_CONSOLE_COOPERATIVE 0
|
|
#endif
|
|
|
|
#if defined(NRF52_PLATFORM) && defined(USE_TINYUSB)
|
|
#define MESH_NRF52_USB_CONSOLE_COOPERATIVE 1
|
|
#else
|
|
#define MESH_NRF52_USB_CONSOLE_COOPERATIVE 0
|
|
#endif
|
|
#define MESH_USB_CONSOLE_COOPERATIVE \
|
|
(MESH_ESP32_USB_CONSOLE_COOPERATIVE || MESH_NRF52_USB_CONSOLE_COOPERATIVE)
|
|
|
|
namespace mesh {
|
|
|
|
#ifndef MESH_ESP32_USB_TX_BUFFER_SIZE
|
|
#define MESH_ESP32_USB_TX_BUFFER_SIZE 4096
|
|
#endif
|
|
#ifndef MESH_ESP32_USB_RX_BUFFER_SIZE
|
|
#define MESH_ESP32_USB_RX_BUFFER_SIZE 1024
|
|
#endif
|
|
|
|
namespace detail {
|
|
|
|
// Keep the identity-marker reconnect rule pure so host tests can exercise the
|
|
// DTR edge case without a TinyUSB device. The USB owner task passes the actual
|
|
// TinyUSB write result here. A short write means the old connection vanished
|
|
// mid-record; byte zero is the only safe starting point for the next host.
|
|
inline size_t nextUsbLoggingIdentityOffset(size_t current_offset,
|
|
size_t requested,
|
|
size_t written) {
|
|
return written == requested ? current_offset + written : 0;
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
// Ordinary merged images start enabled. USB/Full Companion starts disabled to
|
|
// protect framed traffic and restores its saved choice after preferences load.
|
|
bool isUsbLoggingEnabled();
|
|
void setUsbLoggingEnabled(bool enabled);
|
|
// Verbose diagnostics are opt-in and persisted by the role preferences.
|
|
// The requested setting survives switching the master USB output gate off.
|
|
bool isUsbDebugEnabled();
|
|
void setUsbDebugEnabled(bool enabled);
|
|
inline bool isUsbDebugLoggingEnabled() {
|
|
return isUsbLoggingEnabled() && isUsbDebugEnabled();
|
|
}
|
|
|
|
// 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);
|
|
// Select the saved Companion packet-stream mode before preferences enable
|
|
// logging and before the optional second CDC is configured. This keeps CLI
|
|
// replies and packet records on one port for stock serial packet bridges.
|
|
void configureUsbLoggingPacketStream(bool enabled);
|
|
bool isUsbLoggingPacketStream();
|
|
|
|
// Record the HWCDC TX ring size actually allocated during early setup. A zero
|
|
// value keeps reset cleanup quarantined and eligible for a minimum-size retry
|
|
// instead of mistaking an allocation failure for a permanently non-empty ring.
|
|
void setUsbCompanionTxBufferCapacity(size_t capacity);
|
|
|
|
// Configure ESP32 HWCDC's RX queue, bounded write timeout and TX ring before
|
|
// Serial.begin creates its mutex and enables the USB ISR. HWCDC silently drops
|
|
// incoming bytes when its queue is full; hosts must wait for each command reply
|
|
// rather than pipeline bursts larger than the bounded queue. Safe as a no-op
|
|
// on other ports.
|
|
void prepareUsbLoggingPort();
|
|
|
|
// Start the optional dedicated USB logging interface. Ordinary and single-TTY
|
|
// builds use Serial; nRF52 Full Companion uses a second CDC ACM port. Call this
|
|
// after Serial.begin() so native USB roles also register session events.
|
|
void beginUsbLoggingPort();
|
|
// Enable owner-task service when a host opens the dedicated logging endpoint.
|
|
// That task emits the identity marker from the actual TinyUSB write result and
|
|
// retries a busy CDC TX FIFO without waiting.
|
|
// The device can report its USB interface, but the host alone chooses names
|
|
// such as /dev/ttyACM1 or COM7.
|
|
void serviceUsbLoggingPort();
|
|
Stream& usbLoggingPort();
|
|
// Debug-only output uses the same bounded transport when BOTH gates are on.
|
|
// Packet records, identity markers and functional replies must not use this.
|
|
Stream& usbDebugPort();
|
|
// Primary USB Companion data stream. Native TinyUSB on nRF52 and ESP32 uses
|
|
// one FIFO attempt per write, never the framework's wait-for-space loop.
|
|
// Callers retain and retry unwritten suffixes. Other platforms retain Serial
|
|
// or their hardware-CDC session facade.
|
|
Stream& usbCompanionPort();
|
|
// A primary nRF52 client may send commands with DTR low (stock MeshCLI does).
|
|
// Accept actual input in the current USB session as proof of a reader, while
|
|
// retaining the same close/reset generation gate used by the transport.
|
|
#if defined(NRF52_PLATFORM) && (defined(ENABLE_USB_INTERFACE) || defined(USE_TINYUSB))
|
|
bool isUsbCompanionClientConnected();
|
|
#endif
|
|
// Serial mOTA requests are binary records of at most 11 bytes. On TinyUSB this
|
|
// facade admits a request only when the complete record fits in CDC0's current
|
|
// TX capacity, so a retry can never append to a prefix from the prior attempt.
|
|
Stream& usbMotaPort();
|
|
// Functional ASCII output needs the same zero-wait USB primitive plus a
|
|
// bounded queue so a normal host receives complete multi-line replies. Service
|
|
// it from the application loop; discard it before changing the CDC protocol or
|
|
// after a host disconnect so stale text cannot prefix a later Binary session.
|
|
// A quiet default terminal discards unsolicited text until the host sends ASCII.
|
|
Stream& usbTerminalPort(bool enabled = true);
|
|
// Repeater/room-server/sensor console: protect both ESP32 native USB transports
|
|
// while preserving the historical raw Serial behavior of other platforms.
|
|
Stream& usbConsolePort();
|
|
// Diagnostic backlog alone must not starve console input. Native ESP32 CDC
|
|
// admits another command when its reserved functional capacity is available;
|
|
// other platforms preserve their existing command-processing policy.
|
|
bool canAcceptUsbConsoleCommand();
|
|
void serviceUsbTerminalPort();
|
|
void discardUsbTerminalOutput();
|
|
bool hasPendingUsbTerminalOutput();
|
|
// Bytes refused while an ESP32 TinyUSB terminal host was connected. A visible
|
|
// overflow marker is emitted once queue capacity recovers; other ports return 0.
|
|
uint32_t usbTerminalDroppedBytes();
|
|
// Consume a primary-USB session boundary reported by the USB owner task:
|
|
// CDC0 DTR-low on TinyUSB, or a hardware CDC bus reset on ESP32. This is
|
|
// independent of polling current line/SOF state; ESP32 retains that poll as a
|
|
// fallback because its bundled framework event queue is finite.
|
|
bool takeUsbTerminalSessionReset();
|
|
// After the application has reset its protocol state, atomically purge any
|
|
// CDC0 writer that raced the close callback and reopen the producer gate. A
|
|
// false result is a zero-wait busy indication; retry it next loop.
|
|
bool tryCompleteUsbTerminalSessionReset();
|
|
// Purge platform USB-driver bytes at a confirmed host-session boundary. On
|
|
// ESP32 HWCDC this briefly detaches the PHY and gates diagnostics so stale RX
|
|
// or TX data cannot cross into a newly enumerated host session. A false result
|
|
// leaves that quarantine intact and should be retried from a later loop.
|
|
bool resetUsbCompanionTransport();
|
|
bool hasDedicatedUsbLoggingPort();
|
|
bool isDedicatedUsbLoggingPortConfigured();
|
|
bool usbLoggingInterfaceRestartRequired();
|
|
const char* usbLoggingPortDescription();
|
|
|
|
} // namespace mesh
|
|
#endif
|