Skip to content

Add experimental Xteink X3 camera remote support - #313

Open
LittleBidet wants to merge 2 commits into
gkoh:masterfrom
LittleBidet:feat/xteink-x3-port
Open

LittleBidet wants to merge 2 commits into
gkoh:masterfrom
LittleBidet:feat/xteink-x3-port

Conversation

@LittleBidet

@LittleBidet LittleBidet commented Oct 8, 2026 •

Copy link
Copy Markdown

Summary

Add experimental Xteink X3 support as dedicated ESP32-C3 camera-remote firmware, replacing the ebook reader application. The portrait e-ink interface provides front-button navigation, a dedicated right-side shutter button, camera discovery, saved connections, focus, bulb lock, and an intervalometer.

Includes X3 build/release and web-installer support, UC8253/UC8279d display drivers, battery reporting and power-button deep sleep, and PlatformIO installation instructions. X3 supports up to two camera connections; reader functions, SD storage, GPS and OTA are not exposed. Automatic light sleep and dynamic frequency scaling are not enabled.

Shared control changes and M5 behavior

E-ink refreshes can outlast a button press. X3 polls input and advances interval timing separately from rendering, with another worker handling scanning and connections. The shared layer owns camera lifetimes and command queues, so synchronization and cancellation handling also affect existing M5 targets.

The M5 behavior changes are:

  • An empty target set now leads to STATE_CONNECT_FAILED. Previously, an empty vector satisfied allConnected() and could open an empty connected menu.
  • The reconnect failure count is a member reset by each explicit connectAll(bool) call. The previous function-static count leaked across sessions.
  • Connection generations discard stale queued commands after cancellation or reconnect. Presses submitted outside STATE_ACTIVE are rejected instead of queued; accepted release requests are preserved through reconnect.
  • UI::doConnect() returns early outside STATE_IDLE. Failure to add a target or start a connection calls doDisconnect() to clean up partial setup.
  • updateGPS() uses a nonblocking mutex attempt and drops that update when connection work holds the mutex, keeping the UI responsive.
  • Each web-installer manifest now declares one matching chipFamily. Previously, each M5 manifest offered both ESP32 and ESP32-S3 entries using the same board binaries. ESP Web Tools can now refuse an incompatible chip selection.

Queue overflow rejects the affected press without permanently disabling future presses. Releases that cannot be queued are recorded for retry and report acceptance consistently. Dropping one camera does not automatically release every target; explicit releases can reach still-connected cameras during reconnect without waiting for the connection mutex. Target writes check connectivity, and cumulative failure counters keep X3 command errors observable across overwritten status snapshots.

X3 startup failures use a board-neutral fatal hook with best-effort deep sleep instead of repeated rebooting; the default M5 handler remains abort(). The follow-up also separates the display-independent interval timer name from the M5 UI class, removes renderer title-string detection and dead lifecycle cases, and corrects font licensing/source metadata.

Validation

  • Initial hardware bring-up was tested on an Xteink X3 with a UC8253 panel and Fujifilm X-T4. All three firmware images were verified by readback; startup logs showed successful panel detection without display errors or a reboot loop.
  • The initial port was built for all six environments. The latest follow-up changes were rebuilt for Xteink X3 and M5Stick-C.
  • Local control, interval timing, X3 app and renderer checks passed, including accepted releases during a stalled reconnect and persistent error reporting through overwritten snapshots. Formatting and diff checks passed. The validation harness remains local and is not included in this contribution.

The latest follow-up still needs hardware regression testing. UC8279d panel behavior, multi-camera behavior, battery accuracy and sleep/wake behavior need hardware validation. Testing one camera/device combination does not establish compatibility with every supported camera.

Assisted-by: OpenAI Codex

Add native ESP32-C3 display and input support with a portrait UI and
right-side shutter control. Separate shutter timing from e-ink refresh,
harden shared camera lifecycle handling, and add build support,
installer metadata, and installation notes.

The X3 polls buttons and schedules intervals independently of display
refreshes, while a separate worker handles scanning and connections. This
keeps slow e-ink updates from delaying input polling or interval scheduling,
but means status reads, camera-list updates and disconnect requests can
occur concurrently. The shared control layer therefore uses synchronized
state and copied status/list snapshots for the X3 interface.

Commands carry a connection generation so queued presses from an old
session are discarded after cancellation or reconnect. Queue-overflow
handling requests focus/shutter release without blocking the input task,
and target shutdown releases held controls. These changes belong in the
shared layer because it owns the command queues and camera lifetimes;
display-only changes cannot address these races. They also affect M5
targets, so their existing behavior needs regression review.

Validated with all six target builds and sanitizers. Corrected
GPIO and UC8253 probe behavior during physical X3 bring-up; portrait images
flashed and verified. User-tested on an Xteink X3 with a Fujifilm X-T4.

Assisted-by: OpenAI Codex
Keep GPS updates nonblocking during connection work, preserve accepted
releases across reconnect and queue overflow, and report command failures
with a cumulative counter. Handle M5 connection setup failures and use a
board-neutral fatal hook for X3 startup shutdown.

Rename the display-independent interval timer, simplify X3 lifecycle and
renderer handling, align header guards, and update README and font metadata.
Keep validation harnesses outside the contribution.

Assisted-by: OpenAI Codex

This branch has not been deployed

No deployments
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.

1 participant