Skip to content

Speed up and harden USB/Bluetooth remote control#354

Open
GrzegorzZajac000 wants to merge 3 commits into
esp32-si4732:mainfrom
GrzegorzZajac000:usb-ble-remote-speedup
Open

Speed up and harden USB/Bluetooth remote control#354
GrzegorzZajac000 wants to merge 3 commits into
esp32-si4732:mainfrom
GrzegorzZajac000:usb-ble-remote-speedup

Conversation

@GrzegorzZajac000

Copy link
Copy Markdown
Contributor

Faster, more robust USB/Bluetooth remote control (screenshots + protocol hardening)

Summary

This PR improves the speed and reliability of the serial/BLE remote-control path
(Remote.cpp and the BLE modules) without changing any existing behaviour on the
wire. The headline items are a much faster screenshot capture, a new compact
binary screenshot command, and several fixes that stop the cooperative main loop
from stalling or watchdog-rebooting during remote transfers.

All changes compile on both PSRAM profiles (esp32s3-ospi, esp32s3-qspi) and
both hardware variants (standard SI4732 Mini/Pocket and LILYGO_SI473X), with no
new #if guards.

Screenshot capture

  • Faster C (hex BMP) capture — byte-for-byte identical output.
    The pixel loop previously issued 320 × 170 = 54,400 readPixel() + printf("%04x", …)
    calls plus 170 println() calls per capture. It now reads the sprite framebuffer
    directly via spr.getPointer(), formats each row with a nibble lookup table, and
    emits one stream->write() per row — ~170 stream operations instead of ~54,570.
    The emitted bytes are unchanged (the stored framebuffer word equals
    htons(readPixel(x,y)), and the nibble LUT reproduces %04x exactly), so every
    existing consumer keeps working.

  • New binary screenshot command c. Emits the same image as a raw little-endian
    RGB565 BMP, preceded by a short ASCII frame BMP:<size>\r\n. It is about half the
    bytes on the wire of the hex C command (~108 KB vs ~218 KB) and decodes to a
    byte-identical image (equivalent to xxd-decoding the C output). C is left
    completely unchanged; c is purely additive.

  • Larger USB CDC TX ring buffer. Serial.setTxBufferSize(4096) is set before
    Serial.begin() so bulk output (screenshots) drains more smoothly with fewer
    producer stalls. A comment also documents that the 115200 argument is only a CDC
    line-coding label under USBMode=hwcdc and does not limit throughput.

Remote-protocol robustness (USB + BLE)

  • No more watchdog reboot on a mid-command BLE disconnect. remoteReadChar() and
    the multi-byte parsers (remoteReadInteger / remoteReadString / expectNewline)
    previously busy-spun forever if the link dropped while a command (F…, #…, ^…)
    was only partially received. They now wait with a bounded deadline and yield with
    delay(1), so a disconnect degrades gracefully instead of starving the loop into a
    task-watchdog reset. Interactive multi-byte commands typed a key at a time still
    work, because the parsers still block while data is genuinely arriving.
    (The peek() comparisons were also made independent of char signedness.)

  • $ memory dump no longer freezes the UI over BLE. The dump now streams one
    populated slot per loop tick instead of pushing all slots in a single blocking
    burst (which froze encoder/display/RDS for ~1.7 s on BLE). The wire format is
    unchanged.

  • Error replies no longer echo leftover input. remoteShowError() drains the
    remaining input silently instead of echoing each leftover byte back before the
    Error: line.

  • Minor: remoteTickTime() reads millis() once per tick instead of twice.

Bluetooth LE

  • HID scan duty cycle reduced 100% → 25% (interval 400 ms / window 100 ms instead
    of 100 ms / 100 ms). This lowers the RF the 2.4 GHz radio radiates next to the
    SI4732 antenna while scanning, at the cost of slightly longer (imperceptible)
    one-time pairing discovery.

  • BLE central TX power set to 0 dBm (ESP_PWR_LVL_N0), matching the peripheral,
    instead of the stack default (~+9 dBm).

  • Removed blocking delay(500) calls (and a blank-screen flash) on the HID scan and
    connect paths.
    The status message is drawn once and persists until the next
    redraw, so the loop stays responsive during pairing.

Docs & changelog

  • docs/source/remote.md: documents the new c command and the stable C output
    format, and recommends socat -T5 (idle timeout) plus a note that screenshots over
    BLE are slow.
  • Changelog fragments added under changelog/.

Compatibility / risk

  • C output is byte-for-byte identical to before; c is a new, previously-unused
    command letter, so no existing consumer is affected.
  • No protocol change for any existing command; the $ dump format is unchanged.
  • Builds verified for esp32s3-ospi, esp32s3-qspi, and the LILYGO_SI473X and
    HALF_STEP compile-time options.

Testing

  • Compiled all four build combinations above with arduino-cli (pinned core/libraries
    from sketch.yaml).
  • Verified off-device that the c binary output is byte-identical to xxd-decoding
    the C output and that the resulting BMP header is well-formed.
  • Docs build passes with --fail-on-warning --nitpicky.

Copilot AI review requested due to automatic review settings June 18, 2026 15:35

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the performance and robustness of the USB/BLE remote-control pathway by optimizing screenshot streaming, adding a new compact binary screenshot command, and preventing main-loop stalls during partial/failed remote transfers (including over BLE).

Changes:

  • Speed up existing C screenshot capture (hex BMP) by streaming rows from the framebuffer with far fewer stream operations, while keeping output stable.
  • Add new c command for binary BMP screenshots with a simple ASCII framing line to reduce on-wire size.
  • Harden remote parsing and BLE behaviors to avoid watchdog resets and reduce UI stalls (chunked $ dump, bounded waits, reduced HID scan duty cycle, TX power adjustment, removed blocking delays).

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
docs/source/remote.md Documents new c command and clarifies screenshot formats and usage examples.
changelog/+screenshot-speed.changed.md Changelog entry for faster C screenshot path and larger USB TX buffer.
changelog/+screenshot-binary.added.md Changelog entry for new binary screenshot command c.
changelog/+remote-protocol-robustness.fixed.md Changelog entry for remote protocol hardening and $ dump responsiveness fixes.
changelog/+ble-scan-rf.changed.md Changelog entry for BLE HID scan duty cycle, TX power, and responsiveness improvements.
ats-mini/Remote.h Adds state and API for chunked $ memory dump tick.
ats-mini/Remote.cpp Implements faster C, new binary c, bounded read/peek waits, chunked $ dump, and less chatty error draining.
ats-mini/BleMode.cpp Integrates remote tick + chunked memory dump tick into BLE ad-hoc mode; removes blocking delay/flash in HID connect UI.
ats-mini/BleHidCentral.h Adjusts BLE scan interval/window to reduce duty cycle; documents rationale.
ats-mini/BleHidCentral.cpp Removes blocking delay/blank-screen flash during HID scan start.
ats-mini/BleCentral.cpp Sets BLE central TX power to 0 dBm to match peripheral.
ats-mini/ats-mini.ino Enlarges USB CDC TX buffer before Serial.begin() and documents why.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/source/remote.md Outdated
`c` writes the same image as a raw little-endian BMP, preceded by an ASCII frame `BMP:<size>\r\n` so a reader can find the start of the binary and pre-allocate. The decoded file is byte-for-byte identical to `xxd`-decoding the `C` output, in half the bytes:

```shell
echo -n c | socat -T5 stdio /dev/cu.usbmodem14401,echo=0,raw | tail -c +$(( $(printf 'BMP:%s\r\n' 0 | wc -c) )) > /tmp/screenshot.bmp
Comment thread ats-mini/BleMode.cpp Outdated
Comment on lines 58 to 63
if (BLESerial.isConnected())
{
remoteTickTime(&BLESerial, &remoteBLEState);
remoteMemoryDumpTick(&BLESerial, &remoteBLEState);
}
if (!BLESerial.isConnected()) return 0;
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.

2 participants