Brings ~55 mod-exclusive files to the upstream-based mod/master-resync branch: Activities (migrated to new ActivityManager pattern): - Clock/Time: SetTimeActivity, SetTimezoneOffsetActivity, NtpSyncActivity - Dictionary: DictionaryDefinitionActivity, DictionarySuggestionsActivity, DictionaryWordSelectActivity, LookedUpWordsActivity - Bookmark: EpubReaderBookmarkSelectionActivity - Book management: BookManageMenuActivity, EndOfBookMenuActivity - OPDS: OpdsServerListActivity, OpdsSettingsActivity - Utility: DirectoryPickerActivity, NumericStepperActivity Utilities (unchanged): - BookManager, BookSettings, BookmarkStore, BootNtpSync - Dictionary, LookupHistory, TimeSync, OpdsServerStore Libraries: PlaceholderCover, TableData, ChapterXPathIndexer Scripts: inject_mod_version, generate_book_icon, preview_placeholder_cover Docs: KOReader sync XPath mapping Migration changes: - ActivityWithSubactivity -> Activity base class - Callback constructors -> finish()/setResult() pattern - enterNewActivity() -> startActivityForResult() - Activity::RenderLock&& -> RenderLock&& These files won't compile yet - they reference mod settings and I18n strings that will be added in subsequent phases. Made-with: Cursor
9.1 KiB
CrossPoint Reader -- Project Summary
This document is a condensed reference for quickly re-familiarizing with the CrossPoint Reader firmware project. It consolidates hardware specs, codebase layout, build/CI details, architecture patterns, and current mod work. For full detail see
hardware.md,file-structure.md, andci-build-and-code-style.mdin this directory.
What This Is
CrossPoint Reader is an open-source, community-driven firmware replacement for the Xteink X4 e-paper reader. It is not affiliated with Xteink. The project's sole mission is focused, high-quality ebook reading -- no apps, games, browsers, or audio. See SCOPE.md for the full boundary definition.
Repository: https://github.com/crosspoint-reader/crosspoint-reader
License: MIT
Governance: GOVERNANCE.md (critique code not people, public-by-default decisions, @daveallie for moderation)
Hardware at a Glance
| Component | Spec |
|---|---|
| MCU | ESP32-C3, RISC-V, single-core |
| RAM | ~380 KB usable (aggressive SD caching required) |
| Flash | 16 MB total, DIO mode |
| Display | 480x800 e-ink, 2-bit grayscale (4 levels), SPI |
| Refresh | FULL (best quality), HALF (~1720ms), FAST (default, custom LUT) |
| Frame buffer | 48,000 bytes, single-buffer mode |
| Buttons | 7 total: 4 front (remappable), 2 side (page nav), 1 power (deep-sleep wake) |
| Storage | SD card via SPI (shared bus with display), SdFat, UTF-8 long filenames |
| Battery | GPIO 0, BatteryMonitor SDK lib, 0-100% |
| WiFi | 802.11 b/g/n 2.4GHz, STA + AP modes |
| USB | USB-C, CDC on boot, connection detection via GPIO 20 |
| Power | Deep sleep with GPIO wakeup, configurable inactivity timeout |
Flash Partition Layout
NVS 0x9000 20KB Key/value storage
OTA Data 0xE000 8KB Boot selection
ota_0 0x10000 6.25MB Primary firmware
ota_1 0x650000 6.25MB Secondary firmware (OTA)
SPIFFS 0xC90000 3.375MB On-flash filesystem
Coredump 0xFF0000 64KB Crash dumps
Key GPIO Assignments
Display SPI: SCLK=8, MOSI=10, CS=21, DC=4, RST=5, BUSY=6, MISO=7 (shared with SD) Battery: GPIO 0 | USB detect: GPIO 20
Architecture Overview
Application Loop
Standard Arduino setup() / loop() in src/main.cpp. The loop polls buttons via HalGPIO, delegates to the current Activity, handles auto-sleep timeout, and power button hold detection. Memory stats are logged every 10s over serial (when USB connected).
Activity System
UI screens are Activity subclasses with lifecycle methods onEnter(), onExit(), loop(). Only one activity is active at a time. Routing functions in main.cpp (onGoHome(), onGoToReader(), etc.) manage transitions by deleting the old activity and creating the new one.
ActivityWithSubactivity provides composition for activities that host child activities (menus, overlays).
Hardware Abstraction Layer (lib/hal/)
Three classes wrap the SDK drivers:
HalDisplay-- display refresh, buffer ops, grayscale, deep sleepHalGPIO-- buttons, battery, USB detection, deep sleep, wakeup reasonHalStorage-- SD card file ops via singletonStorage
Rendering Pipeline
GfxRenderer wraps HalDisplay for drawing operations. Fonts are registered by ID at startup from compiled headers in lib/EpdFont/builtinFonts/. The renderer supports a fadingFix setting.
Data Caching
EPUB data is aggressively cached to SD under .crosspoint/epub_<hash>/ to conserve RAM:
progress.bin-- reading positioncover.bmp-- extracted cover imagebook.bin-- metadata (title, author, spine, TOC)sections/*.bin-- pre-parsed chapter layout data
Cache is NOT auto-cleaned on book deletion. Moving a book file resets its cache/progress.
Key Source Locations
Where to find things
| What | Where |
|---|---|
| Entry point | src/main.cpp -- setup(), loop(), activity routing, font init |
| User settings | src/CrossPointSettings.cpp/.h -- load/save to SD |
| App state | src/CrossPointState.cpp/.h -- open book path, sleep tracking |
| Button mapping | src/MappedInputManager.cpp/.h -- remappable buttons, labels |
| Boot screen | src/activities/boot_sleep/BootActivity.cpp/.h |
| Sleep screen | src/activities/boot_sleep/SleepActivity.cpp/.h |
| Home screen | src/activities/home/HomeActivity.cpp/.h |
| Library browser | src/activities/home/MyLibraryActivity.cpp/.h |
| EPUB reader | src/activities/reader/EpubReaderActivity.cpp/.h |
| Reader menu | src/activities/reader/EpubReaderMenuActivity.cpp/.h |
| TXT reader | src/activities/reader/TxtReaderActivity.cpp/.h |
| XTC reader | src/activities/reader/XtcReaderActivity.cpp/.h |
| Settings | src/activities/settings/SettingsActivity.cpp/.h |
| Button remap | src/activities/settings/ButtonRemapActivity.cpp/.h |
| OTA update UI | src/activities/settings/OtaUpdateActivity.cpp/.h |
| Web server | src/network/CrossPointWebServer.cpp/.h |
| OTA client | src/network/OtaUpdater.cpp/.h |
| HTTP download | src/network/HttpDownloader.cpp/.h |
| Web UI HTML | src/network/html/{HomePage,FilesPage,SettingsPage}.html |
| Themes | src/components/themes/BaseTheme.cpp/.h, lyra/LyraTheme.cpp/.h |
| Theme manager | src/components/UITheme.cpp/.h |
Library code (lib/)
| What | Where |
|---|---|
| EPUB engine | lib/Epub/ -- parsing, rendering, sections, pages |
| EPUB parsers | lib/Epub/Epub/parsers/ -- container, OPF, HTML, TOC (nav+ncx) |
| CSS parser | lib/Epub/Epub/css/CssParser.cpp/.h |
| Hyphenation | lib/Epub/Epub/hyphenation/ -- Liang algorithm, 5 language tries |
| Display HAL | lib/hal/HalDisplay.cpp/.h |
| GPIO HAL | lib/hal/HalGPIO.cpp/.h |
| Storage HAL | lib/hal/HalStorage.cpp/.h |
| Font rendering | lib/EpdFont/EpdFont.cpp/.h |
| Built-in fonts | lib/EpdFont/builtinFonts/ -- Bookerly, NotoSans, OpenDyslexic, Ubuntu |
| Graphics | lib/GfxRenderer/ -- renderer, bitmap, bitmap helpers |
| XML parsing | lib/expat/ |
| ZIP/compression | lib/miniz/, lib/ZipFile/ |
| JPEG decoding | lib/picojpeg/, lib/JpegToBmpConverter/ |
| OPDS parsing | lib/OpdsParser/ |
| KOReader sync | lib/KOReaderSync/ |
| UTF-8 utils | lib/Utf8/ |
SDK (open-x4-sdk/ submodule)
Provides: BatteryMonitor, InputManager, EInkDisplay, SDCardManager
Linked as symlinks in platformio.ini lib_deps.
Build & CI Quick Reference
Build locally
pio run # Dev build (version: 1.0.0-dev)
pio run -e gh_release # Release build (version: 1.0.0)
pio run --target upload # Build and flash via USB
pio check # Run cppcheck static analysis
Code formatting
./bin/clang-format-fix # Format all tracked C/C++ files
./bin/clang-format-fix -g # Format only modified files
Key style rules: 2-space indent, 120-char column limit, K&R braces (Attach), pointer-left (int* x), sorted/regrouped includes, spaces not tabs, LF line endings.
Excludes lib/EpdFont/builtinFonts/ (generated).
CI (GitHub Actions)
On push to master or any PR, 4 parallel jobs run:
- clang-format -- formatting check (clang-format-21)
- cppcheck -- static analysis (fails on low/medium/high)
- build -- compilation + firmware.bin artifact
- test-status -- aggregated PR gate
PR titles must follow semantic format (feat:, fix:, refactor:, etc.).
Releases
- Official: Push a git tag ->
release.ymlbuildsgh_releaseenv -> uploads bootloader, firmware, ELF, map, partitions - RC: Manually trigger
release_candidate.ymlon arelease/*branch -> embeds commit SHA in version
Version scheme
1.0.0-dev # default env (local dev)
1.0.0 # gh_release env (tagged release)
1.0.0-rc+a1b2c3d # gh_release_rc env (release candidate)
Dependencies
| Dependency | Version | Purpose |
|---|---|---|
| espressif32 | 6.12.0 | PlatformIO platform |
| ArduinoJson | 7.4.2 | JSON parsing |
| QRCode | 0.0.1 | QR code generation |
| WebSockets | 2.7.3 | WebSocket server |
Pre-build step
scripts/build_html.py minifies src/network/html/*.html -> .generated.h PROGMEM strings.
Debugging
python3 scripts/debugging_monitor.py # Linux
python3 scripts/debugging_monitor.py /dev/cu.usbmodem2101 # macOS
Requires: pyserial, colorama, matplotlib.
Supported Document Formats
- EPUB (primary) -- EPUB 2 and EPUB 3, CSS subset, hyphenation (EN, DE, ES, FR, RU)
- TXT -- plain text
- XTC -- proprietary format with chapter support
- Image support within EPUB is listed as incomplete (per README checklist)
Constraints to Remember
- ~380KB RAM -- everything large must be cached to SD card
- Single-core CPU -- WiFi and main loop compete for cycles; no true background tasks
- 6.25MB firmware slot -- maximum firmware binary size
- 48KB frame buffer -- 1-bit per pixel in normal mode, 2-bit for grayscale
- Shared SPI bus -- display and SD card share MISO; cannot access simultaneously
- No PSRAM -- all memory is internal SRAM
- Font headers are generated -- do not hand-edit
lib/EpdFont/builtinFonts/(excluded from formatting) - HTML headers are generated --
.generated.hfiles insrc/network/html/are auto-built from.htmlfiles