Architecture Overview
CrossInk is firmware for the Xteink X4 and X3, built with PlatformIO targeting the ESP32-C3 microcontroller.
At a high level, it is firmware that uses an activity-driven application architecture loop with persistent settings/state, SD-card-first caching, and a rendering pipeline optimized for e-ink constraints.
System at a glance
graph TD
A[Hardware: ESP32-C3 + SD + E-ink + Buttons] --> B[open-x4-sdk]
B --> C[lib/hal wrappers]
C --> D[src/main.cpp runtime loop]
D --> E[Activities layer]
D --> F[State and settings]
E --> G[Reader flows]
E --> H[Home/Library/Settings flows]
E --> I[Network/Web server flows]
G --> J[lib/Epub parsing + layout + hyphenation]
J --> K[SD cache in .crosspoint]
E --> L[GfxRenderer]
L --> M[E-ink display buffer]
Runtime lifecycle
Primary entry point is src/main.cpp.
flowchart TD
A[Boot] --> B[Init GPIO and optional serial]
B --> C[Init SD storage]
C --> D[Load settings and app state]
D --> E[Init display and fonts]
E --> F{Resume reader?}
F -->|No| G[Enter Home activity]
F -->|Yes| H[Enter Reader activity]
G --> I[Main loop]
H --> I
I --> J[Poll input and run current activity]
J --> K{Sleep condition met?}
K -->|No| I
K -->|Yes| L[Persist state and enter deep sleep]
In each loop iteration, the firmware updates input, runs the active activity, handles auto-sleep/power behavior, and applies a short delay policy to balance responsiveness and power.
Activity model
Activities are screen-level controllers deriving from src/activities/Activity.h. Nested flows use the ActivityManager stack with startActivityForResult(), setResult(), and finish().
onEnter()andonExit()manage setup/teardownloop()handles per-frame behaviorskipLoopDelay()andpreventAutoSleep()are used by long-running flows (for example web server mode)
Top-level activity groups:
src/activities/home/: home and library navigationsrc/activities/reader/: EPUB/XTC/TXT reading flowssrc/activities/settings/: settings menus and configurationsrc/activities/network/: Wi-Fi selection, AP/STA mode, file transfer serversrc/activities/boot_sleep/: boot and sleep transitions
Reader and content pipeline
Reader orchestration starts in src/activities/reader/ReaderActivity.h and dispatches to format-specific readers. EPUB processing is implemented in lib/Epub/.
flowchart TD
A[Select book] --> B[ReaderActivity]
B --> C{Format}
C -->|EPUB| D[EPUB loader]
C -->|XTC| X[XTC reader]
C -->|TXT| T[TXT reader]
D --> E[Metadata and TOC]
E --> F[CSS rules]
F --> G[Section layout]
G --> H[Page cache]
H --> I[Page model]
I --> J[GfxRenderer]
J --> K[E-ink display]
X --> I
T --> I
For EPUBs, the metadata step reads or writes book.bin, the CSS step reads or writes css_rules.cache, and the section layout step writes sections/*.bin.
Why caching matters:
- RAM is limited on ESP32-C3, so expensive parsed/layout data is persisted to SD
- repeat opens/page navigation can reuse cached data instead of full reparsing
Reader internals call graph
This diagram zooms into the EPUB path to show the main control and data flow from activity entry to on-screen draw.
flowchart TD
A[ReaderActivity onEnter] --> B{File type}
B -->|EPUB| C[Create Epub object]
B -->|XTC/TXT| Z[Use format-specific reader]
C --> D[Epub load]
D --> E[Locate container and OPF]
E --> F[Build or load BookMetadataCache]
F --> G[Load TOC and spine]
G --> H[Load CSS cache or parse manifest/base-dir CSS]
H --> I[EpubReaderActivity]
I --> J{Section cache exists for current settings?}
J -->|Yes| K[Read section bin from SD cache]
J -->|No| L[Parse chapter HTML and layout text]
L --> M[Apply typography settings and hyphenation]
M --> N[Write section cache bin]
K --> O[Build page model]
N --> O
O --> P[GfxRenderer draw calls]
P --> Q[HAL display framebuffer update]
Q --> R[E-ink refresh policy]
S[SETTINGS singleton] -. influences .-> J
S -. influences .-> M
T[APP_STATE singleton] -. persists .-> U[Reading progress and resume context]
U -. used by .-> I
Notes:
- CSS files are collected from the OPF manifest and, when needed, discovered by streaming ZIP paths under the OPF content base directory; the firmware avoids preloading the full ZIP central directory for large books.
- “section cache exists” depends on cache-busting parameters such as font, viewport size, paragraph alignment, forced paragraph indents, hyphenation, embedded CSS, image rendering, Bionic Reading, and Guide Dots settings
- rendering favors reusing precomputed layout data to keep page turns responsive on constrained hardware
- progress/session state is persisted so the reader can reopen at the last position after reboot/sleep
State and persistence
Two singletons are central:
src/CrossPointSettings.h(SETTINGS): user preferences and behavior flagssrc/CrossPointState.h(APP_STATE): runtime/session state such as current book and sleep context
Most SD-card persistence lives under /.crosspoint/. See file inventory in docs/data-cache.md; for binary cache formats, see docs/file-formats.md.
Networking architecture
Network file transfer is controlled by src/activities/network/CrossPointWebServerActivity.h and served by src/network/CrossPointWebServer.h.
Modes:
- STA: join existing Wi-Fi network
- AP: create hotspot
- Calibre Wireless: STA flow specialized for Calibre plugin uploads
Server behavior:
- HTTP server on port 80
- WebSocket upload server on port 81
- WebDAV handler on the HTTP server
- UDP discovery listener for upload clients
- file operations backed by SD storage
- browser APIs for file management, settings, fonts, OPDS servers, and saved Wi-Fi networks
- activity requests faster loop responsiveness while server is running
Endpoint reference: docs/webserver-endpoints.md.
Build-time generated assets
Some sources are generated and should not be edited manually.
scripts/build_web.pygeneratessrc/network/html/*.generated.hfrom theweb/sourcesscripts/gen_i18n.pygenerateslib/I18n/I18nKeys.h,I18nStrings.h, andI18nStrings.cppscripts/generate_hyphenation_trie.pygenerates hyphenation headers underlib/Epub/Epub/hyphenation/generated/
When editing related source assets, regenerate via normal build steps/scripts.
Key directories
src/: app orchestration, settings/state, and activity implementationssrc/network/: web server and OTA/update networkingsrc/components/: theming and shared UI componentslib/hal/: hardware abstraction wrappers around open-x4-sdklib/Epub/: EPUB parser, layout, CSS handling, and hyphenationlib/: supporting libraries (fonts, text, filesystem helpers, etc.)open-x4-sdk/: hardware SDK submodule (display, input, storage, battery)docs/: user and technical documentation
Embedded constraints that shape design
- constrained RAM drives SD-first caching and careful allocations
- e-ink refresh cost drives render/update batching choices
- main loop responsiveness matters for input, power handling, and watchdog safety
- background/network flows must cooperate with sleep and loop timing logic
Scope guardrails
Before implementing larger ideas, check: