Compare commits

..

131 Commits

Author SHA1 Message Date
cottongin
3853bfe113
feat: widen battery icons and add charging indicator
Some checks are pending
CI / build (push) Waiting to run
- Increase battery width to 1.5x original (small: 15→23px, large: 20→30px)
- Add lightning bolt overlay when USB/charging detected
- Bolt traced from SVG, centered in fill area regardless of charge level
- Add isUsbConnected() to MappedInputManager for charging detection
- Update layout spacing constants for wider battery
2026-02-03 20:11:28 -05:00
cottongin
fbe7d2feb4
release: ef-1.0.5 - stability, memory, and upstream merges
All checks were successful
CI / build (push) Successful in 4m51s
Compile Release / build-release (push) Successful in 1m18s
Webserver: JSON batching, removed MD5 blocking, simplified flow control
Memory: QR code caching, WiFi scan optimization, cover buffer leak fix
EPUB: Fixed errant underlining before styled inline elements
Flash screen: Version string overflow fix, half refresh for cleaner display

Upstream merges:
- PR #522: HAL abstraction layer (HalDisplay, HalGPIO)
- PR #603: Sunlight fading fix toggle in Display settings
2026-01-30 23:20:23 -05:00
cottongin
520a0cb124
feat: implement sunlight fading fix (PR #603)
Add user-toggleable setting to turn off display between refreshes,
which helps mitigate the sunlight fading issue on e-ink displays.

Changes:
- Add turnOffScreen parameter to HalDisplay methods
- Add fadingFix member and setFadingFix() to GfxRenderer
- Add fadingFix setting to CrossPointSettings with persistence
- Add "Sunlight Fading Fix" toggle in Display settings
- Update SDK submodule with turnOffScreen support
2026-01-30 23:02:29 -05:00
cottongin
be8b02efd6
feat: merge PR #522 - add HalDisplay and HalGPIO abstraction layer
Cherry-picked upstream PR #522 (da4d3b5) with conflict resolution:
- Added new lib/hal/ files (HalDisplay, HalGPIO)
- Updated GfxRenderer to use HalDisplay, preserving base viewable margins
- Adopted PR #522's MappedInputManager lookup table implementation
- Updated main.cpp to use HAL while preserving custom Serial initialization
- Updated all EInkDisplay::RefreshMode references to HalDisplay::RefreshMode

This introduces a Hardware Abstraction Layer for display and GPIO,
enabling easier emulation and testing.
2026-01-30 22:49:52 -05:00
cottongin
448ce55bb4
Add individual book cache clearing with preserve progress option
- Add "Clear Cache" option to book action menu in MyLibrary (both Recent and Files tabs)
- Prompt user to preserve reading progress when clearing cache
- Always preserve bookmarks when clearing individual book cache
- Add preserve progress option to system-level Clear Cache in Settings
- Implement BookManager::clearBookCache() for selective cache clearing
2026-01-30 22:22:22 -05:00
cottongin
5464d9de3a
fix: webserver stability, memory leaks, epub underlining, flash screen
Webserver:
- Remove MD5 hash computation from file listings (caused EAGAIN errors)
- Implement JSON batching (2KB) with pacing for file listings
- Simplify sendContentSafe() flow control

Memory:
- Cache QR codes on server start instead of regenerating per render
- Optimize WiFi scan: vector deduplication, 20 network limit, early scanDelete()
- Fix 48KB cover buffer leak when navigating Home -> File Transfer

EPUB Reader:
- Fix errant underlining by flushing partWordBuffer before style changes
- Text before styled inline elements (e.g., <a> with CSS underline) no longer
  incorrectly receives the element's styling

Flash Screen:
- Fix version string buffer overflow (30 -> 50 char limit)
- Use half refresh for cleaner display
- Adjust pre_flash.py timing for half refresh completion
2026-01-30 22:00:15 -05:00
cottongin
48267ad848
release: ef-1.0.4
All checks were successful
CI / build (push) Successful in 4m11s
Compile Release / build-release (push) Successful in 1m14s
New Features:
- End-of-book "Start Over" option to wrap to first page

EPUB Rendering:
- CSS margin-left/padding-left parsing for block indentation
- Vertical bar and italic styling for blockquotes
- Left margin indentation for list items
- Fix ordered lists showing bullets instead of numbers
- Fix nested <p> inside <li> marker placement

Bug Fixes:
- Webserver: flow control and connection checking for file listing
- Webserver: memory optimization for File Transfer mode
- Dictionary: allocation order fix for zip dictionary buffer
2026-01-29 19:59:17 -05:00
cottongin
dd630dcf72
Improve EPUB rendering and add end-of-book Start Over
EPUB rendering improvements:
- Add margin-left/padding-left CSS parsing for block indentation
- Add vertical bar and italic styling for blockquotes
- Add left margin indentation for list items (ol/ul)
- Fix ordered lists showing bullets instead of numbers
- Fix nested <p> inside <li> causing marker on separate line

End-of-book improvements:
- Add "Start Over" option to wrap to first page when pressing next
- Show "Start Over" button hint on finished book prompt
2026-01-29 19:45:58 -05:00
cottongin
ef705d3ac6
Fix zip dictionary allocation 2026-01-29 18:54:01 -05:00
cottongin
bab374a675
fixes webserver uploads and general stability 2026-01-29 17:57:56 -05:00
cottongin
c171813045
release: ef-1.0.3
All checks were successful
CI / build (push) Successful in 2m47s
Compile Release / build-release (push) Successful in 1m16s
- Fixed cppcheck CI failure: removed unused screenWidth variable
- Version bump to 0.15.ef-1.0.3
2026-01-29 13:24:21 -05:00
cottongin
d5e42b9e40
Merge staging: ef-1.0.1 and ef-1.0.2
Some checks failed
Compile Release / build-release (push) Successful in 1m22s
CI / build (push) Failing after 1m38s
ef-1.0.2 - Quick Menu Enhancements
- Screen rotation toggle (Portrait/Landscape CCW)
- Customizable menu order with pick-and-place reordering
- Navigation button hints on quick menu

ef-1.0.1 - Dictionary Stability & UX
- Fixed dictionary crashes from heap fragmentation
- Refactored TextBlock/ParsedText to std::vector (~12x fewer allocations)
- Uncompressed .dict support, chunked HTML parsing
- Orientation-aware button hints on dictionary screens
2026-01-29 13:09:57 -05:00
cottongin
168c8fdb69
staging: 1.0.2 2026-01-29 13:01:59 -05:00
cottongin
492cf976f5
feat(quickmenu): comprehensive quick menu enhancements
Quick Menu UI Improvements:
- Add navigation button hints (prev/next on front buttons, up/down on side buttons)
- Fix orientation-aware margins for button hint areas in landscape modes

Screen Rotation Toggle:
- Add "Rotate Screen" option to toggle between Portrait and Landscape CCW
- Force section reindex when orientation changes to properly reflow content
- Position is automatically restored via content offset after reindex

Customizable Menu Order:
- Add "Edit List Order" option (fixed at bottom of menu)
- Pick-and-place reordering: select item to move, navigate to destination, place
- Visual feedback: filled highlight for cursor, outlined box for item being moved
- Menu order persists in settings (quickMenuOrder array in CrossPointSettings)
- New default order: Bookmark, Dictionary, Rotate Screen, Settings, Clear Cache

Files changed:
- CrossPointSettings.h: Add quickMenuOrder[5] setting
- QuickMenuActivity.h/cpp: Edit mode, order rendering, pick-and-place logic
- EpubReaderActivity.cpp: Handle TOGGLE_ORIENTATION action with section reset
2026-01-29 12:57:37 -05:00
cottongin
25e255af50
staging area for 1.0.1 release 2026-01-29 11:58:28 -05:00
cottongin
a4adbb9dfe
fix(dictionary): comprehensive dictionary fixes for stability and UX
This commit completes a series of fixes addressing dictionary crashes,
memory issues, and UI/UX improvements.

Memory & Stability (from previous checkpoints):
- Add uncompressed dictionary (.dict) support to avoid decompression
  memory issues with large dictzip chunks (58KB -> direct read)
- Implement chunked on-demand HTML parsing for large definitions,
  parsing pages as user navigates rather than all at once
- Refactor TextBlock/ParsedText from std::list to std::vector,
  reducing heap allocations by ~12x per TextBlock and eliminating
  crashes from repeated page navigation due to heap fragmentation
- Limit cached pages to MAX_CACHED_PAGES (4) with re-parse capability
  for backward navigation beyond the cache window

UI/Layout Fixes (this commit):
- Restore DictionaryMargins.h for proper orientation-aware button
  hint space (front buttons: 45px, side buttons: 50px)
- Add side button hints to definition screen with proper "<" / ">"
  labels for page navigation
- Add side button hints to word selection screen ("UP"/"DOWN" labels,
  borderless, small font, 2px edge margin)
- Add side button hints to dictionary menu ("< Prev", "Next >")
- Fix double-button press bug when loading new chunks by checking
  forward navigation availability after parsing instead of page count
- Add drawSideButtonHints() drawBorder parameter for minimal hints
- Add drawTextRotated90CCW() for LandscapeCCW text orientation
- Move page indicator up to avoid bezel cutoff
2026-01-29 11:39:49 -05:00
cottongin
6ceba56620
checkpoint: refactor TextBlock/ParsedText from std::list to std::vector
Reduces heap fragmentation by ~12x fewer allocations per TextBlock.
This fixes crashes when repeatedly navigating dictionary pages.

- Replace std::list with std::vector in TextBlock members
- Replace splice() with move+erase in ParsedText::extractLine()
- Use index-based access in hyphenateWordAtIndex()
2026-01-29 09:52:30 -05:00
cottongin
62643ae933
checkpoint: pre list-to-vector refactor, fixes dictionary crash, mostly
- Add uncompressed dictionary (.dict) file support to avoid decompression memory issues
- Implement chunked on-demand parsing for large definitions
- Add backward navigation with re-parse capability
- Limit cached pages to MAX_CACHED_PAGES (4) to prevent memory exhaustion
- Add helper script for extracting/recompressing dictzip files
2026-01-29 09:33:40 -05:00
cottongin
8b41dccfb9
adjust .gitignore 2026-01-28 19:10:25 -05:00
cottongin
3204fa0339
fixes crash 2026-01-28 19:07:21 -05:00
cottongin
bc6dc357eb
release: ef-0.15.99
All checks were successful
CI / build (push) Successful in 2m22s
Compile Release / build-release (push) Successful in 1m20s
First milestone release of the crosspoint-ef fork.

Key features:
- 14+ major enhancements over upstream 0.16.0
- Comprehensive documentation (crosspoint-ef-features.md, user guide)
- Fixed USB Serial blocking when device booted without USB connected
- Non-blocking Serial handling for ESP32-C3 USB CDC

See docs/crosspoint-ef-features.md for the complete feature list.
2026-01-28 17:49:20 -05:00
cottongin
ffe2aebd7e
fix: guard Serial input calls when USB not connected at boot
Fixes device hanging when booted without USB connected. The root cause
was calling Serial.available() and Serial.read() in checkForFlashCommand()
when Serial.begin() was never called (USB not connected at boot).

Changes:
- Add if (!Serial) return guard to checkForFlashCommand()
- Restore upstream while (!Serial) wait loop with 3s timeout
- Remove Serial.setTxTimeoutMs(0) (not in upstream, may cause issues)
- Remove unnecessary if (Serial) guards from EpubReaderActivity.cpp
  (Serial.printf is safe without guards, only input calls need them)

Key insight: Serial.printf() is safe without guards (returns 0 when not
initialized), but Serial.available()/Serial.read() cause undefined
behavior on ESP32-C3 USB CDC when called without Serial.begin().

See: claude_notes/usb-serial-blocking-fix-2026-01-28.md
2026-01-28 17:45:00 -05:00
cottongin
4965e63ad4
chore: remove chat-summaries from git tracking
All checks were successful
CI / build (push) Successful in 2m20s
These files are now gitignored as they contain session-specific notes.
2026-01-28 16:23:34 -05:00
cottongin
4db384edb6
fix: prevent Serial.printf from blocking when USB disconnected
All checks were successful
CI / build (push) Successful in 2m23s
On ESP32-C3 with USB CDC, Serial.printf() blocks indefinitely when USB
is not connected. This caused device freezes when booted without USB.

Solution: Call Serial.setTxTimeoutMs(0) after Serial.begin() to make
all Serial output non-blocking.

Also added if (Serial) guards to high-traffic logging paths in
EpubReaderActivity as belt-and-suspenders protection.

Includes documentation of the debugging process and Serial call inventory.

Also applies clang-format to fix pre-existing formatting issues.
2026-01-28 16:16:11 -05:00
cottongin
f3075002c1
style: reduce variable scope in EpubReaderActivity
Some checks failed
CI / build (push) Failing after 2m31s
Move cachedRenderer, cachedMappedInput, and cachedSection declarations
into the DICTIONARY action block where they're actually used, addressing
cppcheck variableScope warnings.
2026-01-28 10:22:01 -05:00
cottongin
3e3be8bd23
fix: correct type names and restore cached variables
Some checks failed
CI / build (push) Failing after 2m4s
2026-01-28 10:13:06 -05:00
cottongin
800b07a2e5
docs: add AI assistance disclaimer
Some checks failed
CI / build (push) Failing after 4m13s
2026-01-28 10:08:13 -05:00
cottongin
2a31559747
docs: add fork notice and documentation
Some checks failed
CI / build (push) Failing after 3m43s
- Add crosspoint-ef fork notice to README with links to upstream
- Include feature overview, user guide, and technical comparison docs
2026-01-28 10:03:45 -05:00
cottongin
c052512b1b
chore: point SDK submodule to Gitea fork
Some checks failed
CI / build (push) Failing after 2m45s
Switch from upstream GitHub repo to our Gitea fork which includes:
- SDCardManager.rename() method for archive feature
- EInkDisplay grayscale improvements
2026-01-28 09:58:23 -05:00
cottongin
bd95bfd44d
style: fix all cppcheck warnings
Some checks failed
CI / build (push) Failing after 3m20s
- Fix ignored return value in TxtReaderActivity
- Remove unused variables across multiple files
- Add const correctness to DictionaryMargins and EpubReaderActivity
- Replace inefficient substr patterns with resize+append
- Use STL algorithms (find_if, any_of, copy_if, transform) where applicable
- Remove dead sync placeholder code in EpubReaderChapterSelectionActivity
- Add cppcheck suppression for ValueFlow analysis limitation

Resolves all low, medium, and high severity cppcheck defects.
2026-01-28 09:45:42 -05:00
cottongin
fe446d4690
fix(ci): use system Python instead of setup-python action
Some checks failed
CI / build (push) Failing after 3m13s
The setup-python action has hardcoded paths that fail on self-hosted
macOS runners. Use system Python directly instead.

Also simplified clang-format step to use system version if available.
2026-01-28 05:20:19 -05:00
cottongin
23e73312b4
fix(ci): set RUNNER_TOOL_CACHE for setup-python action
Some checks failed
CI / build (push) Failing after 19s
The setup-python action defaults to /Users/runner which doesn't exist
on self-hosted runners. Set RUNNER_TOOL_CACHE to a writable temp path.
2026-01-28 05:17:54 -05:00
cottongin
e8d332e34f
ci: add Gitea Actions workflows
Some checks failed
CI / build (push) Failing after 51s
Adapt GitHub Actions workflows for self-hosted Gitea instance:
- CI workflow with PlatformIO build, cppcheck, and clang-format
- PR title format checker using conventional commits
- Release workflow for tagged builds

Keeps original .github/workflows/ for upstream compatibility.
2026-01-28 05:12:49 -05:00
cottongin
54004d5a5b
chore: cleanup empty unused file 2026-01-28 03:16:06 -05:00
cottongin
d6e17c09ca
typo 2026-01-28 03:14:19 -05:00
cottongin
7288e6499d
chore: Stop tracking personal notes file
Add CrossPoint-ef.md to .gitignore to keep fork cleaner
and closer to upstream.
2026-01-28 03:13:19 -05:00
cottongin
5dab3ad5a3
feat: Library improvements - bookmarks, search, and tab navigation
Adds bookmark functionality with persistent storage, quick menu for
in-reader actions, Search tab with character picker, and unified
tab bar navigation across all library tabs.

Includes:
- BookmarkStore and BookmarkListActivity for bookmark management
- QuickMenuActivity for in-reader quick actions
- Reader bookmark integration with visual indicators
- Enhanced tab bar with scrolling, overflow indicators, and cursor
- Search tab with character picker and result navigation
- Consistent tab bar navigation (Up from top enters tab bar mode)
2026-01-28 02:51:51 -05:00
cottongin
82165c1022
feat: Wire up bookmark and quick menu features in main app
Integrates BookmarkStore initialization, QuickMenuActivity, and
BookmarkListActivity into the main application flow.
2026-01-28 02:20:58 -05:00
cottongin
e1fcec7d69
feat: Search tab with character picker and unified tab bar navigation
Adds Search tab to MyLibraryActivity with character picker for building
search queries, result navigation with long press jump-to-end support,
and Bookmarks tab integration. Implements consistent tab bar navigation
across all tabs - pressing Up from top of any list enters tab bar mode
with visible cursor indicators, Left/Right switches tabs, Down enters
list at top, and Up jumps to bottom of list.
2026-01-28 02:20:48 -05:00
cottongin
69a26ccb0e
feat: Enhanced tab bar with scrolling, overflow indicators, and cursor
Tab bar now scrolls to keep selected tab visible when content overflows.
Adds triangle overflow indicators and optional bullet cursor indicators
around the active tab for visual focus feedback.
2026-01-28 02:20:38 -05:00
cottongin
245d5a7dd8
feat: Integrate bookmark support into reader activities
Adds bookmark add/remove functionality to EpubReaderActivity and base
ReaderActivity, with visual indicator for bookmarked pages.
2026-01-28 02:20:29 -05:00
cottongin
e991fb10a6
feat: Add QuickMenuActivity for in-reader quick actions
Provides a popup menu accessible during reading for quick access
to bookmarks, settings, and other common actions.
2026-01-28 02:20:19 -05:00
cottongin
4080184b27
feat: Add BookmarkStore and BookmarkListActivity for bookmark management
Introduces persistent bookmark storage with JSON-based file format
and a dedicated activity for viewing bookmarks organized by book.
2026-01-28 02:20:09 -05:00
cottongin
8288cd2890
wishlist cleanup, clean branch start 2026-01-27 22:28:11 -05:00
cottongin
80c9e7a1d6
adds bezel compensation settings 2026-01-27 21:40:52 -05:00
cottongin
c2a966a6ea
refactor: Memory optimization and XTC format removal
Memory optimization:
- Add LOG_STACK_WATERMARK macro for task stack monitoring
- Add freeCoverBufferIfAllocated() and preloadCoverBuffer() for memory management
- Improve cover buffer reuse to reduce heap fragmentation
- Add grayscale buffer cleanup safety in GfxRenderer
- Make grayscale rendering conditional on successful buffer allocation
- Add detailed heap fragmentation logging with ESP-IDF API
- Add CSS parser memory usage estimation

XTC format removal:
- Remove entire lib/Xtc library (XTC parser and types)
- Remove XtcReaderActivity and XtcReaderChapterSelectionActivity
- Remove XTC file handling from HomeActivity, SleepActivity, ReaderActivity
- Remove .xtc/.xtch from supported extensions in BookManager
- Remove XTC cache prefix from Md5Utils
- Update web server and file browser to exclude XTC format
- Clear in-memory caches when disk cache is cleared
2026-01-27 20:35:32 -05:00
cottongin
158caacfe0
feat: Extend high contrast mode to entire UI
- Add global high contrast mode flag in BitmapHelpers
- Modify quantization thresholds for high contrast rendering
- Update ditherer classes (Atkinson, Floyd-Steinberg) for contrast mode
- Add displayContrast setting with persistence
- Add "High Contrast" toggle in display settings
- Apply high contrast mode on startup from saved settings
2026-01-27 20:34:44 -05:00
cottongin
1496ce68a6
feat: Recents view improvements with badges, removal, and clearing
- Add pill badge system for displaying file type and suffix tags
- Add "Remove from Recents" option to remove individual books
- Add "Clear All Recents" option to clear entire recents list
- Add clearThumbExistsCache() for cache invalidation
- Create BadgeConfig.h for customizable badge mappings
- Add extractBookTags() utility for parsing filename badges
- Add drawPillBadge() component for rendering badges
2026-01-27 20:33:27 -05:00
cottongin
0ab8e516f4
wishlist updates 2026-01-27 13:26:41 -05:00
cottongin
8687af738a
wishlist updates 2026-01-27 13:25:20 -05:00
cottongin
a04388fd6c
add proper firmware flashing screen 2026-01-27 13:16:20 -05:00
cottongin
7349fbb208
more wishlish stuff 2026-01-27 11:10:24 -05:00
cottongin
9a723fead8
adds pio helper script for frequent commands 2026-01-27 11:07:55 -05:00
Eliz
5fd1da5d2e
feat: Add support to B&W filters to image covers (#476)
* **What is the goal of this PR?** (e.g., Implements the new feature for
file uploading.)
Implementation of a new feature in Display options as Image Filter
* **What changes are included?**
Black & White and Inverted Black & White options are added.

Here are some examples:

| None | Contrast | Inverted |
| --- | --- | --- |
| <img alt="image"
src="https://github.com/user-attachments/assets/fe02dd9b-f647-41bd-8495-c262f73177c4"
/> | <img alt="image"
src="https://github.com/user-attachments/assets/2d17747d-3ff6-48a9-b9b9-eb17cccf19cf"
/> | <img alt="image"
src="https://github.com/user-attachments/assets/792dea50-f003-4634-83fe-77849ca49095"
/> |
| <img alt="image"
src="https://github.com/user-attachments/assets/28395b63-14f8-41e2-886b-8ddf3faeafc4"
/> | <img alt="image"
src="https://github.com/user-attachments/assets/71a569c8-fc54-4647-ad4c-ec96e220cddb"
/> | <img alt="image"
src="https://github.com/user-attachments/assets/9139e32c-9175-433e-8372-45fa042d3dc9"
/> |

* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks,
  specific areas to focus on).

I have also tried adding Color inversion, but could not see much
difference with that. It might be because my implementation was wrong.

---

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _** PARTIALLY **_

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-27 10:43:33 -05:00
cottongin
0a2c661b8b
update wishlist 2026-01-27 10:34:36 -05:00
cottongin
8fb6402023
update wishlist 2026-01-27 09:56:42 -05:00
cottongin
3b99459b82
ignore dirty submodule 2026-01-27 09:48:53 -05:00
cottongin
1442521d0c
notes for troubleshooting later, maybe 2026-01-27 09:46:55 -05:00
cottongin
7bbdf95aff
tracking for personal fork 2026-01-27 09:45:50 -05:00
cottongin
76e9cf8f75
merge PR 564 2026-01-27 09:38:13 -05:00
cottongin
397abe1ef0
checkpoint 2 - post PR merge - debug ghosting 2026-01-27 08:44:54 -05:00
cottongin
bc4edeef26
Refactor: Replace CalibreWirelessActivity with CalibreConnectActivity (#404)
Cherry-picked from upstream PR #404 with conflict resolution:
- Replaced flaky TCP-based Calibre wireless with WebSocket-based transfer
- Added OPDS authentication support (username/password in settings)
- Renamed "Calibre Library" to "OPDS Browser" in home menu
- Added UDP discovery for Calibre plugin communication
- Merged user's custom settings (customFontIndex, fallbackFontFamily, pinnedListName)
- Applied vTaskDelay cleanup after task deletion
- Kept existing "Calibre Settings" menu item (skipped KOReader Sync per preference)

Fixes issue #334 (Calibre wireless transfer not working)
2026-01-27 08:03:15 -05:00
cottongin
c90304f59b
fix: #348 fit cover artifacts - merge crop parameter (#465)
Cherry-picked from upstream PR #465
Resolved conflicts: merged crop parameter with existing progressCallback,
kept local dimension calculation and edge luminance caching logic
2026-01-27 07:50:37 -05:00
cottongin
6ffd19a7e8
fix: short-press power button to wakeup (#482)
Cherry-picked from upstream PR #482
Compatible with existing DICTIONARY option in SHORT_PWRBTN
2026-01-27 07:41:40 -05:00
cottongin
ff0392b9d2
fix: Validate settings on read (#492)
Cherry-picked from upstream PR #492
Resolved conflict: kept custom values (ACTUAL, progress bar modes,
CUSTOM_FONT, DICTIONARY) while adding _COUNT validation
2026-01-27 07:41:07 -05:00
cottongin
03a18fb298
UX improvement to Forget Network page (#484)
Cherry-picked from upstream PR #484
Unified button hints, clearer options, default to not forget
2026-01-27 07:39:40 -05:00
cottongin
f01f3979bc
fix: rotate origin in drawImage (#557)
Cherry-picked from upstream PR #557
2026-01-27 07:39:27 -05:00
cottongin
3cee01b43d
feat: add new configuration for front buttons, more usable on landscape ccw (#460)
Cherry-picked from upstream PR #460
Adds BACK_CONFIRM_RIGHT_LEFT button layout option
2026-01-27 07:36:57 -05:00
cottongin
8920c62957
fix: line break - flush word before <br/> tag (#525)
Manual implementation of upstream PR #525
Added flushPartWordBuffer() function and call it before <br/> handling
to fix issue where preceding word was incorrectly wrapped to new line
2026-01-27 07:36:06 -05:00
cottongin
991b6b5a01
feat: treat .md files as .txt (#498)
Cherry-picked from upstream PR #498
2026-01-27 07:32:59 -05:00
cottongin
d8b8c5bad9
fix: add txt books to recent tab (#526)
Cherry-picked from upstream PR #526
Resolved conflict: kept local cover generation code
2026-01-27 07:32:40 -05:00
cottongin
31199f9dd1
fix: remove decimal places from progress % (#507)
Cherry-picked from upstream PR #507
Resolved conflict: kept local progress bar feature while applying decimal fix
2026-01-27 07:31:57 -05:00
cottongin
25b75b706f
fix: Allow line break after ellipsis and underscore (#425)
Cherry-picked from upstream PR #425
2026-01-27 07:31:26 -05:00
cottongin
aa87b3f294
docs: add font generation commands to builtin font headers (#547)
Cherry-picked from upstream PR #547
2026-01-27 07:31:06 -05:00
cottongin
7a4af97ae8
docs: Update README with supported languages for EPUB (#530)
Cherry-picked from upstream PR #530
2026-01-27 07:30:53 -05:00
cottongin
703d95523b
fix: Add .vs folder to .gitignore (#466)
Cherry-picked from upstream PR #466
2026-01-27 07:30:38 -05:00
cottongin
1a38fd96af
image tweaks 2026-01-27 07:11:18 -05:00
cottongin
5f4fa3bebe
checkpoint 1 2026-01-26 19:48:21 -05:00
cottongin
94a7c2c0b8
starting point for -ef fork 2026-01-26 18:54:15 -05:00
Martin Brook
41eabba0d4 style: apply clang-format-21 formatting 2026-01-26 22:16:41 +00:00
cottongin
f739869519
Add MD5 hash API for companion app sync and improve upload reliability
- Add /api/hash endpoint to compute and cache MD5 hashes on demand
- Extend /api/files response with md5 field for EPUBs (null if not cached)
- Compute and cache MD5 automatically after EPUB uploads
- Add flush() before close() in WebSocket and HTTP upload handlers
- New Md5Utils module using ESP32's mbedtls for chunked hash computation

The MD5 hashes enable the companion app to detect file changes without
downloading content. Hashes are cached in each book's .crosspoint cache
directory and invalidated when file size changes.
2026-01-26 16:13:27 -05:00
Martin Brook
99702a342c feat: epub add png jpeg support 2026-01-26 19:09:19 +00:00
cottongin
a707cc6da2
debug mode added for memory testing 2026-01-26 13:56:36 -05:00
cottongin
d8bee1d21f
new debugging monitor 2026-01-26 13:13:44 -05:00
cottongin
2f7312e6a0
Merge branch 'merge-438' into merge-438-progress-bar-1
Merges progress bar status bar feature from merge-438:
- Added FULL_WITH_PROGRESS_BAR and ONLY_PROGRESS_BAR status bar modes
- Added drawBookProgressBar() to ScreenComponents

Preserves features from current branch:
- Content offset tracking for position restoration (EPUB_PROGRESS_VERSION)
- drawBatteryLarge() function
- Sleep Screen Cover Mode "Actual" option
2026-01-26 10:42:03 -05:00
cottongin
d02e2e5b5e
further webserver idle screen tweaks 2026-01-26 03:38:49 -05:00
cottongin
2c24ee3f81
Add reading lists feature with pinning and management
Adds full support for book lists managed by the Companion App:
- New /list API endpoints (GET/POST) for uploading, retrieving, and deleting lists
- BookListStore for binary serialization of lists to /.lists/ directory
- ListViewActivity for viewing list contents with book thumbnails
- Reading Lists tab in My Library with pin/unpin and delete actions
- Pinnable list shortcut on home screen (split button layout)
- Automatic cleanup of pinned status when lists are deleted
2026-01-26 02:08:59 -05:00
cottongin
cda8a5ec6d
web server tweaks 2026-01-25 21:22:49 -05:00
Alex Faria
6e0cc4cf46 fix: Use show battery percentage on TxtReaderActivity 2026-01-25 22:41:34 +00:00
Alex Faria
4d74cd795a feat: Add status bar option "Progress Bar" 2026-01-25 22:37:39 +00:00
Alex Faria
08adc91bbe feat: Add status bar option "Progress Bar" 2026-01-25 22:07:48 +00:00
Alex Faria
5996936c2e Merge branch 'master' into alexfaria/status-progress-bar 2026-01-25 21:55:20 +00:00
cottongin
af58eb1987
mDNS tweaks 2026-01-25 16:07:00 -05:00
cottongin
e9e9ef68da
adds initial support for companion app 2026-01-25 13:43:04 -05:00
cottongin
91c8cc67ce
granular position tracking 2026-01-25 00:24:54 -05:00
cottongin
fedc14bcb4
fix web server OOM 2026-01-24 23:08:35 -05:00
cottongin
2b2bc95cf2
fixed 2026-01-24 21:10:08 -05:00
cottongin
6bedc4ffec
improved sleep screen performance and cover art 2026-01-24 20:48:13 -05:00
cottongin
ecff988a29
add basic file management to web server 2026-01-24 13:05:01 -05:00
cottongin
c87a06edb8
roll home screen performance tweaks to library screens 2026-01-24 04:14:19 -05:00
cottongin
7fce5b347d
home screen performance fix 2026-01-24 03:59:08 -05:00
cottongin
2f21f55512
sleep screen filled with cover image's perimeter dominant color prior to being drawn 2026-01-24 03:29:34 -05:00
cottongin
1e20d30875
yep it works 2026-01-24 02:44:11 -05:00
cottongin
5c3828efe8
nice 2026-01-24 02:01:53 -05:00
cottongin
2952d7554c
feat: merge PR #511 - display epub metadata on Recents
Integrates upstream PR #511 changes while preserving local delete/archive
functionality. Key changes:

- Add RecentBook struct with path, title, author fields
- Update RecentBooksStore to store and serialize metadata
- Implement version migration for existing recent.bin files
- Update MyLibraryActivity to display two-line items (title + author)
- Update EpubReaderActivity and XtcReaderActivity to pass metadata

Maintains backwards compatibility with delete/archive feature from
local commit d5a9873.
2026-01-23 22:38:59 -05:00
pablohc
881f866d86
feat(sleep): pre-calculate EPUB cover dimensions for FIT/CROP modes
- Add JpegToBmpConverter::getJpegDimensions() to extract JPEG dimensions
- Fix getCoverBmpPath() ternary operator precedence bug
- Pre-calculate exact dimensions per mode:
  * FIT: width=480px, height=(480*jpegHeight)/jpegWidth
  * CROP: height=800px, width=(800*jpegWidth)/jpegHeight
- Generate separate cache files (cover_fit.bmp vs cover_crop.bmp)
- Eliminates runtime scaling artifacts, improves sleep screen clarity
2026-01-23 22:33:35 -05:00
cottongin
e3ae125f3c
adds Atkinson Hyperlegible Next 2026-01-23 22:17:55 -05:00
cottongin
67494a7c90
epub parsing improvement ideas 2026-01-23 22:16:52 -05:00
cottongin
59f493d293
add download feature to web file transfer 2026-01-23 07:57:44 -05:00
cottongin
ac1251282b
initial version of custom fonts 2026-01-23 03:54:39 -05:00
Daniel
16caa66b4a
perf: batch ZIP size lookup in buildBookBin (O(n*m) → O(n log n))
Add ZipFile::fillUncompressedSizes() for single-pass ZIP central directory
scan with hash-based target matching.

Also apply clang-format fixes for CI.

Shadow Slave results:
- buildBookBin: 506s → 35s
- Total indexing: 8.7min → 50s
2026-01-22 15:53:00 -05:00
Daniel
cf16d33710
perf: optimize large EPUB indexing from O(n²) to O(n log n)
Three optimizations for EPUBs with many chapters (e.g. 2768 chapters):

1. OPF idref→href lookup: Build sorted hash index during manifest parsing,
   use binary search during spine resolution. Reduces ~4min to ~30-60s.

2. TOC href→spineIndex lookup: Build sorted hash index in beginTocPass(),
   use binary search in createTocEntry(). Reduces ~4min to ~30-60s.

3. ZIP central-dir cursor: Resume scanning from last position instead of
   restarting from beginning. Reduces ~8min to ~1-3min.

All optimizations only activate for large EPUBs (≥400 spine items).
Small books use unchanged code paths.

Memory impact: ~33KB + ~39KB temporary during indexing, freed after.
Expected total: ~17min → ~3-5min for Shadow Slave (2768 chapters).

Also adds phase timing logs for performance measurement.
2026-01-22 15:53:00 -05:00
Daniel
51a4faddd4
fix: remove OOM-causing hrefToSpineIndex map from TOC pass
The unordered_map with 2768 string keys (~100KB+) was causing OOM crashes
at beginTocPass() on ESP32-C3's limited ~380KB RAM.

Reverted createTocEntry() to use original O(n) spine file scan instead.
Kept the safe spineToTocIndex vector in buildBookBin() (only ~5.5KB).
2026-01-22 15:52:45 -05:00
Daniel
a91bb0b1b8
perf: optimize large EPUB indexing from O(n²) to O(n)
Replace O(n²) lookups with O(n) preprocessing:

1. createTocEntry(): Build href->spineIndex map once in beginTocPass()
   instead of scanning spine file for every TOC entry

2. buildBookBin(): Build spineIndex->tocIndex vector in single pass
   instead of scanning TOC file for every spine entry

For 2768-chapter EPUBs, this reduces:
- TOC pass: from ~7.6M file reads to ~5.5K reads
- buildBookBin: from ~7.6M file reads to ~5.5K reads

Memory impact: ~80KB for href map (acceptable trade-off for 10x+ speedup)
2026-01-22 15:52:29 -05:00
Daniel
481b8210fb
fix: prevent OOM crash when loading large EPUBs (2000+ chapters)
Remove the call to loadAllFileStatSlims() which pre-loads all ZIP central
directory entries into memory. For EPUBs with 2000+ chapters (like webnovels),
this exhausts the ESP32-C3's ~380KB RAM and causes abort().

The existing loadFileStatSlim() function already handles individual lookups
by scanning the central directory per-file when the cache is empty. This is
O(n*m) instead of O(n), but prevents memory exhaustion.

Fixes #134
2026-01-22 15:52:07 -05:00
Jonas Diemer
c166b89f7b
Make sure img alt text is treated as separate text block 2026-01-22 15:48:32 -05:00
cottongin
d5a9873bd7
adds delete and archive abilities 2026-01-22 15:45:07 -05:00
cottongin
6b533207e1
fix cover art sizing options 2026-01-22 13:13:12 -05:00
cottongin
9493fb1f18
sort of working dictionary 2026-01-22 12:42:01 -05:00
cottongin
ff22a82563
Merge branch 'pr-411-css-parsing' 2026-01-21 19:40:45 -05:00
Alex Faria
1e506cce39 Merge branch 'master' into alexfaria/status-progress-bar 2026-01-21 13:34:25 +00:00
Alex Faria
72fa6f8395 Merge remote-tracking branch 'origin/master' into alexfaria/status-progress-bar
# Conflicts:
#	src/ScreenComponents.cpp
2026-01-21 12:20:51 +00:00
Alex Faria
fd6ea01f64 fix: Remove status bar margin from reader screen if status bar is disabled 2026-01-20 23:40:23 +00:00
Jake Kenneally
8f3d226bf3 increment versions to prevent error when opening cached EPUBs 2026-01-20 10:27:55 -06:00
Jake Kenneally
5c9412b141 fix compilation errors 2026-01-19 23:09:35 -06:00
Jake Kenneally
750a6ee1d8 rerun clang-format 2026-01-19 22:39:40 -06:00
Jake Kenneally
be2de1123b Merge remote-tracking branch 'origin' into feature/add-epub-css-parsing
* origin:
  fix: truncate chapter names that are too long (#422)
  feat: dict based Hyphenation (#305)
  fix: render U+FFFD replacement character instead of ? (#366)
  fix: Invert colors on home screen cover overlay when recent book is selected (#390)
  Adds KOReader Sync support (#232)
  feat: Change keyboard "caps" to "shift" & Wrap Keyboard (#377)
  fix: XTC 1-bit thumb BMP polarity inversion (#373)
2026-01-19 22:37:37 -06:00
Alex Faria
20b6d4d055 Fix formatting 2026-01-20 00:56:28 +00:00
Alex Faria
57379a6590 feat: Add status bar option "Full w/ Progress Bar" 2026-01-20 00:47:29 +00:00
Jake Kenneally
be10b90a71 formatting: run clang-format-fix 2026-01-17 18:35:44 -05:00
Jake Kenneally
94ce987f2c feat: Add CSS parsing and CSS support in EPUBs 2026-01-17 17:57:04 -05:00
288 changed files with 107445 additions and 19535 deletions

41
.gitea/workflows/ci.yml Normal file
View File

@ -0,0 +1,41 @@
name: CI
'on':
push:
branches: [master, crosspoint-ef]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Python
run: |
# Use system Python on self-hosted runner
python3 --version
python3 -m pip install --upgrade pip
- name: Install PlatformIO Core
run: python3 -m pip install --upgrade platformio
- name: Run cppcheck
run: pio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high
- name: Run clang-format
run: |
# Use system clang-format if available, skip if not
if command -v clang-format &> /dev/null; then
./bin/clang-format-fix && git diff --exit-code || (echo "Please run 'bin/clang-format-fix' to fix formatting issues" && exit 1)
else
echo "clang-format not found, skipping format check"
fi
- name: Generate Dictionary Index
run: |
python3 scripts/generate_dict_index.py --zip dict-en-en.zip --output lib/StarDict/DictPrefixIndex.generated.h
- name: Build CrossPoint
run: pio run

View File

@ -0,0 +1,40 @@
name: "PR Formatting"
on:
pull_request:
types:
- opened
- reopened
- edited
- synchronize
jobs:
title-check:
name: Title Check
runs-on: ubuntu-latest
steps:
- name: Check PR Title Format
run: |
PR_TITLE="${{ github.event.pull_request.title }}"
echo "Checking PR title: $PR_TITLE"
# Conventional commit pattern: type(scope): description or type: description
# Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
PATTERN="^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([a-zA-Z0-9_-]+\))?: .+"
if echo "$PR_TITLE" | grep -qE "$PATTERN"; then
echo "✓ PR title follows conventional commit format"
else
echo "✗ PR title does not follow conventional commit format"
echo ""
echo "Expected format: type(scope): description"
echo " or: type: description"
echo ""
echo "Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert"
echo ""
echo "Examples:"
echo " feat(reader): add bookmark sync feature"
echo " fix: resolve memory leak in epub parser"
echo " docs: update README with new instructions"
exit 1
fi

View File

@ -0,0 +1,40 @@
name: Compile Release
on:
push:
tags:
- '*'
jobs:
build-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Python
run: |
# Use system Python on self-hosted runner
python3 --version
python3 -m pip install --upgrade pip
- name: Install PlatformIO Core
run: python3 -m pip install --upgrade platformio
- name: Generate Dictionary Index
run: |
python3 scripts/generate_dict_index.py --zip dict-en-en.zip --output lib/StarDict/DictPrefixIndex.generated.h
- name: Build CrossPoint
run: pio run -e gh_release
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: CrossPoint-${{ github.ref_name }}
path: |
.pio/build/gh_release/bootloader.bin
.pio/build/gh_release/firmware.bin
.pio/build/gh_release/firmware.elf
.pio/build/gh_release/firmware.map
.pio/build/gh_release/partitions.bin

13
.gitignore vendored
View File

@ -2,7 +2,20 @@
.idea
.DS_Store
.vscode
.cursor/
chat-summaries/
lib/EpdFont/fontsrc
*.generated.h
.vs
build
**/__pycache__/
test/epubs/
CrossPoint-ef.md
Serial_print.code-search
# Gitea Release note drafts
release-notes-*.md
# Gitea Actions runner config (contains credentials)
.runner
.runner.*

4
.gitmodules vendored
View File

@ -1,3 +1,5 @@
[submodule "open-x4-sdk"]
path = open-x4-sdk
url = https://github.com/open-x4-epaper/community-sdk.git
url = https://code.cottongin.xyz/cottongin/community-sdk.git
branch = crosspoint-ef
ignore = dirty

View File

@ -1,4 +1,15 @@
# CrossPoint Reader
# CrossPoint Reader (ef fork)
> **Note:** This is **crosspoint-ef**, a heavily customized fork of [CrossPoint Reader](https://github.com/crosspoint-reader/crosspoint-reader) with additional features, UI improvements, and bug fixes. It also uses a [forked community-sdk](https://code.cottongin.xyz/cottongin/community-sdk) with additional hardware support.
>
> **Documentation:**
> - [Feature Overview](./docs/crosspoint-ef-features.md) - What's new in this fork
> - [User Guide](./docs/crosspoint-ef-user-guide.md) - How to use the new features
> - [Technical Comparison](./docs/branch-comparison-summary.md) - Detailed diff from upstream
>
> **Disclaimer:** Much of the code in this fork was developed with assistance from [Claude](https://claude.ai), an AI assistant by Anthropic.
---
Firmware for the **Xteink X4** e-paper display reader (unaffiliated with Xteink).
Built using **PlatformIO** and targeting the **ESP32-C3** microcontroller.
@ -41,6 +52,8 @@ This project is **not affiliated with Xteink**; it's built as a community projec
- [ ] Full UTF support
- [x] Screen rotation
Multi-language support: Read EPUBs in various languages, including English, Spanish, French, German, Italian, Portuguese, Russian, Ukrainian, Polish, Swedish, Norwegian, [and more](./USER_GUIDE.md#supported-languages).
See [the user guide](./USER_GUIDE.md) for instructions on operating CrossPoint.
## Installing

View File

@ -81,6 +81,18 @@ See the [webserver docs](./docs/webserver.md) for more information on how to con
> [!TIP]
> Advanced users can also manage files programmatically or via the command line using `curl`. See the [webserver docs](./docs/webserver.md) for details.
### 3.4.1 Calibre Wireless Transfers
CrossPoint supports sending books from Calibre using the CrossPoint Reader device plugin.
1. Install the plugin in Calibre:
- Head to https://github.com/crosspoint-reader/calibre-plugins/releases to download the latest version of the crosspoint_reader plugin.
- Download the zip file.
- Open Calibre → Preferences → Plugins → Load plugin from file → Select the zip file.
2. On the device: File Transfer → Connect to Calibre → Join a network.
3. Make sure your computer is on the same WiFi network.
4. In Calibre, click "Send to device" to transfer books.
### 3.5 Settings
The Settings screen allows you to configure the device's behavior. There are a few settings you can adjust:
@ -93,6 +105,10 @@ The Settings screen allows you to configure the device's behavior. There are a f
- **Sleep Screen Cover Mode**: How to display the book cover when "Cover" sleep screen is selected:
- "Fit" (default) - Scale the image down to fit centered on the screen, padding with white borders as necessary
- "Crop" - Scale the image down and crop as necessary to try to to fill the screen (Note: this is experimental and may not work as expected)
- **Sleep Screen Cover Filter**: What filter will be applied to the book cover when "Cover" sleep screen is selected
- "None" (default) - The cover image will be converted to a grayscale image and displayed as it is
- "Contrast" - The image will be displayed as a black & white image without grayscale conversion
- "Inverted" - The image will be inverted as in white&black and will be displayed without grayscale conversion
- **Status Bar**: Configure the status bar displayed while reading:
- "None" - No status bar
- "No Progress" - Show status bar without reading progress
@ -116,6 +132,7 @@ The Settings screen allows you to configure the device's behavior. There are a f
- Back, Confirm, Left, Right (default)
- Left, Right, Back, Confirm
- Left, Back, Confirm, Right
- Back, Confirm, Right, Left
- **Side Button Layout (reader)**: Swap the order of the up and down volume buttons from Previous/Next to Next/Previous. This change is only in effect when reading.
- **Long-press Chapter Skip**: Set whether long-pressing page turn buttons skip to the next/previous chapter.
- "Chapter Skip" (default) - Long-pressing skips to next/previous chapter
@ -131,7 +148,7 @@ The Settings screen allows you to configure the device's behavior. There are a f
- **Reader Paragraph Alignment**: Set the alignment of paragraphs; options are "Justified" (default), "Left", "Center", or "Right".
- **Time to Sleep**: Set the duration of inactivity before the device automatically goes to sleep.
- **Refresh Frequency**: Set how often the screen does a full refresh while reading to reduce ghosting.
- **Calibre Settings**: Set up integration for accessing a Calibre web library or connecting to Calibre as a wireless device.
- **OPDS Browser**: Configure OPDS server settings for browsing and downloading books. Set the server URL (for Calibre Content Server, add `/opds` to the end), and optionally configure username and password for servers requiring authentication. Note: Only HTTP Basic authentication is supported. If using Calibre Content Server with authentication enabled, you must set it to use Basic authentication instead of the default Digest authentication.
- **Check for updates**: Check for firmware updates over WiFi.
### 3.6 Sleep Screen
@ -177,6 +194,15 @@ This feature can be disabled in **[Settings](#35-settings)** to help avoid chang
* **Return to Home:** Press and **hold** the **Back** button to close the book and return to the **[Home](#31-home-screen)** screen.
* **Chapter Menu:** Press **Confirm** to open the **[Table of Contents/Chapter Selection](#5-chapter-selection-screen)**.
### Supported Languages
CrossPoint renders text using the following Unicode character blocks, enabling support for a wide range of languages:
* **Latin Script (Basic, Supplement, Extended-A):** Covers English, German, French, Spanish, Portuguese, Italian, Dutch, Swedish, Norwegian, Danish, Finnish, Polish, Czech, Hungarian, Romanian, Slovak, Slovenian, Turkish, and others.
* **Cyrillic Script (Standard and Extended):** Covers Russian, Ukrainian, Belarusian, Bulgarian, Serbian, Macedonian, Kazakh, Kyrgyz, Mongolian, and others.
What is not supported: Chinese, Japanese, Korean, Vietnamese, Hebrew, Arabic and Farsi.
---
## 5. Chapter Selection Screen

View File

@ -0,0 +1,137 @@
# Ghosting Issue Bisect Debug Summary
**Date:** 2026-01-27
**Branch:** `catch-up-PR-merges`
**Issue:** Text ghosting on page turns when anti-aliasing enabled
---
## Problem Description
After merging 15 upstream PRs, ghosting artifacts appeared when turning pages in the EPUB reader. The ghosting manifested as residual edges/outlines of previous page text, visible only when text anti-aliasing was enabled.
---
## The 15 Merged PRs (in merge order)
| Order | Commit | PR | Description |
|-------|--------|-----|-------------|
| 1 | `703d955` | #466 | fix: Add .vs folder to .gitignore |
| 2 | `7a4af97` | #530 | docs: Update README with supported languages for EPUB |
| 3 | `aa87b3f` | #547 | docs: add font generation commands to builtin font headers |
| 4 | `25b75b7` | #425 | fix: Allow line break after ellipsis and underscore |
| 5 | `31199f9` | #507 | fix: remove decimal places from progress % |
| 6 | `d8b8c5b` | #526 | fix: add txt books to recent tab |
| 7 | `991b6b5` | #498 | feat: treat .md files as .txt |
| 8 | `8920c62` | #525 | fix: line break - flush word before br tag |
| 9 | `3cee01b` | #460 | feat: add new configuration for front buttons |
| 10 | `f01f397` | #557 | fix: rotate origin in drawImage |
| 11 | `03a18fb` | #484 | UX improvement to Forget Network page |
| 12 | `ff0392b` | #492 | fix: Validate settings on read |
| 13 | `6ffd19a` | #482 | fix: short-press power button to wakeup |
| 14 | `c90304f` | #465 | fix: cover artifacts - merge crop parameter |
| 15 | `bc4edee` | #404 | Refactor: Replace CalibreWirelessActivity with CalibreConnectActivity |
**Base commit:** `1a38fd9` (before any PR merges)
**Checkpoint commit:** `397abe1` (after all PR merges)
---
## Bisect Process
### Initial State
- **GOOD:** `1a38fd9` - no ghosting
- **BAD:** `397abe1` (HEAD) - ghosting present
### Bisect Steps
| Step | Commit | PR | Result | Remaining |
|------|--------|-----|--------|-----------|
| 1 | `991b6b5` | #498 (midpoint) | NO ghosting | Bug in commits 8-15 |
| 2 | `ff0392b` | #492 (midpoint of 8-15) | NO ghosting | Bug in commits 13-15 |
| 3 | `c90304f` | #465 | NO ghosting | Bug in commits 15 or checkpoint |
| 4 | `bc4edee` | #404 | NO ghosting | Bug in checkpoint only |
### Compilation Issue During Bisect
A conflict from PR #526 merge left `RECENT_BOOKS.addBook()` with 1 argument instead of 3. This caused compilation failures at intermediate commits. Temporary fix applied at each step:
```cpp
// Changed from:
RECENT_BOOKS.addBook(txt->getPath());
// To:
RECENT_BOOKS.addBook(txt->getPath(), txt->getTitle(), "");
```
---
## Root Cause Finding
**The ghosting was NOT caused by any upstream PR.**
After testing all commits, the bisect pointed to the checkpoint commit `397abe1`. However, the diff between `bc4edee` and `397abe1` only contained:
- The `addBook` fix (unrelated to display)
- Removing duplicate `handleDownload` (unrelated to display)
### Actual Cause: Uncommitted Local Changes
The ghosting was caused by **uncommitted local changes in the IDE working directory**. These changes were being preserved across `git checkout` operations because they existed in IDE buffers.
When `git checkout -f catch-up-PR-merges` was executed (force checkout), all local changes were discarded and the ghosting disappeared.
---
## Local Changes That Were Present
The following modifications existed in the working directory but were NOT in the checkpoint commit:
- `CrossPointSettings.h/cpp` - enum `_COUNT` suffixes, `readAndValidate`, OPDS auth fields
- `ChapterHtmlSlimParser.h/cpp` - `flushPartWordBuffer()` function
- `SleepActivity.cpp` - `drawImage` coordinate changes
- `JpegToBmpConverter.h/cpp` - `crop` parameter
- `HomeActivity.cpp` - "OPDS Browser" label
- `SettingsActivity.cpp` - front button layout options
- `CrossPointWebServer.h/cpp` - UDP discovery, `WsUploadStatus`
**Important:** These changes were actually already committed in the PR merge commits. The confusion arose because:
1. Checking out older commits removed these changes
2. IDE buffers or manual re-application restored them as "local changes"
3. This created a mismatch between committed code and working directory
---
## Resolution
1. Force checkout to HEAD: `git checkout -f catch-up-PR-merges`
2. Verified all PR changes are properly committed
3. Built and tested - no ghosting
4. Working directory is now clean (matches committed state)
---
## Key Lessons
1. **Always check `git status` before bisecting** - local changes can persist across checkouts
2. **Use `git checkout -f` or `git checkout <commit> -- .`** to ensure clean state
3. **IDE buffers can reintroduce changes** - close/reload files after checkout if needed
4. **Bisecting with compilation errors** requires temporary fixes that don't affect the bug being investigated
5. **The "bug" may not be in commits at all** - it could be in uncommitted working directory changes
---
## Commands Reference
```bash
# Force checkout to discard local changes
git checkout -f <branch>
# Checkout specific commit with clean state
git checkout <commit> -- . && git checkout <commit>
# Check for uncommitted changes
git status
git diff --stat
# View what's in a specific commit
git show <commit>:path/to/file
```

View File

@ -0,0 +1,70 @@
# Serial.printf Calls Without `if (Serial)` Guards
**Date:** 2026-01-28
**Status:** Informational (not blocking issues)
## Summary
The codebase contains **408 Serial print calls** across 27 files in `src/`. Of these, only **16 calls** (in 2 files) have explicit `if (Serial)` guards.
**This is not a problem** because `Serial.setTxTimeoutMs(0)` is called in `setup()` before any activity code runs, making all Serial output non-blocking globally.
## Protection Mechanism
In `src/main.cpp` (lines 467-468):
```cpp
Serial.begin(115200);
Serial.setTxTimeoutMs(0); // Non-blocking TX - critical for USB disconnect handling
```
This ensures that even without `if (Serial)` guards, Serial.printf calls will return immediately when USB is disconnected instead of blocking indefinitely.
## Files with `if (Serial)` Guards (16 calls)
| File | Protected Calls |
|------|-----------------|
| `src/activities/reader/EpubReaderActivity.cpp` | 15 |
| `src/main.cpp` | 1 |
## Files Without Guards (392 calls)
These calls are protected by `Serial.setTxTimeoutMs(0)` but don't have explicit guards:
| File | Unguarded Calls |
|------|-----------------|
| `src/network/CrossPointWebServer.cpp` | 106 |
| `src/activities/network/CrossPointWebServerActivity.cpp` | 49 |
| `src/activities/boot_sleep/SleepActivity.cpp` | 33 |
| `src/BookManager.cpp` | 25 |
| `src/activities/reader/TxtReaderActivity.cpp` | 20 |
| `src/activities/home/HomeActivity.cpp` | 16 |
| `src/network/OtaUpdater.cpp` | 16 |
| `src/util/Md5Utils.cpp` | 15 |
| `src/main.cpp` | 13 (plus 1 guarded) |
| `src/WifiCredentialStore.cpp` | 12 |
| `src/network/HttpDownloader.cpp` | 12 |
| `src/BookListStore.cpp` | 11 |
| `src/activities/network/WifiSelectionActivity.cpp` | 11 |
| `src/activities/settings/OtaUpdateActivity.cpp` | 9 |
| `src/activities/browser/OpdsBookBrowserActivity.cpp` | 9 |
| `src/activities/settings/ClearCacheActivity.cpp` | 7 |
| `src/BookmarkStore.cpp` | 6 |
| `src/RecentBooksStore.cpp` | 5 |
| `src/activities/reader/ReaderActivity.cpp` | 4 |
| `src/activities/Activity.h` | 3 |
| `src/CrossPointSettings.cpp` | 3 |
| `src/activities/network/CalibreConnectActivity.cpp` | 2 |
| `src/activities/home/ListViewActivity.cpp` | 2 |
| `src/activities/home/MyLibraryActivity.cpp` | 1 |
| `src/activities/dictionary/DictionarySearchActivity.cpp` | 1 |
| `src/CrossPointState.cpp` | 1 |
## Recommendation
No immediate action required. The global `Serial.setTxTimeoutMs(0)` protection is sufficient.
If desired, `if (Serial)` guards could be added to high-frequency logging paths for minor performance optimization (skipping format string processing), but this is low priority.
## Note on open-x4-sdk
The `open-x4-sdk` submodule also contains Serial calls (in `EInkDisplay.cpp`, `SDCardManager.cpp`). These are also protected by the global timeout setting since `Serial.begin()` and `setTxTimeoutMs()` are called before any SDK code executes.

View File

@ -0,0 +1,125 @@
# Serial Blocking Debug Session Summary
**Date:** 2026-01-28
**Issue:** Device freezes when booted without USB connected
**Resolution:** `Serial.setTxTimeoutMs(0)` - make Serial TX non-blocking
## Problem Description
During release preparation for ef-0.15.9, the device was discovered to freeze completely when:
1. Unplugged from USB
2. Powered on via power button
3. Book page displays, then device becomes unresponsive
4. No button presses register
The device worked perfectly when USB was connected.
## Investigation Process
### Initial Hypotheses Tested
Multiple hypotheses were systematically investigated:
1. **Hypothesis A-D:** Display/rendering mutex issues
- Added mutex logging to SD card
- Mutex operations completed successfully
- Ruled out as root cause
2. **Hypothesis E:** FreeRTOS task creation issues
- Task created and ran successfully
- First render completed normally
- Ruled out
3. **Hypothesis F-G:** Main loop execution
- Added loop counter logging to SD card
- **Key finding:** Main loop never started logging
- Setup() completed but loop() never executed meaningful work
4. **Hypothesis H-J:** Various timing and initialization issues
- Tested different delays and initialization orders
- No improvement
### Root Cause Discovery
The breakthrough came from analyzing the boot sequence:
1. `setup()` completes successfully
2. `EpubReaderActivity::onEnter()` runs and calls `Serial.printf()` to log progress
3. **Device hangs at Serial.printf() call**
On ESP32-C3 with USB CDC (USB serial), `Serial.printf()` blocks indefinitely waiting for the TX buffer to drain when USB is not connected. The default behavior expects a host to read the data.
### Evidence
- When USB connected: `Serial.printf()` returns immediately (data sent to host)
- When USB disconnected: `Serial.printf()` blocks forever waiting for TX buffer space
- The hang occurred specifically in `EpubReaderActivity.cpp` during progress logging
## Solution
### Primary Fix
Configure Serial to be non-blocking in `src/main.cpp`:
```cpp
// Always initialize Serial but make it non-blocking
Serial.begin(115200);
Serial.setTxTimeoutMs(0); // Non-blocking TX - critical for USB disconnect handling
```
`Serial.setTxTimeoutMs(0)` tells the ESP32 Arduino core to return immediately from Serial write operations if the buffer is full, rather than blocking.
### Secondary Protection (Belt and Suspenders)
Added `if (Serial)` guards to high-traffic Serial calls in `EpubReaderActivity.cpp`:
```cpp
if (Serial) Serial.printf("[%lu] [ERS] Loaded progress...\n", millis());
```
This provides an additional check before attempting to print, though it's not strictly necessary with the timeout set to 0.
## Files Changed
| File | Change |
|------|--------|
| `src/main.cpp` | Added `Serial.setTxTimeoutMs(0)` after `Serial.begin()` |
| `src/main.cpp` | Added `if (Serial)` guard to auto-sleep log |
| `src/main.cpp` | Added `if (Serial)` guard to max loop duration log |
| `src/activities/reader/EpubReaderActivity.cpp` | Added 16 `if (Serial)` guards |
## Verification
After applying the fix:
1. Device boots successfully when unplugged from USB
2. Book pages render correctly
3. Button presses register normally
4. Sleep/wake cycle works
5. No functionality lost when USB is connected
## Lessons Learned
1. **ESP32-C3 USB CDC behavior:** Serial output can block indefinitely without a connected host
2. **Always set non-blocking:** `Serial.setTxTimeoutMs(0)` should be standard for battery-powered devices
3. **Debug logging location matters:** When debugging hangs, SD card logging proved essential since Serial was the problem
4. **Systematic hypothesis testing:** Ruled out many red herrings (mutex, task, rendering) before finding the true cause
## Technical Details
### Why This Affects ESP32-C3 Specifically
The ESP32-C3 uses native USB CDC for serial communication (no external USB-UART chip). The Arduino core's default behavior is to wait for TX buffer space, which requires an active USB host connection.
### Alternative Approaches Considered
1. **Only initialize Serial when USB connected:** Partially implemented, but insufficient because USB can be disconnected after boot
2. **Add `if (Serial)` guards everywhere:** Too invasive (400+ calls)
3. **Disable Serial entirely:** Would lose debug output when USB connected
The chosen solution (`setTxTimeoutMs(0)`) provides the best balance: debug output works when USB is connected, device operates normally when disconnected.
## References
- ESP32 Arduino Core Serial documentation
- ESP-IDF USB CDC documentation
- FreeRTOS queue behavior (initial red herring investigation)

View File

@ -0,0 +1,132 @@
# USB Serial Blocking Issue - Root Cause and Fix
**Date:** 2026-01-28
**Issue:** Device blocking/hanging when USB is not connected at boot
---
## Problem Description
The device would hang or behave unpredictably when booted without USB connected. This was traced to improper Serial handling on ESP32-C3 with USB CDC.
## Root Cause Analysis
### Factor A: `checkForFlashCommand()` Called Without Serial Initialization
The most critical issue was in `checkForFlashCommand()`, which is called at the start of every `loop()` iteration:
```cpp
void loop() {
checkForFlashCommand(); // Called EVERY loop iteration
// ...
}
void checkForFlashCommand() {
while (Serial.available()) { // Called even when Serial.begin() was never called!
char c = Serial.read();
// ...
}
}
```
When USB is not connected at boot, `Serial.begin()` is never called. Then in `loop()`, `checkForFlashCommand()` calls `Serial.available()` and `Serial.read()` on an uninitialized Serial object. On ESP32-C3 with USB CDC, this causes undefined behavior or blocking.
### Factor B: Removed `while (!Serial)` Wait Loop
The upstream 0.16.0 code included a 3-second wait loop after `Serial.begin()`:
```cpp
if (isUsbConnected()) {
Serial.begin(115200);
unsigned long start = millis();
while (!Serial && (millis() - start) < 3000) {
delay(10);
}
}
```
This wait loop was removed in an earlier attempt to fix boot delays, but it may be necessary for proper USB CDC initialization.
### Factor C: `Serial.setTxTimeoutMs(0)` Added Too Early
`Serial.setTxTimeoutMs(0)` was added immediately after `Serial.begin()` to make TX non-blocking. However, calling this before the Serial connection is fully established may interfere with USB CDC initialization.
---
## The Fix
### 1. Guard `checkForFlashCommand()` with Serial Check
```cpp
void checkForFlashCommand() {
if (!Serial) return; // Early exit if Serial not initialized
while (Serial.available()) {
// ... rest unchanged
}
}
```
### 2. Restore Upstream Serial Initialization Pattern
```cpp
void setup() {
t1 = millis();
// Only start serial if USB connected
pinMode(UART0_RXD, INPUT);
if (isUsbConnected()) {
Serial.begin(115200);
// Wait up to 3 seconds for Serial to be ready to catch early logs
unsigned long start = millis();
while (!Serial && (millis() - start) < 3000) {
delay(10);
}
}
// ... rest of setup
}
```
### 3. Remove `Serial.setTxTimeoutMs(0)`
This call was removed entirely as it's not present in upstream and may cause issues.
### 4. Remove Unnecessary `if (Serial)` Guards
The 15 `if (Serial)` guards added to `EpubReaderActivity.cpp` were removed. `Serial.printf()` is safe to call when Serial isn't initialized (it simply returns 0), so guards around output calls are unnecessary.
**Key distinction:**
- `Serial.printf()` / `Serial.println()` - Safe without guards (no-op when not initialized)
- `Serial.available()` / `Serial.read()` - **MUST** be guarded (undefined behavior when not initialized)
---
## Files Changed
| File | Change |
|------|--------|
| `src/main.cpp` | Removed `Serial.setTxTimeoutMs(0)`, restored `while (!Serial)` wait, added guard to `checkForFlashCommand()` |
| `src/activities/reader/EpubReaderActivity.cpp` | Removed all 15 `if (Serial)` guards |
---
## Testing Checklist
After applying fixes, verify:
1. ✅ Boot with USB connected, serial monitor open - should work
2. ✅ Boot with USB connected, NO serial monitor - should work (3s delay then continue)
3. ✅ Boot without USB - should work immediately (no blocking)
4. ✅ Sleep without USB, plug in USB during sleep, wake - should work
5. ✅ Sleep with USB, unplug during sleep, wake - should work
---
## Lessons Learned
1. **Always guard Serial input operations**: `Serial.available()` and `Serial.read()` must be guarded with `if (Serial)` or `if (!Serial) return` when Serial initialization is conditional.
2. **Serial output is safe without guards**: `Serial.printf()` and similar output functions are safe to call even when Serial is not initialized - they simply return 0.
3. **Don't remove initialization waits without understanding why they exist**: The `while (!Serial)` wait loop exists for proper USB CDC initialization and shouldn't be removed without careful testing.
4. **Upstream patterns exist for a reason**: When diverging from upstream behavior, especially around low-level hardware initialization, be extra cautious and test thoroughly.

BIN
dict-en-en.zip Normal file

Binary file not shown.

View File

@ -0,0 +1,422 @@
# Branch Comparison Summary: crosspoint-ef vs 0.16.0
This document provides a comprehensive comparison between the `crosspoint-ef` branch and the upstream `0.16.0` release for merge planning and implementation decisions.
## Branch History
| Branch | Base | Commits Since Base | Status |
|--------|------|-------------------|--------|
| `crosspoint-ef` | 0.15.0 | 90+ | Active development |
| `0.16.0` | 0.15.0 | 30 | Released |
Both branches diverged from `0.15.0` at commit `3ce11f14`.
---
## Feature Comparison Matrix
### Major Features
| Feature | crosspoint-ef | 0.16.0 | Notes |
|---------|:-------------:|:------:|-------|
| Dictionary Support | Yes | No | StarDict format with word selection |
| Bookmark System | Yes | No | Per-book bookmarks with visual indicator |
| Quick Menu | Yes | No | Power button quick access |
| Library Search | Yes | No | Character picker with weighted search |
| CSS Parsing | Yes | No | Element, class, inline styles |
| Inline Images (PNG/JPEG) | Yes | No | With caching and dithering |
| Custom Fonts | Yes | No | Atkinson Hyperlegible, Fern Micro |
| Enhanced Web Server | Yes | Partial | File ops, MD5 API, mDNS |
| Companion App API | Yes | No | Deep links, WebSocket uploads |
| Reading Lists | Yes | No | With pinning support |
| Tab Bar Enhancements | Yes | No | Scrolling, overflow indicators |
| High Contrast Mode | Yes | No | System-wide |
| Bezel Compensation | Yes | No | Edge defect compensation |
| Sleep Screen Edge Detection | Yes | No | Dominant color fill |
| Recents Improvements | Yes | No | Badges, removal, clearing |
| Progress Bar Status Bar | Yes | Yes | Same feature |
| Spanish Hyphenation | No | Yes | Missing in crosspoint-ef |
| XTC/XTCH Author Extraction | No | Yes | Missing in crosspoint-ef |
| OTA Rework | No | Yes | Different implementation |
| KOReader MD5 Binary Matching | No | Yes | Missing in crosspoint-ef |
| Relative Position on Settings Change | No | Yes | Missing in crosspoint-ef |
| Multi-line Keyboard Entry | No | Yes | Missing in crosspoint-ef |
| Italics on Image Alt | No | Yes | Missing in crosspoint-ef |
| Page Turn on Button Press (UX) | No | Yes | When chapter skip disabled |
### Bug Fixes
| Fix | crosspoint-ef | 0.16.0 | Notes |
|-----|:-------------:|:------:|-------|
| Large EPUB indexing O(n²)→O(n) | Yes | Yes | Same fix |
| Settings validation on read | Yes | Yes | Same fix |
| Line break fixes | Yes | Yes | Similar fixes |
| Rotate origin in drawImage | Yes | Yes | Same fix |
| Short-press power wakeup | Yes | Yes | Same fix |
| TXT books in recent tab | Yes | Yes | Same fix |
| B&W filters for covers | Yes | Yes | Same fix |
| Cover fit artifacts | Yes | Yes | Same fix |
| Grayscale state corruption | Yes | No | Unique to crosspoint-ef |
| Memory graceful degradation | Yes | No | Unique to crosspoint-ef |
| Chapter Selection UI (KOReader) | No | Yes | Missing in crosspoint-ef |
| Front layout in mapLabels() | No | Yes | Missing in crosspoint-ef |
---
## Files Changed Summary
### crosspoint-ef Unique Files (New)
| Category | Files |
|----------|-------|
| Dictionary | `src/activities/dictionary/` (8 files), `lib/StarDict/` (4 files) |
| Bookmarks | `src/BookmarkStore.cpp/.h`, `src/activities/home/BookmarkListActivity.cpp/.h` |
| Quick Menu | `src/activities/util/QuickMenuActivity.cpp/.h` |
| CSS | `lib/Epub/Epub/css/` (3 files) |
| Images | `lib/Epub/Epub/blocks/ImageBlock.cpp/.h`, `lib/Epub/Epub/converters/` (6 files) |
| Custom Fonts | `src/customFonts.cpp`, `src/fontIds.h`, `lib/EpdFont/builtinFonts/custom/` (50+ files) |
| Utils | `src/util/Md5Utils.cpp/.h`, `src/util/StringUtils.cpp/.h` |
| Lists | `src/BookListStore.cpp/.h` |
| Docs | `docs/webserver-api-reference.md`, `docs/companion-app-deep-link-API.md`, `docs/troubleshooting.md` |
### crosspoint-ef Modified Files (Significant Changes)
| File | Changes |
|------|---------|
| `src/network/CrossPointWebServer.cpp` | +1083 lines (file ops, API, WebSocket) |
| `src/activities/home/MyLibraryActivity.cpp` | +700 lines (tabs, search, badges) |
| `src/main.cpp` | +255 lines (feature integration) |
| `lib/GfxRenderer/GfxRenderer.cpp` | +439 lines (contrast, bezel) |
| `lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp` | +596 lines (CSS integration) |
| `src/CrossPointSettings.cpp/.h` | New settings fields |
| `src/activities/boot_sleep/SleepActivity.cpp` | Edge detection, caching |
| `src/RecentBooksStore.cpp` | Badges, removal, metadata |
| `src/ScreenComponents.cpp` | Tab bar enhancements |
### 0.16.0 Unique Files/Changes
| File | Description |
|------|-------------|
| `lib/Epub/Epub/hyphenation/generated/hyph-es.trie.h` | Spanish hyphenation (removed in ef) |
| `lib/KOReaderSync/` | KOReader credential handling (removed in ef) |
| `src/network/OtaUpdater.cpp` | OTA rework |
---
## Merge Strategy Recommendations
### Phase 1: Cherry-pick 0.16.0 Fixes into crosspoint-ef
**Low Risk - Recommended First:**
1. **Spanish hyphenation support** (#558)
- Add `hyph-es.trie.h` back
- Update `LanguageRegistry.cpp`
2. **Render keyboard entry over multiple lines** (#567)
- Update `KeyboardEntryActivity.cpp`
3. **Correctly render italics on image alt** (#569)
- Minimal change to text rendering
4. **Page turning on button pressed** (#451)
- UX improvement when chapter skip disabled
5. **Missing front layout in mapLabels()** (#564)
- Bug fix for button mapping
**Medium Risk:**
6. **KOReader document MD5 binary matching** (#529)
- May conflict with MD5Utils changes
7. **Chapter Selection UI bugs** (#501)
- Review for conflicts with tab bar changes
8. **Relative position on settings change** (#486)
- Reader state management change
**Higher Risk:**
9. **OTA feature rework** (#509)
- Compare implementations, may need reconciliation
- crosspoint-ef has different OTA changes
10. **Extract author from XTC/XTCH** (#563)
- XTC format was removed in crosspoint-ef
- Evaluate if needed
### Phase 2: Potential Upstream Contributions from crosspoint-ef
**High Value, Moderate Complexity:**
1. **Dictionary Support**
- Self-contained feature
- New files, minimal integration points
- Requires shipping dictionary data
2. **Bookmark System**
- Clean implementation
- New files with reader integration
3. **Quick Menu**
- Simple overlay feature
- Depends on bookmark and dictionary
4. **CSS Parsing**
- Significant EPUB improvement
- Well-isolated in `lib/Epub/Epub/css/`
**High Value, Higher Complexity:**
5. **Inline Image Support**
- Major EPUB enhancement
- Multiple new converters
- Memory management considerations
6. **Library Search**
- Integrated into MyLibraryActivity
- Tab bar changes included
7. **Enhanced Web Server**
- Large changes to CrossPointWebServer
- New API endpoints
- WebSocket uploads
**Medium Value:**
8. **Custom Fonts**
- Large binary additions (font headers)
- Clean integration
9. **Display Enhancements**
- High contrast, bezel compensation
- Settings additions
10. **Reading Lists**
- New feature with web API
---
## Potential Conflicts
### High Conflict Risk
| Area | crosspoint-ef | 0.16.0 | Resolution |
|------|---------------|--------|------------|
| `MyLibraryActivity.cpp` | Major restructure | Minor fixes | Manual merge required |
| `CrossPointWebServer.cpp` | Extensive additions | Minimal changes | crosspoint-ef likely compatible |
| `CrossPointSettings.h` | Many new fields | Few changes | Additive, low conflict |
| `main.cpp` | Feature integration | Minor changes | Review integration points |
| `OtaUpdater.cpp` | Modified | Reworked (#509) | Compare implementations |
### Low Conflict Risk
| Area | Notes |
|------|-------|
| Dictionary files | All new, no conflicts |
| Bookmark files | All new, no conflicts |
| CSS parser files | All new, no conflicts |
| Image converter files | All new, no conflicts |
| Custom font files | All new, no conflicts |
| StarDict library | All new, no conflicts |
---
## Testing Considerations
### Regression Testing Required
After any merge:
1. **EPUB Reading**
- Page navigation
- Chapter selection
- CSS styling
- Image rendering
- Bookmark indicators
2. **Library Functions**
- Tab navigation
- Search functionality
- Recent books display
- List management
3. **Dictionary**
- Word selection
- Lookup accuracy
- Definition display
4. **Web Server**
- File upload/download
- API endpoints
- WebSocket uploads
- mDNS discovery
5. **Settings**
- All new settings persist correctly
- Settings migration from older versions
6. **Display**
- High contrast mode
- Bezel compensation (all orientations)
- Sleep screen variations
### Memory Testing
crosspoint-ef includes memory optimization fixes. After merge:
1. Test with large EPUBs (2000+ chapters)
2. Test opening multiple books in sequence
3. Test anti-aliasing under memory pressure
4. Monitor for ghosting/artifacts
---
## Priority Recommendations
### Immediate (For crosspoint-ef Stability)
1. Cherry-pick Spanish hyphenation (#558)
2. Cherry-pick multi-line keyboard entry (#567)
3. Cherry-pick italics on image alt (#569)
4. Cherry-pick front layout fix (#564)
### Short-term (Feature Completeness)
5. Evaluate OTA rework (#509) - compare implementations
6. Cherry-pick page turn UX (#451)
7. Cherry-pick relative position fix (#486)
### Long-term (Upstream Contribution)
8. Prepare dictionary feature as PR
9. Prepare bookmark system as PR
10. Prepare CSS parsing as PR
11. Evaluate inline image support for upstream
---
## File Inventory for Merge
### Files to Add to 0.16.0 Base (for upstream contribution)
```
src/activities/dictionary/
DictionaryMargins.h
DictionaryMenuActivity.cpp
DictionaryMenuActivity.h
DictionaryResultActivity.cpp
DictionaryResultActivity.h
DictionarySearchActivity.cpp
DictionarySearchActivity.h
EpubWordSelectionActivity.cpp
EpubWordSelectionActivity.h
src/activities/util/
QuickMenuActivity.cpp
QuickMenuActivity.h
src/activities/home/
BookmarkListActivity.cpp
BookmarkListActivity.h
src/
BookmarkStore.cpp
BookmarkStore.h
BookListStore.cpp
BookListStore.h
customFonts.cpp
fontIds.h
BadgeConfig.h
src/util/
Md5Utils.cpp
Md5Utils.h
StringUtils.cpp
StringUtils.h
src/images/
LockIcon.h
lib/StarDict/
StarDict.cpp
StarDict.h
DictHtmlParser.cpp
DictHtmlParser.h
DictPrefixIndex.generated.h
lib/Epub/Epub/css/
CssParser.cpp
CssParser.h
CssStyle.h
lib/Epub/Epub/blocks/
ImageBlock.cpp
ImageBlock.h
BlockStyle.h
lib/Epub/Epub/converters/
FramebufferWriter.cpp
FramebufferWriter.h
ImageDecoderFactory.cpp
ImageDecoderFactory.h
ImageToFramebufferDecoder.cpp
ImageToFramebufferDecoder.h
JpegToFramebufferConverter.cpp
JpegToFramebufferConverter.h
PngToFramebufferConverter.cpp
PngToFramebufferConverter.h
lib/EpdFont/builtinFonts/custom/
[All font header files]
docs/
webserver-api-reference.md
companion-app-deep-link-API.md
troubleshooting.md
crosspoint-ef-features.md
crosspoint-ef-user-guide.md
```
### Files to Merge Carefully
```
src/main.cpp
src/CrossPointSettings.cpp
src/CrossPointSettings.h
src/network/CrossPointWebServer.cpp
src/network/CrossPointWebServer.h
src/network/OtaUpdater.cpp
src/network/OtaUpdater.h
src/activities/home/MyLibraryActivity.cpp
src/activities/home/MyLibraryActivity.h
src/activities/reader/EpubReaderActivity.cpp
src/activities/settings/SettingsActivity.cpp
src/activities/settings/CategorySettingsActivity.cpp
src/ScreenComponents.cpp
src/ScreenComponents.h
src/RecentBooksStore.cpp
src/RecentBooksStore.h
lib/GfxRenderer/GfxRenderer.cpp
lib/GfxRenderer/GfxRenderer.h
lib/GfxRenderer/BitmapHelpers.cpp
lib/GfxRenderer/BitmapHelpers.h
lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp
lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h
lib/Epub/Epub/Section.cpp
lib/Epub/Epub/Section.h
```
---
## Conclusion
The `crosspoint-ef` branch represents a significant enhancement over the `0.15.0` baseline with 14+ major features. Most features are cleanly isolated in new files, making selective upstream contribution feasible.
**Recommended approach:**
1. First, bring crosspoint-ef up to date with 0.16.0 bug fixes
2. Then, evaluate individual features for upstream PR submission
3. Prioritize dictionary, bookmarks, and CSS parsing as highest-value contributions
The grayscale state corruption fix in crosspoint-ef should also be submitted upstream as a critical bug fix, as it prevents display artifacts under memory pressure.

View File

@ -0,0 +1,309 @@
# CrossPoint Companion Deep Link API
This document describes the deep link functionality that allows the CrossPoint Companion Android app to be launched from QR codes displayed on CrossPoint e-reader devices.
## Overview
The CrossPoint firmware can generate QR codes containing deep link URLs. When scanned with a mobile device, these URLs launch the companion app directly to a specific tab and optionally auto-connect to the device.
## URL Scheme
```
crosspoint://<path>?<query_parameters>
```
### Components
| Component | Description |
|-----------|-------------|
| `crosspoint://` | Custom URL scheme registered by the app |
| `<path>` | Target tab in the app (see [Path Mapping](#path-mapping)) |
| `<query_parameters>` | Optional device connection parameters |
## Path Mapping
The URL path determines which tab the app navigates to:
| Path | App Tab | Description |
|------|---------|-------------|
| `files` | Device | File browser for device storage |
| `library` | Library | Local book library |
| `lists` | Lists | Reading lists management |
| `settings` | Settings | App settings |
**Note:** Unknown paths default to the Library tab.
## Query Parameters
Query parameters provide device connection information for automatic connection:
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `host` | string | *(required for auto-connect)* | IP address or hostname of the device |
| `port` | integer | `80` | HTTP API port |
| `wsPort` | integer | `81` | WebSocket port for file uploads |
## URL Examples
### Basic Navigation (No Auto-Connect)
Navigate to a specific tab without connecting to a device:
```
crosspoint://files
crosspoint://library
crosspoint://lists
crosspoint://settings
```
### Auto-Connect to Device
Navigate to Device tab and auto-connect:
```
crosspoint://files?host=192.168.1.100
crosspoint://files?host=192.168.1.100&port=80&wsPort=81
```
### Custom Ports
Connect to a device with non-default ports:
```
crosspoint://files?host=192.168.1.100&port=8080&wsPort=8081
```
### Hostname Instead of IP
```
crosspoint://files?host=crosspoint.local&port=80&wsPort=81
```
## Firmware Implementation
### QR Code Generation
The CrossPoint firmware should generate QR codes containing the deep link URL. Example format:
```
crosspoint://files?host=<device_ip>&port=<http_port>&wsPort=<ws_port>
```
Where:
- `<device_ip>` is the device's current IP address (e.g., from WiFi connection)
- `<http_port>` is the HTTP API port (default: 80)
- `<ws_port>` is the WebSocket port (default: 81)
### Example Firmware Code (C++)
```cpp
String generateDeepLinkUrl(const char* path = "files") {
String url = "crosspoint://";
url += path;
url += "?host=";
url += WiFi.localIP().toString();
url += "&port=";
url += String(HTTP_PORT); // e.g., 80
url += "&wsPort=";
url += String(WS_PORT); // e.g., 81
return url;
}
// Generate QR code with:
// String url = generateDeepLinkUrl("files");
// displayQRCode(url);
```
## App Behavior
### Launch Scenarios
#### 1. App Not Running
When the app is launched via deep link:
1. App starts and parses the deep link URL
2. Navigates to the target tab
3. If device connection info is present and target is "files":
- Checks for existing device with matching IP
- If found: uses existing device (preserving user's custom name)
- If not found: creates temporary connection
- Attempts to connect automatically
#### 2. App Already Running
When a deep link is received while the app is open:
1. `onNewIntent` receives the new URL
2. Navigates to the target tab
3. Handles device connection (same as above)
### Device Matching Logic
When connecting via deep link:
```
1. Look up device by IP address in database
2. If device exists:
a. Check if ports match
b. If ports differ, update the stored device with new ports
c. Connect using the existing device (preserves custom name)
3. If device doesn't exist:
a. Create temporary Device object (not saved to database)
b. Connect using temporary device
c. Display as "CrossPoint (<ip>)"
```
### Error Handling
| Scenario | Behavior |
|----------|----------|
| Malformed URL | App opens to Library tab (default) |
| Unknown path | App opens to Library tab with warning logged |
| Invalid host format | Navigation succeeds, no auto-connect |
| Invalid port values | Default ports used (80, 81) |
| Connection failure | Error message displayed, user can retry |
| Device unreachable | Error message with device IP shown |
## Android Implementation Details
### Intent Filter (AndroidManifest.xml)
```xml
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="crosspoint" />
</intent-filter>
```
### Key Classes
| Class | Purpose |
|-------|---------|
| `DeepLinkParser` | Parses URI into `DeepLinkData` |
| `DeepLinkData` | Data class holding parsed deep link info |
| `DeviceConnectionInfo` | Data class for host/port/wsPort |
| `MainActivity` | Handles incoming intents |
| `CrossPointApp` | Routes navigation based on deep link |
| `DeviceBrowserViewModel` | Handles `connectFromDeepLink()` |
### Data Flow
```
QR Code Scan
Android Intent (ACTION_VIEW)
MainActivity.onCreate() / onNewIntent()
DeepLinkParser.parse(uri)
DeepLinkData { targetTab, deviceConnection? }
CrossPointApp (LaunchedEffect)
├─► Navigate to targetTab
└─► If targetTab == Device && deviceConnection != null
DeviceBrowserScreen
DeviceBrowserViewModel.connectFromDeepLink()
├─► Check existing device by IP
├─► Update ports if needed
└─► Connect and load files
```
## Validation Rules
### Host Validation
Valid hosts:
- IPv4 addresses: `192.168.1.100`, `10.0.0.1`
- Hostnames: `crosspoint.local`, `my-device`
Invalid hosts (rejected):
- Empty strings
- Malformed IPs: `192.168.1.256`, `192.168.1`
- IPs with invalid octets
### Port Validation
- Valid range: 1-65535
- Out-of-range values default to 80 (HTTP) or 81 (WebSocket)
- Non-numeric values default to standard ports
## Testing
### Manual Testing with ADB
Test deep links without a QR code using ADB:
```bash
# Basic navigation
adb shell am start -a android.intent.action.VIEW -d "crosspoint://files"
adb shell am start -a android.intent.action.VIEW -d "crosspoint://library"
# With device connection
adb shell am start -a android.intent.action.VIEW -d "crosspoint://files?host=192.168.1.100"
adb shell am start -a android.intent.action.VIEW -d "crosspoint://files?host=192.168.1.100&port=80&wsPort=81"
# Test while app is running (onNewIntent)
adb shell am start -a android.intent.action.VIEW -d "crosspoint://settings"
```
### Test Cases
1. **Valid deep link with connection info**
- URL: `crosspoint://files?host=192.168.1.100&port=80&wsPort=81`
- Expected: Opens Device tab, auto-connects to device
2. **Valid deep link without connection info**
- URL: `crosspoint://files`
- Expected: Opens Device tab, shows device selection
3. **Unknown path**
- URL: `crosspoint://unknown`
- Expected: Opens Library tab (default)
4. **Missing host parameter**
- URL: `crosspoint://files?port=80`
- Expected: Opens Device tab, no auto-connect
5. **Invalid host format**
- URL: `crosspoint://files?host=invalid..host`
- Expected: Opens Device tab, no auto-connect
6. **Device already exists in database**
- Precondition: Device with IP 192.168.1.100 saved as "My Reader"
- URL: `crosspoint://files?host=192.168.1.100`
- Expected: Connects using "My Reader" name
7. **Existing device with different ports**
- Precondition: Device saved with port=80, wsPort=81
- URL: `crosspoint://files?host=192.168.1.100&port=8080&wsPort=8081`
- Expected: Updates device ports, then connects
## Security Considerations
1. **Local Network Only**: Deep links should only contain local network addresses. The app does not validate this, but firmware should only generate URLs with local IPs.
2. **No Authentication**: The deep link does not include authentication. Device security relies on network-level access control.
3. **Temporary Devices**: Devices created from deep links (when no matching device exists) are not persisted, preventing automatic accumulation of device entries.
4. **No Sensitive Data**: Deep link URLs should not contain sensitive information as QR codes can be photographed.
## Changelog
| Version | Changes |
|---------|---------|
| 1.0.0 | Initial deep link support with `crosspoint://` scheme |

View File

@ -0,0 +1,603 @@
# CrossPoint-EF Branch Features
This document describes the features and enhancements unique to the `crosspoint-ef` branch, which diverged from CrossPoint Reader at version `0.15.0`.
## Overview
The `crosspoint-ef` branch introduces significant new functionality including:
- **Dictionary Support** - Offline StarDict dictionary with word selection from reader
- **Bookmark System** - Per-book bookmarks with visual indicators and management
- **Quick Menu** - Fast access to common actions via power button
- **Library Search** - Search across all books by title, author, or filename
- **CSS Support** - Parse and apply CSS styles from EPUB files
- **Inline Images** - PNG and Baseline JPEG image rendering within EPUBs
- **Custom Fonts** - Atkinson Hyperlegible Next and Fern Micro accessibility fonts
- **Enhanced Web Server** - File management, companion app API, mDNS discovery
- **Reading Lists** - Create, manage, and pin custom book lists
- **Display Enhancements** - High contrast mode, bezel compensation, sleep screen improvements
---
## Major Features
### 1. Dictionary Support
Full offline dictionary lookup using the StarDict format with fast prefix-indexed search.
**Features:**
- Word selection directly from EPUB pages
- Manual word entry via on-screen keyboard
- Rich HTML formatting in definitions (bold, italic, lists)
- Multi-page definitions with pagination
- Synonym support
- Case-insensitive search with prefix optimization
**Access Methods:**
- **Quick Menu** → Dictionary
- **Power Button** (when configured to `Dictionary` action)
**Dictionary Format:**
- StarDict format with dictzip compression
- Files located at `/dictionaries/dict-data` on SD card:
- `dict-data.ifo` - Metadata
- `dict-data.idx` - Word index
- `dict-data.dict.dz` - Compressed definitions
- `dict-data.syn` - Synonyms (optional)
**Technical Implementation:**
- Files: `src/activities/dictionary/`, `lib/StarDict/`
- Prefix jump table for near-instant lookups
- On-demand chunk decompression using miniz
- HTML definition parsing with entity decoding
---
### 2. Bookmark System
Per-book bookmark storage with visual indicators and dedicated management interface.
**Features:**
- Add/remove bookmarks from current page
- Visual folded-corner indicator on bookmarked pages
- Bookmarks tab in library showing all books with bookmarks
- Long-press to delete bookmarks
- Auto-generated bookmark names ("Chapter Title - Page X")
- Maximum 100 bookmarks per book
**Storage:**
- Binary file per book: `/.crosspoint/{epub_|txt_}<hash>/bookmarks.bin`
- Stores: name, spine index, content offset, page number, timestamp
**Technical Implementation:**
- Files: `src/BookmarkStore.cpp/.h`, `src/activities/home/BookmarkListActivity.cpp/.h`
- Bookmark identification by `spineIndex + contentOffset` (stable across re-renders)
---
### 3. Quick Menu
In-reader quick access menu for common actions, triggered by short power button press.
**Menu Options:**
1. **Dictionary** - Look up a word
2. **Bookmark** - Add/Remove bookmark (state-aware text)
3. **Clear Cache** - Free up storage space
4. **Settings** - Open settings menu
**Configuration:**
- Settings → Controls → Short Power Button Click → `Quick Menu`
**Technical Implementation:**
- File: `src/activities/util/QuickMenuActivity.cpp/.h`
- Renders overlay with navigation and selection
---
### 4. Library Search with Character Picker
Search across all books using a dynamic character picker interface.
**Features:**
- Character picker with dynamically generated character set from library content
- Weighted search scoring:
- Title match: 100 points (+50 if at start)
- Author match: 80 points (+40 if at start)
- Path match: 30 points
- Results sorted by relevance score
- Special controls: SPC (space), ← (backspace), CLR (clear)
**Navigation:**
- Left/Right: Select character
- Confirm: Add character to query
- Up/Down: Switch between picker and results
**Technical Implementation:**
- Integrated in `src/activities/home/MyLibraryActivity.cpp`
- Search tab accessible from library tab bar
---
### 5. CSS Support for EPUBs
Parse and apply CSS styles from EPUB stylesheets.
**Supported Selectors:**
- Element selectors: `p`, `div`, `h1`, etc.
- Class selectors: `.classname`
- Combined selectors: `element.classname`
- Grouped selectors: `h1, h2, h3`
- Inline styles: `style="..."`
**Supported Properties:**
- `text-align` (left, center, right, justify)
- `font-style` (normal, italic)
- `font-weight` (normal, bold)
- `text-decoration` (underline)
- `text-indent`
- `margin-top`, `margin-bottom`
- `padding-top`, `padding-bottom`
**Cascade Order:**
1. Element styles
2. Class styles
3. Element.class styles
4. Inline styles
**Technical Implementation:**
- Files: `lib/Epub/Epub/css/CssParser.cpp/.h`, `CssStyle.h`
- CSS files parsed during EPUB loading
- Styles applied during HTML parsing via `ChapterHtmlSlimParser`
---
### 6. Inline Image Support (PNG/Baseline JPEG)
Render embedded images within EPUB content.
**Supported Formats:**
- Baseline JPEG (.jpg, .jpeg)
- PNG (.png)
**Features:**
- Images decoded to 2-bit grayscale with dithering
- Image caching as `.pxc` files (2 bits per pixel, packed format)
- Row-by-row rendering to minimize memory usage
- Automatic scaling to fit page width
**Technical Implementation:**
- Files: `lib/Epub/Epub/blocks/ImageBlock.cpp/.h`
- Converters: `JpegToFramebufferConverter`, `PngToFramebufferConverter`
- Factory: `ImageDecoderFactory` routes to appropriate decoder
---
### 7. Custom Fonts
Additional accessibility-focused fonts beyond the standard Bookerly and Noto Sans.
**Available Fonts:**
1. **Atkinson Hyperlegible Next** - Designed for low-vision readers
2. **Fern Micro** - Optimized for small screens
**Font Sizes:**
- 12pt, 14pt, 16pt, 18pt for each font
- Full style support: Regular, Italic, Bold, Bold Italic
**Configuration:**
- Settings → Reader → Font Family → Custom
- Settings → Reader → Custom Font → [Select font]
- Settings → Reader → Fallback Font → [Bookerly/Noto Sans]
**Technical Implementation:**
- Files: `src/customFonts.cpp`, `src/fontIds.h`
- Font headers: `lib/EpdFont/builtinFonts/custom/`
- Conversion scripts: `lib/EpdFont/scripts/convert-builtin-fonts.sh`
---
### 8. Enhanced Web Server
Extended web server with file management operations and companion app support.
**File Operations:**
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/files` | GET | List files with MD5 hashes for EPUBs |
| `/api/status` | GET | Device status (version, IP, heap, uptime) |
| `/api/archived` | GET | List archived books |
| `/api/hash` | GET | Compute/retrieve MD5 hash for sync |
| `/download` | GET | Download files |
| `/upload` | POST | Upload files (multipart) |
| `/delete` | POST | Delete files/folders |
| `/archive` | POST | Archive a book |
| `/unarchive` | POST | Restore archived book |
| `/rename` | POST | Rename files/folders |
| `/copy` | POST | Copy files/folders |
| `/move` | POST | Move files/folders |
| `/mkdir` | POST | Create folders |
| `/list` | GET/POST | Manage reading lists |
**WebSocket Upload (Port 81):**
- Fast binary uploads for large files
- Protocol: `START:<filename>:<size>:<path>``READY` → binary chunks → `DONE`
- Progress updates: `PROGRESS:<received>:<total>`
**mDNS Discovery:**
- Hostname: `crosspoint.local`
- Service: `_http._tcp` on port 80
- UDP discovery on port 8134
**Deep Link Support:**
- URL scheme: `crosspoint://<path>?host=<ip>&port=<port>&wsPort=<wsPort>`
- Paths: `files`, `library`, `lists`, `settings`
**Technical Implementation:**
- Files: `src/network/CrossPointWebServer.cpp/.h`
- MD5 Utils: `src/util/Md5Utils.cpp/.h`
- Docs: `docs/webserver-api-reference.md`, `docs/companion-app-deep-link-API.md`
---
### 9. Reading Lists with Pinning
Create and manage custom book lists with pinning support.
**Features:**
- Create, load, delete lists
- Pin a list to show on home screen
- List contents displayed with book metadata
- Web API for list upload/download (CSV format)
**Storage:**
- Lists stored in `/.lists/` as `.bin` files
- CSV format for API: `order,title,author,path`
**Configuration:**
- Library → Lists tab → Long-press → Pin/Unpin
- Pinned list name shown on home screen Lists button
**Technical Implementation:**
- Files: `src/BookListStore.cpp/.h`
- Pinned list stored in `SETTINGS.pinnedListName`
---
### 10. Display Enhancements
#### High Contrast Mode
System-wide display contrast adjustment for improved readability.
- **Normal mode:** Standard grayscale thresholds
- **High contrast mode:** Pushes mid-grays toward black/white
**Configuration:**
- Settings → Display → High Contrast → On/Off
#### Bezel Compensation
Compensate for physical screen edge defects with configurable margin.
- **Range:** 0-10 pixels
- **Edges:** Bottom, Top, Left, Right
- **Behavior:** Margin rotates with screen orientation
**Configuration:**
- Settings → Display → Bezel Compensation → [0-10]
- Settings → Display → Bezel Edge → [Bottom/Top/Left/Right]
#### Sleep Screen Improvements
Enhanced sleep screen with edge-aware color filling.
- **Edge luminance detection:** Samples edge pixels for dominant color
- **Letterbox fill:** Fills letterbox regions with edge colors for seamless appearance
- **Two-level caching:**
- Per-BMP cache: `.bmp.perim` files store edge luminance
- Book-level cache: `edge.bin` stores cover data
---
### 11. Recents View Improvements
Enhanced recent books display with metadata and management.
**Features:**
- **Badges:** Extension and suffix tags (e.g., "epub", "X4")
- **Metadata display:** Title and author from EPUB
- **Remove from recents:** Long-press → Remove from Recents
- **Clear all:** Long-press → Clear All Recents
**Badge Configuration:**
- Extension badges: `.epub` → "epub", `.txt` → "txt"
- Suffix badges: `-x4` → "X4", `-x4p` → "X4P"
**Technical Implementation:**
- Files: `src/RecentBooksStore.cpp/.h`
- Badge config: `src/BadgeConfig.h`
- String utils: `src/util/StringUtils.cpp/.h`
---
### 12. Enhanced Tab Bar
Unified tab bar with scrolling and overflow indicators.
**Features:**
- Horizontal scrolling when tabs exceed available width
- Overflow indicators (< >) when content extends beyond view
- Selected tab highlighting with underline
- Bullet cursors for focus mode
**Tabs:**
- Recent, Lists, Bookmarks, Search, Files
**Technical Implementation:**
- Files: `src/ScreenComponents.cpp/.h`
- Used in `MyLibraryActivity` for library navigation
---
### 13. Progress Bar Status Bar
Additional status bar option showing visual progress bar.
**Options:**
- `Full w/ Progress Bar` - Full status bar with progress bar
- `Progress Bar` - Only progress bar, no other status info
**Configuration:**
- Settings → Display → Status Bar
---
### 14. Additional Settings
New configuration options unique to crosspoint-ef:
| Setting | Options | Description |
|---------|---------|-------------|
| Short Power Button Click | Ignore, Sleep, Page Turn, Dictionary, Quick Menu | Map power button to action |
| Bezel Compensation | 0-10 pixels | Edge defect compensation |
| Bezel Edge | Bottom, Top, Left, Right | Which edge to compensate |
| High Contrast | Off, On | System-wide contrast boost |
| Custom Font | [Font list] | Select custom font |
| Fallback Font | Bookerly, Noto Sans | Fallback for custom fonts |
---
### 15. OPDS Browser Enhancements
Improved OPDS catalog browsing experience.
**Features:**
- **Navigation history stack** - Back button navigates through visited feeds
- **Page skipping** - Hold Up/Down for 700ms to skip 23 items at once
- **Error retry mechanism** - Retry button on error screens with WiFi status check
- **HTTP Basic Authentication** - Username/password support for protected OPDS servers
**Configuration:**
- Settings → System → Calibre Settings → OPDS Server URL
- Settings → System → Calibre Settings → Username/Password
**Technical Implementation:**
- Files: `src/activities/browser/OpdsBookBrowserActivity.cpp`
- Authentication: `src/network/HttpDownloader.cpp`
---
### 16. Development Tools
Scripts and utilities for firmware development.
**Scripts:**
| Script | Purpose |
|--------|---------|
| `pre_flash.py` | Displays "Flashing firmware..." screen during upload |
| `debugging_monitor.py` | Enhanced serial monitor with memory graphs and color output |
| `pio_helper.py` | Interactive PlatformIO workflow helper with presets |
| `version_hash.py` | Embeds git commit hash in dev builds |
| `build_html.py` | Minifies HTML files for web server |
**Firmware Flashing Screen:**
- Full-screen display during firmware upload
- Shows "Flashing firmware..." with version info
- Lock icon indicates USB port location
- Prevents accidental disconnection
**Debug/Memory Monitoring:**
- `DEBUG_MEMORY` build mode for heap tracking at activity transitions
- Periodic memory logging every 10 seconds (when Serial connected)
- Loop duration warnings when exceeding 50ms
- Detailed heap fragmentation info
**Technical Implementation:**
- Scripts: `scripts/pre_flash.py`, `scripts/debugging_monitor.py`, `scripts/pio_helper.py`
- Flash screen: `src/main.cpp` (lines 138-247)
- Memory monitoring: `src/main.cpp` (lines 549-562)
- Build config: `platformio.ini` (`debug_memory` environment)
---
### 17. Power Management Enhancements
Optimizations for battery life and responsiveness.
**Features:**
- **Auto-sleep prevention** - Background tasks (web server, OTA, downloads) prevent auto-sleep
- **USB connection detection** - Serial only starts when USB is connected (saves power)
- **Skip loop delay** - Activities can request faster loop execution for responsive HTTP handling
- **Power button release wait** - Prevents immediate wake if button is still held
**Technical Implementation:**
- Files: `src/main.cpp`, `src/activities/Activity.h`
- Methods: `preventAutoSleep()`, `skipLoopDelay()`
---
## Bug Fixes
### Unique to crosspoint-ef
1. **Grayscale state corruption fix** - Prevents ghosting and gray filter artifacts when anti-aliasing is enabled under memory pressure
2. **Memory optimization** - Graceful degradation when memory is low (skip anti-aliasing instead of corrupting display)
### Shared with 0.16.0
- Large EPUB indexing optimization (O(n²) → O(n))
- Settings validation on read
- Line break fixes (flush word before `<br/>`)
- Rotate origin in `drawImage()`
- Short-press power button to wakeup
- Add txt books to recent tab
- B&W filters for cover images
---
## Missing or Removed Features from 0.16.0
The following features are present in the upstream `0.16.0` release but are missing or were removed in `crosspoint-ef`:
### Removed Features
#### 1. KOReader Sync Support (Removed)
The entire KOReader sync functionality has been removed.
**What was removed:**
- `lib/KOReaderSync/` library (8 files deleted)
- Progress sync with KOReader sync server (`sync.koreader.rocks`)
- Document MD5 binary matching for progress synchronization
- KOReader credential storage
**Impact:**
- Cannot sync reading progress with KOReader app
- Chapter Selection UI fixes for KOReader sync (#501) not applicable
**Files deleted:**
- `KOReaderSyncClient.cpp/.h`
- `KOReaderCredentialStore.cpp/.h`
- `KOReaderDocumentId.cpp/.h`
- `ProgressMapper.cpp/.h`
---
#### 2. Non-English Hyphenation Patterns (Removed)
Hyphenation pattern files for non-English languages have been removed.
**What was removed:**
- `hyph-es.trie.h` - Spanish hyphenation
- `hyph-de.trie.h` - German hyphenation
- `hyph-fr.trie.h` - French hyphenation
- `hyph-ru.trie.h` - Russian hyphenation
**Impact:**
- Only English hyphenation patterns remain
- Non-English books will not hyphenate correctly
- Spanish hyphenation support (#558) not available
**Note:** These can be restored by copying the trie files from 0.16.0.
---
#### 3. XTC/XTCH File Support (Removed)
Support for the XTC/XTCH proprietary format has been removed.
**What was removed:**
- Author extraction from XTC/XTCH files (#563)
- XTC format handling in file browsers
**Impact:**
- XTC/XTCH files cannot be read
- Author metadata not extracted from these formats
---
### Missing Bug Fixes
The following bug fixes from 0.16.0 have not been applied to crosspoint-ef:
| PR | Description | Impact |
|----|-------------|--------|
| #567 | Multi-line keyboard entry | Long text input truncated with "..." instead of wrapping |
| #569 | Italics on image alt text | Image alt placeholders don't render in italics |
| #564 | Front layout in mapLabels() | Button mapping may be incorrect in some layouts |
| #486 | Relative position on settings change | Reader may jump to different location when settings change |
| #501 | Chapter Selection UI (KOReader) | N/A - KOReader sync removed |
| #529 | KOReader MD5 binary matching | N/A - KOReader sync removed |
---
### Missing UX Enhancements
| PR | Description | Impact |
|----|-------------|--------|
| #451 | Page turn on button press | When long-press chapter skip is disabled, 0.16.0 allows page turn on button press; crosspoint-ef does not |
---
### Different Implementation: OTA Updates
The OTA update mechanism uses a different implementation:
| Aspect | crosspoint-ef | 0.16.0 |
|--------|---------------|--------|
| HTTP Client | Arduino `HTTPClient` | ESP-IDF `esp_http_client` |
| OTA Library | Arduino `Update` | ESP-IDF `esp_https_ota` |
| Memory Management | Standard | Improved with custom buffer handling |
**Impact:**
- Both implementations work, but 0.16.0's ESP-IDF approach may be more memory-efficient
- Consider evaluating 0.16.0's OTA rework (#509) for potential adoption
---
### Recommendation for Missing Features
**High Priority to Cherry-pick:**
1. Multi-line keyboard entry (#567) - Improves UX for long inputs
2. Front layout fix (#564) - Bug fix for button mapping
3. Relative position on settings change (#486) - Improves reader UX
**Medium Priority:**
4. Restore hyphenation patterns for non-English languages
5. Italics on image alt (#569) - Minor visual improvement
6. Page turn on button press (#451) - UX enhancement
**Evaluate:**
7. OTA rework (#509) - Compare implementations for memory benefits
8. KOReader sync - Restore if sync functionality is desired
---
## File Summary
| Feature | Primary Files |
|---------|---------------|
| Dictionary | `src/activities/dictionary/`, `lib/StarDict/` |
| Bookmarks | `src/BookmarkStore.*`, `src/activities/home/BookmarkListActivity.*` |
| Quick Menu | `src/activities/util/QuickMenuActivity.*` |
| Search | `src/activities/home/MyLibraryActivity.cpp` |
| CSS | `lib/Epub/Epub/css/` |
| Images | `lib/Epub/Epub/blocks/ImageBlock.*`, `lib/Epub/Epub/converters/` |
| Custom Fonts | `src/customFonts.cpp`, `lib/EpdFont/builtinFonts/custom/` |
| Web Server | `src/network/CrossPointWebServer.*`, `src/util/Md5Utils.*` |
| Lists | `src/BookListStore.*` |
| Settings | `src/CrossPointSettings.*` |
| Tab Bar | `src/ScreenComponents.*` |
| Recents | `src/RecentBooksStore.*`, `src/BadgeConfig.h` |
| OPDS Browser | `src/activities/browser/OpdsBookBrowserActivity.*` |
| Dev Tools | `scripts/pre_flash.py`, `scripts/debugging_monitor.py`, `scripts/pio_helper.py` |
| Power Management | `src/main.cpp`, `src/activities/Activity.h` |
---
## Version Information
- **Base version:** 0.15.0
- **Branch:** crosspoint-ef
- **Commits since divergence:** 90+
- **Files changed:** 250+

View File

@ -0,0 +1,555 @@
# CrossPoint-EF User Guide Supplement
This guide covers the additional features available in the `crosspoint-ef` branch. For basic operation, refer to the main [User Guide](../USER_GUIDE.md).
## Table of Contents
- [Dictionary](#dictionary)
- [Bookmarks](#bookmarks)
- [Quick Menu](#quick-menu)
- [Library Search](#library-search)
- [Reading Lists](#reading-lists)
- [Display Settings](#display-settings)
- [Web Server Features](#web-server-features)
- [Custom Fonts](#custom-fonts)
- [Additional Settings](#additional-settings)
---
## Dictionary
The dictionary feature provides offline word lookup while reading.
### Setup
1. Download a StarDict dictionary (English-English dictionary provided as `dict-en-en.zip`)
2. Extract the dictionary files to `/dictionaries/dict-data/` on your SD card
3. You should have these files:
- `dict-data.ifo`
- `dict-data.idx`
- `dict-data.dict.dz`
- `dict-data.syn` (optional, for synonyms)
### Using the Dictionary
#### Method 1: Quick Menu
1. While reading, press the **Power** button briefly (requires Quick Menu to be configured)
2. Select **Dictionary** from the menu
3. Choose **Select from Screen** or **Enter a Word**
#### Method 2: Direct Power Button Access
1. Go to **Settings → Controls → Short Power Button Click**
2. Set to **Dictionary**
3. While reading, press the **Power** button briefly to open the dictionary
### Selecting a Word from the Page
1. Choose **Select from Screen** from the dictionary menu
2. The current page will display with word selection enabled
3. Use **Left/Right** to move between words
4. Use **Up/Down** to jump between lines
5. Press **Confirm** to look up the selected word
6. Press **Back** to cancel
### Viewing Definitions
- Definitions display with rich formatting (bold, italic, lists)
- Use **Left/Right** or **Volume Up/Down** to navigate between pages if the definition is long
- Press **Confirm** to search for another word
- Press **Back** to return to your book
---
## Bookmarks
Create and manage bookmarks within your books.
### Adding a Bookmark
#### Method 1: Quick Menu
1. Press the **Power** button briefly (requires Quick Menu to be configured)
2. Select **Add Bookmark** (or **Remove Bookmark** if already bookmarked)
#### Method 2: Settings Configuration
1. Go to **Settings → Controls → Short Power Button Click**
2. Set to **Quick Menu**
3. Use Quick Menu to toggle bookmarks
### Bookmark Indicator
When a page is bookmarked, a small folded corner triangle appears in the top-right corner of the page.
### Viewing Bookmarks
1. Go to **Home → Library**
2. Select the **Bookmarks** tab
3. You'll see a list of books that have bookmarks
4. Select a book to view its bookmarks
5. Select a bookmark to jump to that location
### Deleting Bookmarks
1. Open a book's bookmark list (from Bookmarks tab)
2. Navigate to the bookmark you want to delete
3. **Long-press Confirm** (hold for about 1 second)
4. Confirm deletion when prompted
### Bookmark Naming
Bookmarks are automatically named based on:
- Chapter title and page number (e.g., "Chapter 3 - Page 42")
- Just page number if no chapter title (e.g., "Page 15")
---
## Quick Menu
Fast access to common actions while reading.
### Enabling Quick Menu
1. Go to **Settings → Controls → Short Power Button Click**
2. Select **Quick Menu**
### Using Quick Menu
1. While reading, press the **Power** button briefly
2. Navigate with **Up/Down** or **Left/Right**
3. Press **Confirm** to select an option
4. Press **Back** to close the menu
### Quick Menu Options
| Option | Description |
|--------|-------------|
| **Dictionary** | Look up a word |
| **Add/Remove Bookmark** | Toggle bookmark on current page |
| **Clear Cache** | Free up storage space |
| **Settings** | Open settings menu |
---
## Library Search
Search your library by title, author, or filename.
### Accessing Search
1. Go to **Home → Library**
2. Select the **Search** tab
3. Or from any tab, scroll to the bottom and select **Search...**
### Using the Character Picker
The search uses a character picker interface:
1. **Left/Right** - Move between characters
2. **Confirm** - Add character to search query
3. **SPC** - Add a space
4. **←** - Delete last character (backspace)
5. **CLR** - Clear entire query
### Navigating Results
1. After entering characters, results appear below
2. Press **Down** to move from character picker to results
3. **Left/Right** to navigate results
4. **Confirm** to open a book
5. **Up** to return to character picker
### Search Scoring
Results are ranked by relevance:
- Title matches rank highest
- Author matches rank second
- Filename matches rank lowest
- Matches at the start of a field rank higher
---
## Reading Lists
Create custom book lists for organizing your library.
### Viewing Lists
1. Go to **Home → Library**
2. Select the **Lists** tab
3. Available lists are displayed
### Opening a List
1. Navigate to a list name
2. Press **Confirm** to view the list contents
3. Select a book to start reading
### Pinning a List
Pin a list to quickly access it from the home screen:
1. In the Lists tab, navigate to a list
2. **Long-press Confirm** to open the action menu
3. Select **Pin List**
The pinned list name will appear on the Lists button on the home screen.
### Unpinning a List
1. Navigate to the pinned list
2. **Long-press Confirm**
3. Select **Unpin List**
### Deleting a List
1. Navigate to a list
2. **Long-press Confirm**
3. Select **Delete List**
4. Confirm deletion
### Creating Lists via Web Server
Lists can be created and uploaded via the web server API. See [Web Server Features](#web-server-features).
---
## Display Settings
### High Contrast Mode
Increases contrast across the entire UI for better readability.
1. Go to **Settings → Display → High Contrast**
2. Set to **On** or **Off**
When enabled, mid-gray tones are pushed toward black or white.
### Bezel Compensation
Compensate for physical screen edge defects (common on some devices).
1. Go to **Settings → Display → Bezel Compensation**
2. Set value from **0** (disabled) to **10** pixels
3. If compensation is enabled, select **Bezel Edge**:
- **Bottom** - Default, compensates bottom edge
- **Top** - Compensates top edge
- **Left** - Compensates left edge
- **Right** - Compensates right edge
The compensation margin automatically rotates with screen orientation.
### Status Bar Options
Additional status bar display options:
| Option | Description |
|--------|-------------|
| None | No status bar |
| No Progress | Status bar without reading progress |
| Full w/ Percentage | Status bar with percentage progress |
| Full w/ Progress Bar | Status bar with visual progress bar |
| Progress Bar | Only progress bar, no other info |
Configure at **Settings → Display → Status Bar**.
### Sleep Screen Cover Filter
When using book cover as sleep screen:
| Filter | Effect |
|--------|--------|
| None | Grayscale image as-is |
| Contrast | Black and white only (no grays) |
| Inverted | Inverted black and white |
Configure at **Settings → Display → Sleep Screen Cover Filter**.
---
## Web Server Features
The web server provides extended file management and companion app support.
### Starting the Web Server
1. Go to **Home → File Transfer**
2. Select a WiFi network or create a hotspot
3. The web server URL will be displayed
### File Management
Access the file manager at `http://<device-ip>/files`
**Available Operations:**
- **Upload** - Upload files via drag-and-drop or file picker
- **Download** - Download files to your computer
- **Delete** - Remove files and folders
- **Rename** - Rename files and folders
- **Create Folder** - Create new directories
- **Archive/Unarchive** - Archive books (preserves reading progress)
- **Copy/Move** - Copy or move files and folders
### API Access
The web server provides a JSON API for programmatic access:
| Endpoint | Description |
|----------|-------------|
| `GET /api/status` | Device status |
| `GET /api/files?path=/` | List files |
| `GET /api/archived` | List archived books |
| `GET /api/hash?path=/book.epub` | Get MD5 hash |
### mDNS Discovery
The device advertises itself as `crosspoint.local` on your network.
### Companion App Support
The web server supports the CrossPoint Companion Android app:
1. **QR Code** - Scan the QR code displayed on the web server screen
2. **Deep Links** - URLs like `crosspoint://files?host=192.168.1.100` open the app directly
### Managing Reading Lists via API
**Get all lists:**
```
GET /list
```
**Get specific list:**
```
GET /list?name=MyList
```
**Upload a list:**
```
POST /list?action=upload&name=MyList
Content-Type: text/plain
1,Book Title,Author Name,/path/to/book.epub
2,Another Book,Another Author,/path/to/another.epub
```
**Delete a list:**
```
POST /list?action=delete&name=MyList
```
---
## Custom Fonts
Two additional accessibility-focused fonts are available.
### Available Custom Fonts
1. **Atkinson Hyperlegible Next** - Designed for low-vision readers with high character differentiation
2. **Fern Micro** - Optimized for small screens
### Enabling Custom Fonts
1. Go to **Settings → Reader → Font Family**
2. Select **Custom**
3. Go to **Settings → Reader → Custom Font**
4. Select your preferred font
### Fallback Font
When using custom fonts, set a fallback for missing glyphs:
1. Go to **Settings → Reader → Fallback Font**
2. Choose **Bookerly** or **Noto Sans**
---
## Additional Settings
### Short Power Button Actions
Configure what happens when you briefly press the Power button:
| Option | Action |
|--------|--------|
| Ignore | No action (default) |
| Sleep | Put device to sleep |
| Page Turn | Turn to next page |
| Dictionary | Open dictionary |
| Quick Menu | Open quick menu |
Configure at **Settings → Controls → Short Power Button Click**.
### Long-press Chapter Skip
Control side button long-press behavior:
- **On** (default) - Long-press Volume buttons to skip chapters
- **Off** - Long-press scrolls a page instead
Configure at **Settings → Controls → Long-press Chapter Skip**.
### Hyphenation
Enable word hyphenation for justified text:
1. Go to **Settings → Reader → Hyphenation**
2. Set to **On**
Hyphenation patterns are available for multiple languages (English, German, French, Spanish, Russian, etc.).
---
## Recents View Enhancements
### Badges
Books in the Recent tab display badges showing:
- **File extension** (epub, txt, md)
- **Suffix tags** (X4, X4P for files with `-x4` or `-x4p` suffixes)
### Removing from Recents
1. Navigate to a book in the Recent tab
2. **Long-press Confirm**
3. Select **Remove from Recents**
### Clearing All Recents
1. Navigate to any book in the Recent tab
2. **Long-press Confirm**
3. Select **Clear All Recents**
4. Confirm the action
---
## Tab Navigation
The library uses a unified tab bar for navigation.
### Tabs Available
| Tab | Contents |
|-----|----------|
| Recent | Recently opened books |
| Lists | Custom reading lists |
| Bookmarks | Books with bookmarks |
| Search | Search all books |
| Files | File browser |
### Navigating Tabs
When the tab bar is focused:
- **Left/Right** - Switch between tabs
- **Down** - Enter the selected tab's content
- **Confirm** - Same as Down
### Tab Overflow
When tabs don't fit on screen:
- **<** indicator appears on left when more tabs exist to the left
- **>** indicator appears on right when more tabs exist to the right
- Scroll continues automatically when navigating past visible tabs
---
## Inline Images
EPUBs with embedded images now display them inline with text.
### Supported Formats
- JPEG (.jpg, .jpeg)
- PNG (.png)
### Image Display
- Images are automatically scaled to fit the page width
- Images are converted to 4-level grayscale with dithering
- First load may be slower as images are processed
- Subsequent loads use cached versions
### Image Cache
Processed images are cached as `.pxc` files in the book's cache directory for faster loading.
---
## Troubleshooting
### Dictionary Not Working
1. Verify dictionary files are in `/dictionaries/dict-data/`
2. Check that all required files exist (.ifo, .idx, .dict.dz)
3. File names must match exactly (case-sensitive)
### Bookmarks Not Saving
1. Ensure SD card is not write-protected
2. Check available storage space
3. Bookmarks are saved per-book in `/.crosspoint/`
### Search Not Finding Books
1. Search only indexes books in the library
2. Ensure books have proper EPUB metadata
3. Try searching by filename if metadata is missing
### Images Not Displaying
1. Only PNG and JPEG formats are supported
2. Very large images may fail to load due to memory constraints
3. Check for sufficient free memory (multiple large books open may exhaust memory)
### Web Server Connection Issues
1. Ensure device and computer are on the same network
2. Try accessing via IP address instead of `crosspoint.local`
3. Check that firewall isn't blocking port 80
---
## Keyboard Shortcuts Summary
### In Reader
| Button | Action |
|--------|--------|
| Left/Volume Up | Previous page |
| Right/Volume Down | Next page |
| Left (hold) | Previous chapter |
| Right (hold) | Next chapter |
| Back | Return to library |
| Back (hold) | Return to home |
| Confirm | Open chapter selection |
| Power (brief) | Configured action (Quick Menu/Dictionary/Sleep/Page Turn) |
### In Quick Menu
| Button | Action |
|--------|--------|
| Up/Down/Left/Right | Navigate options |
| Confirm | Select option |
| Back | Close menu |
### In Word Selection
| Button | Action |
|--------|--------|
| Left/Right | Move between words |
| Up/Down | Move between lines |
| Confirm | Look up word |
| Back | Cancel |
### In Library Tabs
| Button | Action |
|--------|--------|
| Left/Right | Switch tabs (when tab bar focused) |
| Up/Down | Navigate within tab |
| Confirm | Select item / Enter tab |
| Confirm (hold) | Action menu |
| Back | Go back / Exit to home |

View File

@ -3,11 +3,40 @@
This document show most common issues and possible solutions while using the device features.
- [Troubleshooting](#troubleshooting)
- [Images Not Displaying in EPUBs](#images-not-displaying-in-epubs)
- [Cannot See the Device on the Network](#cannot-see-the-device-on-the-network)
- [Connection Drops or Times Out](#connection-drops-or-times-out)
- [Upload Fails](#upload-fails)
- [Saved Password Not Working](#saved-password-not-working)
### Images Not Displaying in EPUBs
**Problem:** Some images in EPUB books show as placeholders like "[Image: filename.jpg]" instead of the actual image
**Possible Causes:**
1. **Progressive JPEGs are not supported**
- The device uses a minimal JPEG decoder optimized for embedded systems
- Progressive/multi-scan JPEGs cannot be decoded due to memory constraints
- This affects some professionally published EPUBs, especially maps and high-quality photos
- **Workaround:** Use Calibre or another EPUB editor to convert progressive JPEGs to baseline JPEGs
2. **Unsupported image format**
- Only JPEG and PNG images are supported
- Other formats (GIF, WebP, SVG graphics) will show placeholders
3. **Image extraction failed**
- The image file may be corrupted or the EPUB structure malformed
- Try re-downloading the EPUB or converting it with Calibre
**How to check if an image is progressive JPEG:**
```python
from PIL import Image
print(Image.open("image.jpg").info.get('progressive', 0))
# Output: 1 = progressive (not supported), 0 = baseline (supported)
```
### Cannot See the Device on the Network
**Problem:** Browser shows "Cannot connect" or "Site can't be reached"

View File

@ -0,0 +1,334 @@
# CrossPointWebServer API Reference
Source: `src/network/CrossPointWebServer.cpp` and `CrossPointWebServer.h`
## Server Configuration
- HTTP port: 80 (default)
- WebSocket port: 81 (default)
- WiFi sleep disabled for responsiveness
- Supports both STA (station) and AP (access point) modes
## HTTP Endpoints
### GET /
**Handler:** `handleRoot()`
**Response:** HTML homepage from `HomePageHtml` (generated from `html/HomePage.html`)
**Content-Type:** text/html
### GET /files
**Handler:** `handleFileList()`
**Response:** HTML file browser page from `FilesPageHtml` (generated from `html/FilesPage.html`)
**Content-Type:** text/html
### GET /api/status
**Handler:** `handleStatus()`
**Response:** JSON device status
**Content-Type:** application/json
```json
{
"version": "CROSSPOINT_VERSION",
"ip": "192.168.x.x",
"mode": "AP" | "STA",
"rssi": -50, // 0 in AP mode
"freeHeap": 123456,
"uptime": 3600 // seconds
}
```
### GET /api/files
**Handler:** `handleFileListData()`
**Query params:**
- `path` (optional): Directory path, defaults to "/"
- `showHidden` (optional): "true" to show dot-files (except .crosspoint)
**Response:** JSON array of files
**Content-Type:** application/json
```json
[
{"name": "book.epub", "size": 123456, "isDirectory": false, "isEpub": true},
{"name": "folder", "size": 0, "isDirectory": true, "isEpub": false}
]
```
**Notes:**
- Hidden by default: files starting with ".", "System Volume Information", "XTCache"
- Always hidden: ".crosspoint" (internal cache folder)
- Streamed response (chunked encoding) to reduce memory usage
### GET /api/archived
**Handler:** `handleArchivedList()`
**Response:** JSON array of archived books
**Content-Type:** application/json
```json
[
{"filename": "archived_file.epub", "originalPath": "/Books/archived_file.epub"}
]
```
**Notes:** Uses `BookManager::listArchivedBooks()` and `BookManager::getArchivedBookOriginalPath()`
### GET /download
**Handler:** `handleDownload()`
**Query params:**
- `path` (required): File path to download
**Response:** File binary with Content-Disposition attachment header
**Content-Type:** application/octet-stream
**Errors:**
- 400: Missing path, path is directory
- 403: Hidden/system file, protected item
- 404: File not found
**Notes:**
- Streams in 4KB chunks
- Updates `totalBytesDownloaded` and `totalFilesDownloaded` stats
- Security: rejects paths with "..", files starting with ".", protected items
### POST /upload
**Handler:** `handleUpload()` (multipart handler), `handleUploadPost()` (response handler)
**Query params:**
- `path` (optional): Upload directory, defaults to "/"
**Form data:** multipart/form-data with file
**Response:** "File uploaded successfully: filename" or error message
**Notes:**
- Uses 4KB write buffer for SD card efficiency
- Overwrites existing files
- Clears epub cache after upload via `clearEpubCacheIfNeeded()`
- Updates `totalBytesUploaded` and `totalFilesUploaded` stats
- Logs progress every 100KB
### POST /mkdir
**Handler:** `handleCreateFolder()`
**Form params:**
- `name` (required): Folder name
- `path` (optional): Parent directory, defaults to "/"
**Response:** "Folder created: foldername" or error
**Errors:**
- 400: Missing name, empty name, folder exists
### POST /delete
**Handler:** `handleDelete()`
**Form params:**
- `path` (required): Item path to delete
- `type` (optional): "file" (default) or "folder"
- `archived` (optional): "true" for archived books
**Response:** "Deleted successfully" or error
**Errors:**
- 400: Missing path, root directory, folder not empty
- 403: Hidden/system file, protected item
- 404: Item not found
- 500: Delete failed
**Notes:**
- For files: uses `BookManager::deleteBook()` which handles cache and recent books cleanup
- For folders: must be empty first
- For archived: passes filename to `BookManager::deleteBook(filename, true)`
### POST /archive
**Handler:** `handleArchive()`
**Form params:**
- `path` (required): Book path to archive
**Response:** "Book archived successfully" or error
**Notes:** Uses `BookManager::archiveBook()`
### POST /unarchive
**Handler:** `handleUnarchive()`
**Form params:**
- `filename` (required): Archived book filename
**Response:** JSON with original path
**Content-Type:** application/json
```json
{"success": true, "originalPath": "/Books/book.epub"}
```
**Notes:** Uses `BookManager::unarchiveBook()` and `BookManager::getArchivedBookOriginalPath()`
### POST /rename
**Handler:** `handleRename()`
**Form params:**
- `path` (required): Current item path
- `newName` (required): New name (filename only, no path separators)
**Response:** "Renamed successfully" or error
**Errors:**
- 400: Missing params, empty name, name contains "/" or "\\", root directory, destination exists
- 403: System file, protected item
- 404: Source not found
- 500: Rename failed
**Notes:**
- Renames in place (same directory, new name)
- Uses `SdMan.rename()`
- Clears epub cache after rename via `clearEpubCacheIfNeeded()`
### POST /copy
**Handler:** `handleCopy()`
**Form params:**
- `srcPath` (required): Source path
- `destPath` (required): Full destination path (including new name)
**Response:** "Copied successfully" or error
**Errors:**
- 400: Missing params, root directory, destination exists, copy into self
- 403: System file, protected item
- 404: Source not found
- 500: Copy failed
**Notes:**
- Uses `copyFile()` for files (4KB buffer chunks)
- Uses `copyFolder()` for recursive directory copy
- Skips hidden files in folder copy
### POST /move
**Handler:** `handleMove()`
**Form params:**
- `srcPath` (required): Source path
- `destPath` (required): Full destination path (including new name)
**Response:** "Moved successfully" or error
**Errors:** Same as copy
**Notes:**
- First attempts atomic `SdMan.rename()` (fast)
- Falls back to copy+delete if rename fails
- Uses `deleteFolderRecursive()` for folder cleanup
### GET /list
**Handler:** `handleListGet()`
**Query params:**
- `name` (optional): Specific list name to retrieve
**Response:** JSON array of lists (if no name) or single list details (if name specified)
**Content-Type:** application/json
**Response (all lists - no name param):**
```json
[
{"name": "MyReadingList", "path": "/.lists/MyReadingList.bin", "bookCount": 5},
{"name": "Favorites", "path": "/.lists/Favorites.bin", "bookCount": 12}
]
```
**Response (specific list - with name param):**
```json
{
"name": "MyReadingList",
"path": "/.lists/MyReadingList.bin",
"books": [
{"order": 1, "title": "The Great Gatsby", "author": "F. Scott Fitzgerald", "path": "/Books/gatsby.epub"},
{"order": 2, "title": "1984", "author": "George Orwell", "path": "/Books/1984.epub"}
]
}
```
**Errors:**
- 404: List not found (when `name` specified but doesn't exist)
**Notes:**
- Lists are stored in `/.lists/` directory as `.bin` files
- Uses `BookListStore::listAllLists()` and `BookListStore::loadList()`
### POST /list
**Handler:** `handleListPost()`
**Query params:**
- `action` (required): "upload" or "delete"
- `name` (required): List name (without .bin extension)
**Request body (for upload):** CSV text with one book per line
**Content-Type:** text/plain (for upload body)
**Input format (POST body for upload action):**
```
1,The Great Gatsby,F. Scott Fitzgerald,/Books/gatsby.epub
2,1984,George Orwell,/Books/1984.epub
3,Pride and Prejudice,Jane Austen,/Books/pride.epub
```
Format: `order,title,author,path` (one per line)
**Response (upload success):**
```json
{"success": true, "path": "/.lists/MyReadingList.bin"}
```
**Response (delete success):**
```json
{"success": true}
```
**Errors:**
- 400: Missing action or name parameter, empty name, failed to parse list data
- 404: List not found (for delete action)
- 500: Failed to save/delete list
**Notes:**
- Lists are stored as binary files in `/.lists/` directory
- Uses `BookListStore::parseFromText()`, `BookListStore::saveList()`, `BookListStore::deleteList()`
- Order field determines display order (books are sorted by order when loaded)
- Overwrites existing list with same name on upload
## WebSocket Protocol (port 81)
**Handler:** `onWebSocketEvent()` via `wsEventCallback()` trampoline
### Upload Protocol
1. Client connects
2. Server: (implicit connection acknowledgment)
3. Client TEXT: `START:<filename>:<size>:<path>`
4. Server TEXT: `READY` or `ERROR:<message>`
5. Client BIN: file data chunks (any size, recommend 64KB)
6. Server TEXT: `PROGRESS:<received>:<total>` (every 64KB or at end)
7. Server TEXT: `DONE` or `ERROR:<message>`
### Events
- `WStype_CONNECTED`: Client connected, logs connection
- `WStype_DISCONNECTED`: Cleanup incomplete upload, delete partial file
- `WStype_TEXT`: Parse control messages (START)
- `WStype_BIN`: Write file data, send progress, complete upload
### Notes
- Faster than HTTP multipart for large files
- Direct binary writes to SD card
- Clears epub cache after upload
- Updates traffic statistics
## Security
### Protected Items (HIDDEN_ITEMS[])
- "System Volume Information"
- "XTCache"
### Always Hidden
- ".crosspoint" (internal cache)
### Security Checks Applied To
- `/delete`: Rejects dot-files (unless archived), protected items
- `/download`: Rejects dot-files, protected items, path traversal (..)
- `/rename`: Rejects dot-files, protected items
- `/copy`: Rejects dot-files, protected items
- `/move`: Rejects dot-files, protected items
## Helper Functions
### clearEpubCacheIfNeeded(filePath)
- Location: anonymous namespace at top of file
- Clears epub cache if file ends with ".epub"
- Uses `Epub(filePath, "/.crosspoint").clearCache()`
- Called by: upload, WebSocket upload, rename
### scanFiles(path, callback, showHidden)
- Iterates directory, calls callback for each FileInfo
- Yields and resets watchdog during iteration
- Filters hidden items based on showHidden flag
### copyFile(srcPath, destPath) / copyFolder(srcPath, destPath)
- 4KB buffer for file copy
- Recursive for folders
- Returns bool success
### deleteFolderRecursive(path)
- Static helper for move fallback
- Recursively deletes contents then directory
## Traffic Statistics (mutable, updated from const handlers)
- `totalBytesUploaded`
- `totalBytesDownloaded`
- `totalFilesUploaded`
- `totalFilesDownloaded`
- `serverStartTime` (for uptime calculation)
## Dependencies
- `<WebServer.h>` - ESP32 HTTP server
- `<WebSocketsServer.h>` - WebSocket support
- `<ArduinoJson.h>` - JSON serialization
- `<SDCardManager.h>` - SD card operations (SdMan singleton)
- `<Epub.h>` - Epub cache management
- `BookListStore.h` - Book list management (lists feature)
- `BookManager.h` - Book deletion, archiving, recent books
- `StringUtils.h` - File extension checking

195
ef-CHANGELOG.md Normal file
View File

@ -0,0 +1,195 @@
# crosspoint-ef Changelog
All notable changes to the crosspoint-ef fork are documented here.
Base: CrossPoint Reader 0.15.0
---
## ef-1.0.5
**Stability & Memory Improvements**
### Bug Fixes - Webserver
- **File Transfer Stability**: Removed blocking MD5 hash computation from file listings that caused EAGAIN errors and connection stalls
- **JSON Batching**: Implemented 2KB batch streaming for file listings with pacing to prevent TCP buffer overflow
- **Simplified Flow Control**: Removed unnecessary yield/delay logic from content streaming
### Bug Fixes - Memory
- **QR Code Caching**: Generate QR codes once on server start instead of regenerating on each screen render
- **WiFi Scan Optimization**: Replaced memory-heavy `std::map` deduplication with in-place vector search, limited results to 20 networks, earlier `WiFi.scanDelete()` for faster memory recovery
- **Cover Buffer Leak**: Fixed 48KB memory leak when navigating from Home to File Transfer (cover buffer now explicitly freed)
### Bug Fixes - EPUB Reader
- **Errant Underlining**: Fixed words before styled inline elements (like `<a>` tags with CSS underline) incorrectly receiving the element's style by flushing the text buffer before style changes
### Bug Fixes - Flashing Screen
- **Version String Overflow**: Fixed flash notification parsing failing on longer version strings (buffer limit increased from 30 to 50 characters)
- **Display Quality**: Changed flashing screen to half refresh for cleaner appearance
- **Timing**: Adjusted pre-flash script timing for half refresh completion
### Upstream Merges
- **PR #522 - HAL Abstraction Layer**: Merged hardware abstraction layer refactor introducing `HalDisplay` and `HalGPIO` classes, decoupling application code from direct hardware access
- **PR #603 - Sunlight Fading Fix**: Added user-toggleable setting to turn off display between refreshes, mitigating the sunlight fading issue on e-ink displays
- New "Sunlight Fading Fix" toggle in Display settings (OFF/ON)
- Passes `turnOffScreen` parameter through display stack when enabled
### Files Changed
- `src/main.cpp` - flash screen fixes, cover buffer free on File Transfer entry, fading fix integration
- `scripts/pre_flash.py` - timing adjustments for full refresh
- `src/network/CrossPointWebServer.cpp` - JSON batching, removed MD5 from listings
- `src/network/CrossPointWebServer.h` - removed md5 from FileInfo, simplified sendContentSafe
- `src/activities/network/CrossPointWebServerActivity.cpp` - QR code caching
- `src/activities/network/CrossPointWebServerActivity.h` - QR code cache members
- `src/activities/network/WifiSelectionActivity.cpp` - WiFi scan memory optimization
- `lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp` - flush buffer before style changes
- `lib/hal/HalDisplay.h` - new HAL abstraction for display (PR #522), turnOffScreen parameter (PR #603)
- `lib/hal/HalDisplay.cpp` - HAL display implementation with fading fix passthrough
- `lib/hal/HalGPIO.h` - new HAL abstraction for GPIO (PR #522)
- `lib/hal/HalGPIO.cpp` - HAL GPIO implementation
- `lib/GfxRenderer/GfxRenderer.h` - updated for HAL layer, added fadingFix member
- `lib/GfxRenderer/GfxRenderer.cpp` - updated for HAL layer, passes fadingFix to display
- `src/CrossPointSettings.h` - added fadingFix setting
- `src/CrossPointSettings.cpp` - fadingFix persistence
- `src/activities/settings/SettingsActivity.cpp` - added Sunlight Fading Fix toggle
- `open-x4-sdk` - updated submodule with turnOffScreen support in EInkDisplay
---
## ef-1.0.4
**EPUB Rendering & Stability**
### New Features
- **End-of-Book "Start Over"**: Press next at end of book to wrap to first page
### EPUB Rendering Improvements
- CSS `margin-left`/`padding-left` parsing for block indentation
- Vertical bar and italic styling for blockquotes
- Left margin indentation for list items (`<ol>`/`<ul>`)
- Fixed ordered lists showing bullets instead of numbers
- Fixed nested `<p>` inside `<li>` causing marker on separate line
### Bug Fixes
- **Webserver**: Fixed file listing disconnection issues with flow control
- **Webserver**: Memory optimization for File Transfer mode (frees heap before starting)
- **Dictionary**: Fixed zip dictionary allocation order for better memory allocation success
---
## ef-1.0.3
**Maintenance Release**
### Bug Fixes
- Fixed cppcheck CI failure: removed unused `screenWidth` variable in word selection activity
---
## ef-1.0.2
**Quick Menu Enhancements**
### New Features
- **Screen Rotation Toggle**: Quick toggle between Portrait and Landscape CCW directly from the quick menu
- Automatically reindexes content for new screen dimensions
- Preserves reading position via content offset restoration
- **Customizable Menu Order**: Reorder quick menu items to your preference
- New "Edit List Order" option at bottom of menu
- Pick-and-place reordering: select item, navigate to destination, place
- Order persists across sessions
### UI Improvements
- Added navigation button hints to quick menu (prev/next on front buttons, up/down on side buttons)
- Fixed orientation-aware margins for button hint areas in landscape modes
- New default menu order: Bookmark, Dictionary, Rotate Screen, Settings, Clear Cache
---
## ef-1.0.1
**Dictionary Stability & UX Improvements**
### Bug Fixes - Stability
- Fixed dictionary crashes caused by heap fragmentation from repeated page navigation
- Refactored TextBlock/ParsedText from `std::list` to `std::vector`, reducing heap allocations by ~12x per TextBlock
- Affects EPUB reader page rendering, dictionary definition display, and word selection
- Contiguous memory improves cache locality during text layout and reduces heap fragmentation on the memory-constrained ESP32
- Added uncompressed dictionary (`.dict`) support to avoid decompression memory issues with large dictzip chunks (58KB chunks -> direct read)
- Implemented chunked on-demand HTML parsing for large definitions, parsing pages as user navigates rather than all at once
- Limited cached pages to 4 with re-parse capability for backward navigation beyond cache window
- Fixed double-button press bug when loading new dictionary chunks
### Bug Fixes - UI/Layout
- Restored proper orientation-aware button hint spacing (front: 45px, side: 50px)
- Added side button hints to definition screen with "<" / ">" labels for page navigation
- Added side button hints to word selection screen ("UP"/"DOWN" labels, borderless, small font)
- Added side button hints to dictionary menu ("< Prev", "Next >")
- Moved page indicator up to avoid bezel cutoff in landscape orientations
---
## ef-1.0.0
**First Official Release** (previously ef-0.15.99)
First milestone release of the crosspoint-ef fork, building on CrossPoint Reader 0.15.0 with 14+ major new features and enhancements.
### New Features
- **Dictionary Support**: Offline StarDict dictionary with word selection from reader, fast prefix-indexed search, rich HTML formatting, and multi-page pagination
- **Bookmark System**: Per-book bookmarks with visual folded-corner indicators, dedicated management interface, and auto-generated bookmark names
- **Quick Menu**: In-reader quick access menu for common actions (Dictionary, Bookmark, Clear Cache, Settings) via short power button press
- **Library Search**: Search across all books by title, author, or filename with dynamic character picker and weighted relevance scoring
- **CSS Support**: Parse and apply CSS styles from EPUB stylesheets (text-align, font-style, font-weight, text-decoration, margins, padding)
- **Inline Image Support**: PNG and Baseline JPEG rendering within EPUB content with 2-bit grayscale dithering and caching
- **Custom Fonts**: Atkinson Hyperlegible Next (low-vision readers) and Fern Micro (small screens)
- **Enhanced Web Server**: File management (upload, download, delete, rename, copy, move, mkdir), companion app API, WebSocket uploads, mDNS discovery at `crosspoint.local`
- **Reading Lists**: Create, manage, and pin custom book lists with web API support (CSV format)
- **Enhanced Tab Bar**: Unified tab bar with horizontal scrolling and overflow indicators (Recent, Lists, Bookmarks, Search, Files)
- **Progress Bar Status**: Additional status bar option showing visual reading progress
- **OPDS Browser Enhancements**: Navigation history, page skipping (hold Up/Down), error retry, HTTP Basic Auth support
### Display Enhancements
- **High Contrast Mode**: System-wide contrast adjustment
- **Bezel Compensation**: Configurable margin (0-10px) for physical screen edge defects
- **Sleep Screen Improvements**: Edge-aware color filling for seamless letterbox appearance
### Bug Fixes
- Fixed device hanging when booted without USB connected (Serial.available()/Serial.read() called without Serial.begin())
- Fixed grayscale state corruption causing ghosting artifacts when anti-aliasing enabled under memory pressure
- Memory optimization with graceful degradation when memory is low
### Development Tools
- `pre_flash.py`: Displays "Flashing firmware..." screen during upload
- `debugging_monitor.py`: Enhanced serial monitor with memory graphs
- `pio_helper.py`: Interactive PlatformIO workflow helper
---
## Differences from Upstream 0.16.0
This fork is based on upstream 0.15.0. The following 0.16.0 features are not included:
- KOReader sync support
- Non-English hyphenation patterns (Spanish, German, French, Russian)
- XTC/XTCH file format support
See [crosspoint-ef-features.md](docs/crosspoint-ef-features.md) for complete feature documentation.

View File

@ -33,23 +33,10 @@
#include <builtinFonts/notosans_18_bolditalic.h>
#include <builtinFonts/notosans_18_italic.h>
#include <builtinFonts/notosans_18_regular.h>
#include <builtinFonts/opendyslexic_10_bold.h>
#include <builtinFonts/opendyslexic_10_bolditalic.h>
#include <builtinFonts/opendyslexic_10_italic.h>
#include <builtinFonts/opendyslexic_10_regular.h>
#include <builtinFonts/opendyslexic_12_bold.h>
#include <builtinFonts/opendyslexic_12_bolditalic.h>
#include <builtinFonts/opendyslexic_12_italic.h>
#include <builtinFonts/opendyslexic_12_regular.h>
#include <builtinFonts/opendyslexic_14_bold.h>
#include <builtinFonts/opendyslexic_14_bolditalic.h>
#include <builtinFonts/opendyslexic_14_italic.h>
#include <builtinFonts/opendyslexic_14_regular.h>
#include <builtinFonts/opendyslexic_8_bold.h>
#include <builtinFonts/opendyslexic_8_bolditalic.h>
#include <builtinFonts/opendyslexic_8_italic.h>
#include <builtinFonts/opendyslexic_8_regular.h>
#include <builtinFonts/ubuntu_10_bold.h>
#include <builtinFonts/ubuntu_10_regular.h>
#include <builtinFonts/ubuntu_12_bold.h>
#include <builtinFonts/ubuntu_12_regular.h>
// Custom fonts registry (generated by convert-builtin-fonts.sh)
#include <builtinFonts/custom/customFonts.h>

View File

@ -3,6 +3,7 @@
* name: bookerly_12_bold
* size: 12
* mode: 2-bit
* Command used: fontconvert.py bookerly_12_bold 12 ../builtinFonts/source/Bookerly/Bookerly-Bold.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: bookerly_12_bolditalic
* size: 12
* mode: 2-bit
* Command used: fontconvert.py bookerly_12_bolditalic 12 ../builtinFonts/source/Bookerly/Bookerly-BoldItalic.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: bookerly_12_italic
* size: 12
* mode: 2-bit
* Command used: fontconvert.py bookerly_12_italic 12 ../builtinFonts/source/Bookerly/Bookerly-Italic.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: bookerly_12_regular
* size: 12
* mode: 2-bit
* Command used: fontconvert.py bookerly_12_regular 12 ../builtinFonts/source/Bookerly/Bookerly-Regular.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: bookerly_14_bold
* size: 14
* mode: 2-bit
* Command used: fontconvert.py bookerly_14_bold 14 ../builtinFonts/source/Bookerly/Bookerly-Bold.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: bookerly_14_bolditalic
* size: 14
* mode: 2-bit
* Command used: fontconvert.py bookerly_14_bolditalic 14 ../builtinFonts/source/Bookerly/Bookerly-BoldItalic.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: bookerly_14_italic
* size: 14
* mode: 2-bit
* Command used: fontconvert.py bookerly_14_italic 14 ../builtinFonts/source/Bookerly/Bookerly-Italic.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: bookerly_14_regular
* size: 14
* mode: 2-bit
* Command used: fontconvert.py bookerly_14_regular 14 ../builtinFonts/source/Bookerly/Bookerly-Regular.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: bookerly_16_bold
* size: 16
* mode: 2-bit
* Command used: fontconvert.py bookerly_16_bold 16 ../builtinFonts/source/Bookerly/Bookerly-Bold.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: bookerly_16_bolditalic
* size: 16
* mode: 2-bit
* Command used: fontconvert.py bookerly_16_bolditalic 16 ../builtinFonts/source/Bookerly/Bookerly-BoldItalic.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: bookerly_16_italic
* size: 16
* mode: 2-bit
* Command used: fontconvert.py bookerly_16_italic 16 ../builtinFonts/source/Bookerly/Bookerly-Italic.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: bookerly_16_regular
* size: 16
* mode: 2-bit
* Command used: fontconvert.py bookerly_16_regular 16 ../builtinFonts/source/Bookerly/Bookerly-Regular.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: bookerly_18_bold
* size: 18
* mode: 2-bit
* Command used: fontconvert.py bookerly_18_bold 18 ../builtinFonts/source/Bookerly/Bookerly-Bold.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: bookerly_18_bolditalic
* size: 18
* mode: 2-bit
* Command used: fontconvert.py bookerly_18_bolditalic 18 ../builtinFonts/source/Bookerly/Bookerly-BoldItalic.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: bookerly_18_italic
* size: 18
* mode: 2-bit
* Command used: fontconvert.py bookerly_18_italic 18 ../builtinFonts/source/Bookerly/Bookerly-Italic.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: bookerly_18_regular
* size: 18
* mode: 2-bit
* Command used: fontconvert.py bookerly_18_regular 18 ../builtinFonts/source/Bookerly/Bookerly-Regular.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,99 @@
/**
* Generated by convert-builtin-fonts.sh
* Registry of available custom fonts
*/
#pragma once
#include <EpdFont.h>
#include <EpdFontFamily.h>
class GfxRenderer;
#define CUSTOM_FONT_COUNT 2
static const char* CUSTOM_FONT_NAMES[] = {
"AtkinsonHyperlegibleNext",
"FernMicro"
};
// Include all custom font headers
#include <builtinFonts/custom/atkinsonhyperlegiblenext_12_regular.h>
#include <builtinFonts/custom/atkinsonhyperlegiblenext_12_italic.h>
#include <builtinFonts/custom/atkinsonhyperlegiblenext_12_bold.h>
#include <builtinFonts/custom/atkinsonhyperlegiblenext_12_bolditalic.h>
#include <builtinFonts/custom/atkinsonhyperlegiblenext_14_regular.h>
#include <builtinFonts/custom/atkinsonhyperlegiblenext_14_italic.h>
#include <builtinFonts/custom/atkinsonhyperlegiblenext_14_bold.h>
#include <builtinFonts/custom/atkinsonhyperlegiblenext_14_bolditalic.h>
#include <builtinFonts/custom/atkinsonhyperlegiblenext_16_regular.h>
#include <builtinFonts/custom/atkinsonhyperlegiblenext_16_italic.h>
#include <builtinFonts/custom/atkinsonhyperlegiblenext_16_bold.h>
#include <builtinFonts/custom/atkinsonhyperlegiblenext_16_bolditalic.h>
#include <builtinFonts/custom/atkinsonhyperlegiblenext_18_regular.h>
#include <builtinFonts/custom/atkinsonhyperlegiblenext_18_italic.h>
#include <builtinFonts/custom/atkinsonhyperlegiblenext_18_bold.h>
#include <builtinFonts/custom/atkinsonhyperlegiblenext_18_bolditalic.h>
#include <builtinFonts/custom/fernmicro_12_regular.h>
#include <builtinFonts/custom/fernmicro_12_italic.h>
#include <builtinFonts/custom/fernmicro_12_bold.h>
#include <builtinFonts/custom/fernmicro_12_bolditalic.h>
#include <builtinFonts/custom/fernmicro_14_regular.h>
#include <builtinFonts/custom/fernmicro_14_italic.h>
#include <builtinFonts/custom/fernmicro_14_bold.h>
#include <builtinFonts/custom/fernmicro_14_bolditalic.h>
#include <builtinFonts/custom/fernmicro_16_regular.h>
#include <builtinFonts/custom/fernmicro_16_italic.h>
#include <builtinFonts/custom/fernmicro_16_bold.h>
#include <builtinFonts/custom/fernmicro_16_bolditalic.h>
#include <builtinFonts/custom/fernmicro_18_regular.h>
#include <builtinFonts/custom/fernmicro_18_italic.h>
#include <builtinFonts/custom/fernmicro_18_bold.h>
#include <builtinFonts/custom/fernmicro_18_bolditalic.h>
// Extern EpdFont declarations for custom fonts
extern EpdFont atkinsonhyperlegiblenext12RegularFont;
extern EpdFont atkinsonhyperlegiblenext12ItalicFont;
extern EpdFont atkinsonhyperlegiblenext12BoldFont;
extern EpdFont atkinsonhyperlegiblenext12BoldItalicFont;
extern EpdFont atkinsonhyperlegiblenext14RegularFont;
extern EpdFont atkinsonhyperlegiblenext14ItalicFont;
extern EpdFont atkinsonhyperlegiblenext14BoldFont;
extern EpdFont atkinsonhyperlegiblenext14BoldItalicFont;
extern EpdFont atkinsonhyperlegiblenext16RegularFont;
extern EpdFont atkinsonhyperlegiblenext16ItalicFont;
extern EpdFont atkinsonhyperlegiblenext16BoldFont;
extern EpdFont atkinsonhyperlegiblenext16BoldItalicFont;
extern EpdFont atkinsonhyperlegiblenext18RegularFont;
extern EpdFont atkinsonhyperlegiblenext18ItalicFont;
extern EpdFont atkinsonhyperlegiblenext18BoldFont;
extern EpdFont atkinsonhyperlegiblenext18BoldItalicFont;
extern EpdFont fernmicro12RegularFont;
extern EpdFont fernmicro12ItalicFont;
extern EpdFont fernmicro12BoldFont;
extern EpdFont fernmicro12BoldItalicFont;
extern EpdFont fernmicro14RegularFont;
extern EpdFont fernmicro14ItalicFont;
extern EpdFont fernmicro14BoldFont;
extern EpdFont fernmicro14BoldItalicFont;
extern EpdFont fernmicro16RegularFont;
extern EpdFont fernmicro16ItalicFont;
extern EpdFont fernmicro16BoldFont;
extern EpdFont fernmicro16BoldItalicFont;
extern EpdFont fernmicro18RegularFont;
extern EpdFont fernmicro18ItalicFont;
extern EpdFont fernmicro18BoldFont;
extern EpdFont fernmicro18BoldItalicFont;
// Extern EpdFontFamily declarations for custom fonts
extern EpdFontFamily atkinsonhyperlegiblenext12FontFamily;
extern EpdFontFamily atkinsonhyperlegiblenext14FontFamily;
extern EpdFontFamily atkinsonhyperlegiblenext16FontFamily;
extern EpdFontFamily atkinsonhyperlegiblenext18FontFamily;
extern EpdFontFamily fernmicro12FontFamily;
extern EpdFontFamily fernmicro14FontFamily;
extern EpdFontFamily fernmicro16FontFamily;
extern EpdFontFamily fernmicro18FontFamily;
// Function to register all custom fonts with the renderer
void registerCustomFonts(GfxRenderer& renderer);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@
* name: notosans_12_bold
* size: 12
* mode: 2-bit
* Command used: fontconvert.py notosans_12_bold 12 ../builtinFonts/source/NotoSans/NotoSans-Bold.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: notosans_12_bolditalic
* size: 12
* mode: 2-bit
* Command used: fontconvert.py notosans_12_bolditalic 12 ../builtinFonts/source/NotoSans/NotoSans-BoldItalic.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: notosans_12_italic
* size: 12
* mode: 2-bit
* Command used: fontconvert.py notosans_12_italic 12 ../builtinFonts/source/NotoSans/NotoSans-Italic.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: notosans_12_regular
* size: 12
* mode: 2-bit
* Command used: fontconvert.py notosans_12_regular 12 ../builtinFonts/source/NotoSans/NotoSans-Regular.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: notosans_14_bold
* size: 14
* mode: 2-bit
* Command used: fontconvert.py notosans_14_bold 14 ../builtinFonts/source/NotoSans/NotoSans-Bold.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: notosans_14_bolditalic
* size: 14
* mode: 2-bit
* Command used: fontconvert.py notosans_14_bolditalic 14 ../builtinFonts/source/NotoSans/NotoSans-BoldItalic.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: notosans_14_italic
* size: 14
* mode: 2-bit
* Command used: fontconvert.py notosans_14_italic 14 ../builtinFonts/source/NotoSans/NotoSans-Italic.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: notosans_14_regular
* size: 14
* mode: 2-bit
* Command used: fontconvert.py notosans_14_regular 14 ../builtinFonts/source/NotoSans/NotoSans-Regular.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: notosans_16_bold
* size: 16
* mode: 2-bit
* Command used: fontconvert.py notosans_16_bold 16 ../builtinFonts/source/NotoSans/NotoSans-Bold.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: notosans_16_bolditalic
* size: 16
* mode: 2-bit
* Command used: fontconvert.py notosans_16_bolditalic 16 ../builtinFonts/source/NotoSans/NotoSans-BoldItalic.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: notosans_16_italic
* size: 16
* mode: 2-bit
* Command used: fontconvert.py notosans_16_italic 16 ../builtinFonts/source/NotoSans/NotoSans-Italic.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: notosans_16_regular
* size: 16
* mode: 2-bit
* Command used: fontconvert.py notosans_16_regular 16 ../builtinFonts/source/NotoSans/NotoSans-Regular.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: notosans_18_bold
* size: 18
* mode: 2-bit
* Command used: fontconvert.py notosans_18_bold 18 ../builtinFonts/source/NotoSans/NotoSans-Bold.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: notosans_18_bolditalic
* size: 18
* mode: 2-bit
* Command used: fontconvert.py notosans_18_bolditalic 18 ../builtinFonts/source/NotoSans/NotoSans-BoldItalic.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: notosans_18_italic
* size: 18
* mode: 2-bit
* Command used: fontconvert.py notosans_18_italic 18 ../builtinFonts/source/NotoSans/NotoSans-Italic.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: notosans_18_regular
* size: 18
* mode: 2-bit
* Command used: fontconvert.py notosans_18_regular 18 ../builtinFonts/source/NotoSans/NotoSans-Regular.ttf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: notosans_8_regular
* size: 8
* mode: 1-bit
* Command used: fontconvert.py notosans_8_regular 8 ../builtinFonts/source/NotoSans/NotoSans-Regular.ttf
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: opendyslexic_10_bold
* size: 10
* mode: 2-bit
* Command used: fontconvert.py opendyslexic_10_bold 10 ../builtinFonts/source/OpenDyslexic/OpenDyslexic-Bold.otf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: opendyslexic_10_bolditalic
* size: 10
* mode: 2-bit
* Command used: fontconvert.py opendyslexic_10_bolditalic 10 ../builtinFonts/source/OpenDyslexic/OpenDyslexic-BoldItalic.otf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: opendyslexic_10_italic
* size: 10
* mode: 2-bit
* Command used: fontconvert.py opendyslexic_10_italic 10 ../builtinFonts/source/OpenDyslexic/OpenDyslexic-Italic.otf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: opendyslexic_10_regular
* size: 10
* mode: 2-bit
* Command used: fontconvert.py opendyslexic_10_regular 10 ../builtinFonts/source/OpenDyslexic/OpenDyslexic-Regular.otf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: opendyslexic_12_bold
* size: 12
* mode: 2-bit
* Command used: fontconvert.py opendyslexic_12_bold 12 ../builtinFonts/source/OpenDyslexic/OpenDyslexic-Bold.otf --2bit
*/
#pragma once
#include "EpdFontData.h"

View File

@ -3,6 +3,7 @@
* name: opendyslexic_12_bolditalic
* size: 12
* mode: 2-bit
* Command used: fontconvert.py opendyslexic_12_bolditalic 12 ../builtinFonts/source/OpenDyslexic/OpenDyslexic-BoldItalic.otf --2bit
*/
#pragma once
#include "EpdFontData.h"

Some files were not shown because too many files have changed in this diff Show More