Add native USB CDC broker transport
This commit is contained in:
@@ -12,7 +12,7 @@ Universal wireless serial adaptor firmware for the ESP32-S3.
|
||||
- 8 MB octal PSRAM
|
||||
- Adafruit MAX3243 full-pinout RS-232 breakout, product 5988
|
||||
|
||||
The firmware has completed **Phase 0 hardware characterization** and the **Phase 1 serial-core foundation**. **Phase 2** adds a transport-neutral serial-session broker with one active writer, multiple observers, bounded per-client queues, event delivery, and slow-client isolation. The MAX3243 diagnostics and persistent serial configuration remain available. Neither the UART service nor an electrical test starts automatically at boot.
|
||||
The firmware has completed **Phase 0 hardware characterization**, the **Phase 1 serial-core foundation**, and the **Phase 2 transport-neutral session broker**. The current phase adds the first real broker transport: native USB CDC-ACM on the ESP32-S3 USB port. The MAX3243 diagnostics and persistent serial configuration remain available. No electrical test starts automatically; UART1 starts when requested explicitly or when a host opens native USB CDC.
|
||||
|
||||
## Hardware wiring
|
||||
|
||||
@@ -59,14 +59,14 @@ pio run
|
||||
|
||||
## Upload and monitor
|
||||
|
||||
Connect the board's USB-to-UART port, then run:
|
||||
Connect the board's **USB-to-UART** port for firmware upload and the UART0 development console, then run:
|
||||
|
||||
```sh
|
||||
pio run --target upload
|
||||
pio device monitor -b 115200
|
||||
```
|
||||
|
||||
The firmware starts an interactive console on UART0 with the prompt `serial-tool>`. Type `help` to display command descriptions.
|
||||
The firmware starts an interactive console on UART0 with the prompt `serial-tool>`. Type `help` to display command descriptions. This USB-to-UART device normally appears as `/dev/ttyUSB*`; it is separate from the native USB CDC serial transport described below.
|
||||
|
||||
### Phase 1 serial service
|
||||
|
||||
@@ -105,7 +105,7 @@ UART1 has exclusive ownership while the service runs. Phase 0 commands will refu
|
||||
|
||||
### Phase 2 session broker
|
||||
|
||||
The broker is initialized at boot and continuously drains the serial service whenever UART1 is running. It is transport-neutral: current console clients use the same API that native USB CDC, WebSocket, and SSH transports will use later.
|
||||
The broker is initialized at boot and continuously drains the serial service whenever UART1 is running. It is transport-neutral: console test clients and native USB CDC use the same API that WebSocket and SSH transports will use later.
|
||||
|
||||
```text
|
||||
broker status
|
||||
@@ -130,6 +130,64 @@ Exactly one client may hold the writer lease. Competing requests are denied and
|
||||
|
||||
Connect, disconnect, writer grant, release, revoke, and denial events have a broker-global sequence number. Event queues are intentionally bounded, so future transports should reconcile sequence gaps against broker snapshots. The first and last broker connection also drive the Phase 1 `DTR=on-connect` policy.
|
||||
|
||||
### Native USB CDC-ACM transport
|
||||
|
||||
The ESP32-S3's native USB OTG peripheral presents one CDC-ACM serial interface through the development board's connector labelled **USB**. It uses GPIO19 (`USB D-`) and GPIO20 (`USB D+`) and normally appears on Linux as `/dev/ttyACM*`. It is not the USB-to-UART bridge used for upload and logs.
|
||||
|
||||
The UART0 development console provides these diagnostics and controls:
|
||||
|
||||
```text
|
||||
usb status
|
||||
usb counters
|
||||
usb clear-counters
|
||||
usb request-writer
|
||||
usb release-writer
|
||||
```
|
||||
|
||||
Opening the CDC port with DTR asserted automatically starts UART1, connects a broker client named `usb-cdc`, and requests the writer lease. If another client already owns the lease, USB remains connected as a read-only observer; `usb status` reports its current role. Closing the port or unplugging native USB disconnects that broker client and discards transport-local pending data. The serial service itself remains running until it is stopped explicitly with `serial stop`.
|
||||
|
||||
The data path is binary-transparent. UTF-8 bytes, NUL bytes, terminal escape sequences, and color sequences are passed unchanged; interpretation remains the terminal application's responsibility. USB output is bounded and nonblocking, so a host that stops reading can lose only its own observer data rather than stall UART1 or another client.
|
||||
|
||||
Host line coding is accepted for baud rates 110–1000000 with 7 or 8 data bits, none/odd/even parity, and 1 or 2 stop bits. USB's 1.5 stop bits and mark/space parity are rejected. Supported settings are applied to the working UART configuration only when USB owns the writer lease and queued UART TX has drained. They are not saved to NVS automatically; use `serial save` deliberately if the setting should survive reboot. USB RTS is reported as host status only. It does not drive the physical RS-232 RTS line, which remains controlled by UART1's configured RTS/CTS flow control.
|
||||
|
||||
The development VID/PID comes from Espressif's TinyUSB defaults. The USB serial-number string is derived from the ESP32-S3 station MAC so multiple adapters can be distinguished consistently.
|
||||
|
||||
#### Linux loopback validation
|
||||
|
||||
Keep the USB-to-UART cable connected for logs and commands, and connect a second data-capable cable to the native **USB** connector. On the host, identify the new CDC device:
|
||||
|
||||
```sh
|
||||
dmesg
|
||||
ls -l /dev/ttyACM*
|
||||
```
|
||||
|
||||
With power removed and no external RS-232 peer attached, connect only DE-9 pin 3 (`TX`) to pin 2 (`RX`), then power the board. Open the native port with a serial terminal such as:
|
||||
|
||||
```sh
|
||||
picocom -b 115200 /dev/ttyACM0
|
||||
```
|
||||
|
||||
Use the actual device path assigned by the host. Typed data should return through USB → broker → UART1 → MAX3243 loopback → broker → USB. On the UART0 console, verify `usb status`, `usb counters`, `broker clients`, and `serial status`. The USB client should normally be the writer and counters should increase without drops.
|
||||
|
||||
For a binary check, install PySerial on the host and send all byte values:
|
||||
|
||||
```python
|
||||
import serial
|
||||
|
||||
payload = bytes(range(256))
|
||||
with serial.Serial("/dev/ttyACM0", 115200, timeout=2) as port:
|
||||
port.reset_input_buffer()
|
||||
port.write(payload)
|
||||
echoed = port.read(len(payload))
|
||||
|
||||
assert echoed == payload, (len(echoed), echoed.hex())
|
||||
print("256-byte binary USB/RS-232 loopback passed")
|
||||
```
|
||||
|
||||
Close the terminal and check `usb status` and `broker clients`; DTR-aware applications should cause the USB broker client to disconnect. Physically unplugging the native USB cable is the definitive detach test. To test observer mode, assign a console test client as writer before opening `/dev/ttyACM0`; USB should connect as an observer, receive UART output, and discard host-originated input until ownership is granted.
|
||||
|
||||
Power down and remove the DE-9 pin 3-to-2 jumper before connecting an external serial peer.
|
||||
|
||||
### Phase 0 diagnostics
|
||||
|
||||
The retained hardware-characterization commands are:
|
||||
|
||||
Reference in New Issue
Block a user