Conversation
Agent-Logs-Url: https://github.com/bring42/tbx/sessions/2816ed76-19fb-4145-812b-d366a6770f48 Co-authored-by: bring42 <63049750+bring42@users.noreply.github.com>
Agent-Logs-Url: https://github.com/bring42/tbx/sessions/2816ed76-19fb-4145-812b-d366a6770f48 Co-authored-by: bring42 <63049750+bring42@users.noreply.github.com>
Agent-Logs-Url: https://github.com/bring42/tbx/sessions/2816ed76-19fb-4145-812b-d366a6770f48 Co-authored-by: bring42 <63049750+bring42@users.noreply.github.com>
Agent-Logs-Url: https://github.com/bring42/tbx/sessions/2816ed76-19fb-4145-812b-d366a6770f48 Co-authored-by: bring42 <63049750+bring42@users.noreply.github.com>
Agent-Logs-Url: https://github.com/bring42/tbx/sessions/2816ed76-19fb-4145-812b-d366a6770f48 Co-authored-by: bring42 <63049750+bring42@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds dual-channel UART monitoring/injection plus optional bidirectional passthrough bridging to the tools/userial ESP32 web-UI tool, along with updated dev-server mocks and refreshed UI assets.
Changes:
- Extend firmware to support two UART channels (A/B), passthrough modes, per-port counters, and on-device history buffering.
- Refresh userial web UI to show per-port traffic, filtering, injection targeting, and passthrough controls (plus updated mocks).
- Improve dev server behavior for the new WS protocol and ignore local
dist/build artifacts.
Reviewed changes
Copilot reviewed 9 out of 11 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/userial/web/mock_data.json | Updates mock payload schema for dual-port status/settings/history. |
| tools/userial/web/config.json | Renames tool title for the new dual-UART functionality. |
| tools/userial/web/app.js | Implements dual-port monitoring, filtering, export, and targeted injection logic. |
| tools/userial/web/app.html | Updates layout to show bridge status, per-port cards, and injection port selectors. |
| tools/userial/web/app.css | Adds styles for port badges/cards and refreshed monitor/toolbar layout. |
| tools/userial/src/main.cpp | Implements dual-UART firmware, passthrough forwarding, history ring buffer, and persisted serial settings. |
| tools/userial/src/_assembled.html | Regenerated assembled HTML including updated UI/JS/CSS (build output). |
| build/dev_server.py | Enhances mock WS server to emulate dual-port protocol + rewrites WS URL for split-port dev mode. |
| README.md | Updates tool description to reflect dual-UART bridging capabilities. |
| .gitignore | Ignores dist/ directories to avoid committing local build previews. |
| const entry = normalizeEntry({ ...data, dir: 'RX' }); | ||
| addLogEntry(entry); | ||
| updateTrafficStats(data, true); | ||
| terminalAppend('[' + entry.port + '] ' + decodeDisplayText(entry.ascii) + '\n', 'rx-line'); |
There was a problem hiding this comment.
RX handler normalizes the entry before calling addLogEntry(), but addLogEntry() normalizes again. This duplicates work on every message and makes it easier for the two normalization paths to drift. Consider either passing raw WS data into addLogEntry() (and separately normalizing only for terminal output) or updating addLogEntry() to accept already-normalized entries.
| const entry = normalizeEntry({ ...data, dir: 'RX' }); | ||
| addLogEntry(entry); | ||
| updateTrafficStats(data, true); | ||
| terminalAppend('[' + entry.port + '] ' + decodeDisplayText(entry.ascii) + '\n', 'rx-line'); |
There was a problem hiding this comment.
For RX events, decodeDisplayText(entry.ascii) converts preview sequences like "\n" back into real newlines, and then an additional "\n" is appended. If the payload preview already contains line endings, this produces extra blank lines in the terminal output (and reintroduces carriage returns). Consider either not decoding "\n"/"\r" for the terminal view, or only appending a newline when the decoded payload doesn’t already end with one.
| terminalAppend('[' + entry.port + '] ' + decodeDisplayText(entry.ascii) + '\n', 'rx-line'); | |
| const rxText = decodeDisplayText(entry.ascii); | |
| const rxLineEnding = /[\r\n]$/.test(rxText) ? '' : '\n'; | |
| terminalAppend('[' + entry.port + '] ' + rxText + rxLineEnding, 'rx-line'); |
| @@ -1,19 +1,101 @@ | |||
| /* RS-232 Serial Tool — specific styles */ | |||
There was a problem hiding this comment.
The file header comment still says “RS-232 Serial Tool — specific styles”, but the tool has been renamed/repurposed to dual-UART. Updating this comment will help keep generated assets (_assembled.html) and future maintenance aligned with the current tool behavior.
| /* RS-232 Serial Tool — specific styles */ | |
| /* Dual-UART Tool — specific styles */ |
| Serial.println("\n RS-232 Serial Tool ready."); | ||
| Serial.println(" Waiting for serial data...\n"); | ||
| Serial.printf(" Channel A RX/TX: GPIO%u/GPIO%u\n", channels[0].rxPin, channels[0].txPin); |
There was a problem hiding this comment.
Startup log still prints “RS-232 Serial Tool ready.” even though the tool/UI/config have been renamed to Dual UART. Consider updating the Serial console banner so it matches the current tool name and avoids confusion when debugging.
| HardwareSerial SerialChannelA(1); | ||
| HardwareSerial SerialChannelB(0); | ||
| ChannelState channels[] = { | ||
| {"A", "Channel A", SERIAL_A_RX_PIN, SERIAL_A_TX_PIN, &SerialChannelA, 0, 0}, | ||
| {"B", "Channel B", SERIAL_B_RX_PIN, SERIAL_B_TX_PIN, &SerialChannelB, 0, 0}, |
There was a problem hiding this comment.
Channel B is instantiated as HardwareSerial(0) and later initialized in beginChannel(). On ESP32 Arduino, Serial usually maps to UART0; reconfiguring UART0 (baud/pins) after Serial.begin(115200) can break the USB/serial console and any Serial logging used by toolbox_web/toolbox_wifi. Consider moving Channel B to a different UART index (e.g., 2) or explicitly separating the debug console from UART0 so Serial output remains stable.
| if (len == 0) return; | ||
| channels[channelIndex].uart->write(data, len); | ||
| channels[channelIndex].txBytes += len; | ||
| tbLedFlash(); | ||
|
|
There was a problem hiding this comment.
tbLedFlash() is called immediately after every UART write. Since tbLedFlash() uses delay() (blocking), this can throttle high-throughput serial traffic, increase latency, and potentially cause UART RX buffer overflows/data loss during passthrough. Prefer a non-blocking LED activity indicator (e.g., set a timestamp/flag and blink in tbLedBlink) or make LED flashing conditional/throttled.
| channels[peerIndex].uart->write(buffer, count); | ||
| channels[peerIndex].txBytes += count; | ||
| } | ||
| tbLedFlash(); | ||
| storeHistory(channel.id[0], 'R', forwarded ? channels[peerIndex].id[0] : 0, buffer, count, ts); |
There was a problem hiding this comment.
tbLedFlash() is called during RX handling (and also when forwarding to the peer UART). Since tbLedFlash() blocks via delay(), sustained traffic can slow the loop enough to starve tbWifiLoop()/tbWebLoop() and increase the risk of UART buffer overflow/data loss. Consider replacing this with a non-blocking activity indicator or throttling flashes (e.g., max once per N ms).
| HistoryEntry history[HISTORY_SIZE]; | ||
| size_t historyHead = 0; | ||
| size_t historyCount = 0; |
There was a problem hiding this comment.
PR description mentions persisted serial settings/history, but the firmware only persists serial settings (Preferences) while history is kept only in RAM (history[] ring buffer) and will be lost on reboot. If persistence across reboots is intended, history needs to be stored in Preferences/flash (with wear considerations); otherwise, update the PR description/UI copy to clarify that history is session-only.
Summary
tools/userialwith default channel A pins on GPIO4/GPIO5 and channel B pins on GPIO6/GPIO7dist/output so local preview artifacts are not committedValidation
python build/build_web.py --tool-dir tools/userialpython build/build_web.py --tool-dir tools/wifiscanpio run -e xiao_esp32c3(blocked by PlatformIOHTTPClientErrorwhile installingespressif32in this environment)parallel_validationcompleted with 0 CodeQL alerts