Compare commits

..

3 Commits

Author SHA1 Message Date
Dave Allie
551e57295f
Alloc/free inflator once per drawText call 2026-01-05 23:13:17 +11:00
Dave Allie
c9cfedf3d6
Do not include ZLIB header or checksum bytes in compressed glyphs 2026-01-05 22:58:42 +11:00
Dave Allie
cb3e08e73c
Basic glyph compression 2026-01-05 22:54:09 +11:00
313 changed files with 204057 additions and 392216 deletions

View File

@ -1,41 +0,0 @@
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

@ -1,40 +0,0 @@
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

@ -1,40 +0,0 @@
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

View File

@ -1,18 +1,9 @@
## Summary ## Summary
* **What is the goal of this PR?** (e.g., Implements the new feature for file uploading.) * **What is the goal of this PR?** (e.g., Fixes a bug in the user authentication module, Implements the new feature for
file uploading.)
* **What changes are included?** * **What changes are included?**
## Additional Context ## Additional Context
* Add any other information that might be helpful for the reviewer (e.g., performance implications, potential risks, * Add any other information that might be helpful for the reviewer (e.g., performance implications, potential risks, specific areas to focus on).
specific areas to focus on).
---
### AI Usage
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? _**< YES | PARTIALLY | NO >**_

View File

@ -7,11 +7,11 @@ name: CI
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v6
with: with:
submodules: recursive submodules: recursive
- uses: actions/setup-python@v6 - uses: actions/setup-python@v6
with: with:
python-version: '3.14' python-version: '3.14'

View File

@ -1,26 +0,0 @@
name: "PR Formatting"
on:
pull_request_target:
types:
- opened
- reopened
- edited
permissions:
statuses: write
jobs:
title-check:
name: Title Check
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
with:
egress-policy: audit
- name: Check PR Title
uses: amannn/action-semantic-pull-request@v6
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -7,18 +7,17 @@ on:
jobs: jobs:
build-release: build-release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v6
with: with:
submodules: recursive submodules: recursive
- uses: actions/cache@v5 - uses: actions/cache@v5
with: with:
path: | path: |
~/.cache/pip ~/.cache/pip
~/.platformio/.cache ~/.platformio/.cache
key: ${{ runner.os }}-pio key: ${{ runner.os }}-pio
- uses: actions/setup-python@v6 - uses: actions/setup-python@v6
with: with:
python-version: '3.14' python-version: '3.14'

15
.gitignore vendored
View File

@ -2,20 +2,5 @@
.idea .idea
.DS_Store .DS_Store
.vscode .vscode
.cursor/
chat-summaries/
lib/EpdFont/fontsrc lib/EpdFont/fontsrc
*.generated.h *.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,5 +1,3 @@
[submodule "open-x4-sdk"] [submodule "open-x4-sdk"]
path = open-x4-sdk path = open-x4-sdk
url = https://code.cottongin.xyz/cottongin/community-sdk.git url = https://github.com/open-x4-epaper/community-sdk.git
branch = crosspoint-ef
ignore = dirty

View File

@ -1,15 +1,4 @@
# CrossPoint Reader (ef fork) # CrossPoint Reader
> **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). Firmware for the **Xteink X4** e-paper display reader (unaffiliated with Xteink).
Built using **PlatformIO** and targeting the **ESP32-C3** microcontroller. Built using **PlatformIO** and targeting the **ESP32-C3** microcontroller.
@ -52,8 +41,6 @@ This project is **not affiliated with Xteink**; it's built as a community projec
- [ ] Full UTF support - [ ] Full UTF support
- [x] Screen rotation - [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. See [the user guide](./USER_GUIDE.md) for instructions on operating CrossPoint.
## Installing ## Installing

View File

@ -1,37 +1,17 @@
# CrossPoint User Guide # CrossPoint User Guide
Welcome to the **CrossPoint** firmware. This guide outlines the hardware controls, navigation, and reading features of the device. Welcome to the **CrossPoint** firmware. This guide outlines the hardware controls, navigation, and reading features of
the device.
- [CrossPoint User Guide](#crosspoint-user-guide)
- [1. Hardware Overview](#1-hardware-overview)
- [Button Layout](#button-layout)
- [2. Power \& Startup](#2-power--startup)
- [Power On / Off](#power-on--off)
- [First Launch](#first-launch)
- [3. Screens](#3-screens)
- [3.1 Home Screen](#31-home-screen)
- [3.2 Book Selection](#32-book-selection)
- [3.3 Reading Mode](#33-reading-mode)
- [3.4 File Upload Screen](#34-file-upload-screen)
- [3.5 Settings](#35-settings)
- [3.6 Sleep Screen](#36-sleep-screen)
- [4. Reading Mode](#4-reading-mode)
- [Page Turning](#page-turning)
- [Chapter Navigation](#chapter-navigation)
- [System Navigation](#system-navigation)
- [5. Chapter Selection Screen](#5-chapter-selection-screen)
- [6. Current Limitations \& Roadmap](#6-current-limitations--roadmap)
## 1. Hardware Overview ## 1. Hardware Overview
The device utilises the standard buttons on the Xtink X4 (in the same layout as the manufacturer firmware, by default): The device utilises the standard buttons on the Xtink X4 (in the same layout as the manufacturer firmware, by default):
### Button Layout ### Button Layout
| Location | Buttons | | Location | Buttons |
| --------------- | ---------------------------------------------------- | |-----------------|--------------------------------------------|
| **Bottom Edge** | **Back**, **Confirm**, **Left**, **Right** | | **Bottom Edge** | **Back**, **Confirm**, **Left**, **Right** |
| **Right Side** | **Power**, **Volume Up**, **Volume Down**, **Reset** | | **Right Side** | **Power**, **Volume Up**, **Volume Down** |
Button layout can be customized in **[Settings](#35-settings)**. Button layout can be customized in **[Settings](#35-settings)**.
@ -41,10 +21,8 @@ Button layout can be customized in **[Settings](#35-settings)**.
### Power On / Off ### Power On / Off
To turn the device on or off, **press and hold the Power button for approximately half a second**. To turn the device on or off, **press and hold the Power button for half a second**. In **[Settings](#35-settings)** you can configure
In **[Settings](#35-settings)** you can configure the power button to turn the device off with a short press instead of a long one. the power button to trigger on a short press instead of a long one.
To reboot the device (for example if it's frozen, or after a firmware update), press and release the Reset button, and then quickly press and hold the Power button for a few seconds.
### First Launch ### First Launch
@ -59,13 +37,15 @@ Upon turning the device on for the first time, you will be placed on the **[Home
### 3.1 Home Screen ### 3.1 Home Screen
The Home Screen is the main entry point to the firmware. From here you can navigate to **[Reading Mode](#4-reading-mode)** with the most recently read book, **[Book Selection](#32-book-selection)**, **[Settings](#35-settings)**, or the **[File Upload](#34-file-upload-screen)** screen. The Home Screen is the main entry point to the firmware. From here you can navigate to **[Reading Mode](#4-reading-mode)** with the most recently read book, **[Book Selection](#32-book-selection)**,
**[Settings](#35-settings)**, or the **[File Upload](#34-file-upload-screen)** screen.
### 3.2 Book Selection ### 3.2 Book Selection
The Book Selection acts as a folder and file browser. The Book Selection acts as a folder and file browser.
* **Navigate List:** Use **Left** (or **Volume Up**), or **Right** (or **Volume Down**) to move the selection cursor up and down through folders and books. You can also long-press these buttons to scroll a full page up or down. * **Navigate List:** Use **Left** (or **Volume Up**), or **Right** (or **Volume Down**) to move the selection cursor up
and down through folders and books.
* **Open Selection:** Press **Confirm** to open a folder or read a selected book. * **Open Selection:** Press **Confirm** to open a folder or read a selected book.
### 3.3 Reading Mode ### 3.3 Reading Mode
@ -74,81 +54,42 @@ See [Reading Mode](#4-reading-mode) below for more information.
### 3.4 File Upload Screen ### 3.4 File Upload Screen
The File Upload screen allows you to upload new e-books to the device. When you enter the screen, you'll be prompted with a WiFi selection dialog and then your X4 will start hosting a web server. The File Upload screen allows you to upload new e-books to the device. When you enter the screen, you'll be prompted with
a WiFi selection dialog and then your X4 will start hosting a web server.
See the [webserver docs](./docs/webserver.md) for more information on how to connect to the web server and upload files. See the [webserver docs](./docs/webserver.md) for more information on how to connect to the web server and upload files.
> [!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 ### 3.5 Settings
The Settings screen allows you to configure the device's behavior. There are a few settings you can adjust: The Settings screen allows you to configure the device's behavior. There are a few settings you can adjust:
- **Sleep Screen**: Which sleep screen to display when the device sleeps: - **Sleep Screen**: Which sleep screen to display when the device sleeps, options are:
- "Dark" (default) - The default dark Crosspoint logo sleep screen - "Dark" (default) - The default dark sleep screen
- "Light" - The same default sleep screen, on a white background - "Light" - The same default sleep screen, on a white background
- "Custom" - Custom images from the SD card; see [Sleep Screen](#36-sleep-screen) below for more information - "Custom" - Custom images from the SD card, see [Sleep Screen](#36-sleep-screen) below for more information
- "Cover" - The book cover image (Note: this is experimental and may not work as expected) - "Cover" - The book cover image (Note: this is experimental and may not work as expected)
- "None" - A blank screen - **Status Bar**: Configure the status bar displayed while reading, options are:
- **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 - "None" - No status bar
- "No Progress" - Show status bar without reading progress - "No Progress" - Show status bar without reading progress
- "Full" - Show status bar with reading progress - "Full" - Show status bar with reading progress
- **Hide Battery %**: Configure where to suppress the battery pecentage display in the status bar; the battery icon will still be shown: - **Extra Paragraph Spacing**: If enabled, vertical space will be added between paragraphs in the book, if disabled,
- "Never" - Always show battery percentage (default) paragraphs will not have vertical space between them, but will have first word indentation.
- "In Reader" - Show battery percentage everywhere except in reading mode - **Short Power Button Click**: Whether to trigger the power button on a short press or a long press.
- "Always" - Always hide battery percentage - **Reading Orientation**: Set the screen orientation for reading, options are:
- **Extra Paragraph Spacing**: If enabled, vertical space will be added between paragraphs in the book. If disabled, paragraphs will not have vertical space between them, but will have first-line indentation.
- **Text Anti-Aliasing**: Whether to show smooth grey edges (anti-aliasing) on text in reading mode. Note this slows down page turns slightly.
- **Short Power Button Click**: Controls the effect of a short click of the power button:
- "Ignore" - Require a long press to turn off the device
- "Sleep" - A short press powers the device off
- "Page Turn" - A short press in reading mode turns to the next page; a long press turns the device off
- **Reading Orientation**: Set the screen orientation for reading EPUB files:
- "Portrait" (default) - Standard portrait orientation - "Portrait" (default) - Standard portrait orientation
- "Landscape CW" - Landscape, rotated clockwise - "Landscape CW" - Landscape, rotated clockwise
- "Inverted" - Portrait, upside down - "Inverted" - Portrait, upside down
- "Landscape CCW" - Landscape, rotated counter-clockwise - "Landscape CCW" - Landscape, rotated counter-clockwise
- **Front Button Layout**: Configure the order of the bottom edge buttons: - **Front Button Layout**: Configure the order of the bottom edge buttons, options are:
- Back, Confirm, Left, Right (default) - "Bck, Cnfrm, Lft, Rght" (default) - Back, Confirm, Left, Right
- Left, Right, Back, Confirm - "Lft, Rght, Bck, Cnfrm" - Left, Right, Back, Confirm
- Left, Back, Confirm, Right - "Lft, Bck, Cnfrm, Rght" - Left, Back, Confirm, Right
- Back, Confirm, Right, Left - **Side Button Layout**: Swap the order of the volume buttons from Previous/Next to Next/Previous. This change is only in effect when reading.
- **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. - **Reader Font Family**: Choose the font used for reading, options are:
- **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
- "Page Scroll" - Long-pressing scrolls a page up/down
- Swap the order of the up and down volume buttons from Previous/Next to Next/Previous. This change is only in effect when reading.
- **Reader Font Family**: Choose the font used for reading:
- "Bookerly" (default) - Amazon's reading font - "Bookerly" (default) - Amazon's reading font
- "Noto Sans" - Google's sans-serif font - "Noto Sans" - Google's sans-serif font
- "Open Dyslexic" - Font designed for readers with dyslexia - "Open Dyslexic" - Font designed for readers with dyslexia
- **Reader Font Size**: Adjust the text size for reading; options are "Small", "Medium", "Large", or "X Large". - **Reader Font Size**: Adjust the text size for reading, options are "Small", "Medium", "Large", or "X Large".
- **Reader Line Spacing**: Adjust the spacing between lines; options are "Tight", "Normal", or "Wide". - **Reader Line Spacing**: Adjust the spacing between lines, options are "Tight", "Normal", or "Wide".
- **Reader Screen Margin**: Controls the screen margins in reader mode between 5 and 40 pixels in 5 pixel increments.
- **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.
- **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. - **Check for updates**: Check for firmware updates over WiFi.
### 3.6 Sleep Screen ### 3.6 Sleep Screen
@ -156,7 +97,9 @@ The Settings screen allows you to configure the device's behavior. There are a f
You can customize the sleep screen by placing custom images in specific locations on the SD card: You can customize the sleep screen by placing custom images in specific locations on the SD card:
- **Single Image:** Place a file named `sleep.bmp` in the root directory. - **Single Image:** Place a file named `sleep.bmp` in the root directory.
- **Multiple Images:** Create a `sleep` directory in the root of the SD card and place any number of `.bmp` images inside. If images are found in this directory, they will take priority over the `sleep.bmp` file, and one will be randomly selected each time the device sleeps. - **Multiple Images:** Create a `sleep` directory in the root of the SD card and place any number of `.bmp` images
inside. If images are found in this directory, they will take priority over the `sleep.bmp` file, and one will be
randomly selected each time the device sleeps.
> [!NOTE] > [!NOTE]
> You'll need to set the **Sleep Screen** setting to **Custom** in order to use these images. > You'll need to set the **Sleep Screen** setting to **Custom** in order to use these images.
@ -174,35 +117,19 @@ Once you have opened a book, the button layout changes to facilitate reading.
### Page Turning ### Page Turning
| Action | Buttons | | Action | Buttons |
| ----------------- | ------------------------------------ | |-------------------|--------------------------------------|
| **Previous Page** | Press **Left** _or_ **Volume Up** | | **Previous Page** | Press **Left** _or_ **Volume Up** |
| **Next Page** | Press **Right** _or_ **Volume Down** | | **Next Page** | Press **Right** _or_ **Volume Down** |
The role of the volume (side) buttons can be swapped in **[Settings](#35-settings)**.
If the **Short Power Button Click** setting is set to "Page Turn", you can also turn to the next page by briefly pressing the Power button.
### Chapter Navigation ### Chapter Navigation
* **Next Chapter:** Press and **hold** the **Right** (or **Volume Down**) button briefly, then release. * **Next Chapter:** Press and **hold** the **Right** (or **Volume Down**) button briefly, then release.
* **Previous Chapter:** Press and **hold** the **Left** (or **Volume Up**) button briefly, then release. * **Previous Chapter:** Press and **hold** the **Left** (or **Volume Up**) button briefly, then release.
This feature can be disabled in **[Settings](#35-settings)** to help avoid changing chapters by mistake.
### System Navigation ### System Navigation
* **Return to Book Selection:** Press **Back** to close the book and return to the **[Book Selection](#32-book-selection)** screen. * **Return to Book Selection:** Press **Back** to close the book and return to the **[Book Selection](#32-book-selection)** screen.
* **Return to Home:** Press and **hold** the **Back** button to close the book and return to the **[Home](#31-home-screen)** screen. * **Return to Home:** Press and hold **Back** 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)**. * **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 ## 5. Chapter Selection Screen
@ -217,6 +144,7 @@ Accessible by pressing **Confirm** while inside a book.
## 6. Current Limitations & Roadmap ## 6. Current Limitations & Roadmap
Please note that this firmware is currently in active development. The following features are **not yet supported** but are planned for future updates: Please note that this firmware is currently in active development. The following features are **not yet supported** but
are planned for future updates:
* **Images:** Embedded images in e-books will not render. * **Images:** Embedded images in e-books will not render.

View File

@ -1,137 +0,0 @@
# 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

@ -1,70 +0,0 @@
# 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

@ -1,125 +0,0 @@
# 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

@ -1,132 +0,0 @@
# 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.

Binary file not shown.

View File

@ -1,422 +0,0 @@
# 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

@ -1,309 +0,0 @@
# 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

@ -1,603 +0,0 @@
# 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

@ -1,555 +0,0 @@
# 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

@ -1,66 +0,0 @@
# Hypher Binary Tries
CrossPoint embeds the exact binary automata produced by
[Typst's `hypher`](https://github.com/typst/hypher).
## File layout
Each `.bin` blob is a single self-contained automaton:
```
uint32_t root_addr_be; // big-endian offset of the root node
uint8_t levels[]; // shared "levels" tape (dist/score pairs)
uint8_t nodes[]; // node records packed back-to-back
```
The size of the `levels` tape is implicit. Individual nodes reference slices
inside that tape via 12-bit offsets, so no additional pointers are required.
### Node encoding
Every node starts with a single control byte:
- Bit 7 set when the node stores scores (`levels`).
- Bits 5-6 stride of the target deltas (1, 2, or 3 bytes, big-endian).
- Bits 0-4 transition count (values ≥ 31 spill into an extra byte).
If the `levels` flag is set, two more bytes follow. Together they encode a
12-bit offset into the global `levels` tape and a 4-bit length. Each byte in the
levels tape packs a distance/score pair as `dist * 10 + score`, where `dist`
counts how many UTF-8 bytes we advanced since the previous digit.
After the optional levels header come the transition labels (one byte per edge)
followed by the signed target deltas. Targets are stored as relative offsets
from the current node address. Deltas up to ±128 fit in a single byte, larger
distances grow to 2 or 3 bytes. The runtime walks the transitions with a simple
linear scan and materializes the absolute address by adding the decoded delta
to the current nodes base.
## Embedding blobs into the firmware
The helper script `scripts/generate_hyphenation_trie.py` acts as a thin
wrapper: it reads the hypher-generated `.bin` files, formats them as `constexpr`
byte arrays, and emits headers under
`lib/Epub/Epub/hyphenation/generated/`. Each header defines the raw data plus a
`SerializedHyphenationPatterns` descriptor so the reader can keep the automaton
in flash.
To refresh the firmware assets after updating the `.bin` files, run:
```
./scripts/generate_hyphenation_trie.py \
--input lib/Epub/Epub/hyphenation/tries/en.bin \
--output lib/Epub/Epub/hyphenation/generated/hyph-en.trie.h
./scripts/generate_hyphenation_trie.py \
--input lib/Epub/Epub/hyphenation/tries/fr.bin \
--output lib/Epub/Epub/hyphenation/generated/hyph-fr.trie.h
./scripts/generate_hyphenation_trie.py \
--input lib/Epub/Epub/hyphenation/tries/de.bin \
--output lib/Epub/Epub/hyphenation/generated/hyph-de.trie.h
./scripts/generate_hyphenation_trie.py \
--input lib/Epub/Epub/hyphenation/tries/ru.bin \
--output lib/Epub/Epub/hyphenation/generated/hyph-ru.trie.h
```

View File

@ -1,86 +0,0 @@
# Troubleshooting
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"
**Solutions:**
1. Verify both devices are on the **same WiFi network**
- Check your computer/phone WiFi settings
- Confirm the CrossPoint Reader shows "Connected" status
2. Double-check the IP address
- Make sure you typed it correctly
- Include `http://` at the beginning
3. Try disabling VPN if you're using one
4. Some networks have "client isolation" enabled - check with your network administrator
### Connection Drops or Times Out
**Problem:** WiFi connection is unstable
**Solutions:**
1. Move closer to the WiFi router
2. Check signal strength on the device (should be at least `||` or better)
3. Avoid interference from other devices
4. Try a different WiFi network if available
### Upload Fails
**Problem:** File upload doesn't complete or shows an error
**Solutions:**
1. Ensure the file is a valid `.epub` file
2. Check that the SD card has enough free space
3. Try uploading a smaller file first to test
4. Refresh the browser page and try again
### Saved Password Not Working
**Problem:** Device fails to connect with saved credentials
**Solutions:**
1. When connection fails, you'll be prompted to "Forget Network"
2. Select **Yes** to remove the saved password
3. Reconnect and enter the password again
4. Choose to save the new password

View File

@ -1,334 +0,0 @@
# 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

View File

@ -1,331 +0,0 @@
# Webserver Endpoints
This document describes all HTTP and WebSocket endpoints available on the CrossPoint Reader webserver.
- [Webserver Endpoints](#webserver-endpoints)
- [Overview](#overview)
- [HTTP Endpoints](#http-endpoints)
- [GET `/` - Home Page](#get----home-page)
- [GET `/files` - File Browser Page](#get-files---file-browser-page)
- [GET `/api/status` - Device Status](#get-apistatus---device-status)
- [GET `/api/files` - List Files](#get-apifiles---list-files)
- [POST `/upload` - Upload File](#post-upload---upload-file)
- [POST `/mkdir` - Create Folder](#post-mkdir---create-folder)
- [POST `/delete` - Delete File or Folder](#post-delete---delete-file-or-folder)
- [WebSocket Endpoint](#websocket-endpoint)
- [Port 81 - Fast Binary Upload](#port-81---fast-binary-upload)
- [Network Modes](#network-modes)
- [Station Mode (STA)](#station-mode-sta)
- [Access Point Mode (AP)](#access-point-mode-ap)
- [Notes](#notes)
## Overview
The CrossPoint Reader exposes a webserver for file management and device monitoring:
- **HTTP Server**: Port 80
- **WebSocket Server**: Port 81 (for fast binary uploads)
---
## HTTP Endpoints
### GET `/` - Home Page
Serves the home page HTML interface.
**Request:**
```bash
curl http://crosspoint.local/
```
**Response:** HTML page (200 OK)
---
### GET `/files` - File Browser Page
Serves the file browser HTML interface.
**Request:**
```bash
curl http://crosspoint.local/files
```
**Response:** HTML page (200 OK)
---
### GET `/api/status` - Device Status
Returns JSON with device status information.
**Request:**
```bash
curl http://crosspoint.local/api/status
```
**Response (200 OK):**
```json
{
"version": "1.0.0",
"ip": "192.168.1.100",
"mode": "STA",
"rssi": -45,
"freeHeap": 123456,
"uptime": 3600
}
```
| Field | Type | Description |
| ---------- | ------ | --------------------------------------------------------- |
| `version` | string | CrossPoint firmware version |
| `ip` | string | Device IP address |
| `mode` | string | `"STA"` (connected to WiFi) or `"AP"` (access point mode) |
| `rssi` | number | WiFi signal strength in dBm (0 in AP mode) |
| `freeHeap` | number | Free heap memory in bytes |
| `uptime` | number | Seconds since device boot |
---
### GET `/api/files` - List Files
Returns a JSON array of files and folders in the specified directory.
**Request:**
```bash
# List root directory
curl http://crosspoint.local/api/files
# List specific directory
curl "http://crosspoint.local/api/files?path=/Books"
```
**Query Parameters:**
| Parameter | Required | Default | Description |
| --------- | -------- | ------- | ---------------------- |
| `path` | No | `/` | Directory path to list |
**Response (200 OK):**
```json
[
{"name": "MyBook.epub", "size": 1234567, "isDirectory": false, "isEpub": true},
{"name": "Notes", "size": 0, "isDirectory": true, "isEpub": false},
{"name": "document.pdf", "size": 54321, "isDirectory": false, "isEpub": false}
]
```
| Field | Type | Description |
| ------------- | ------- | ---------------------------------------- |
| `name` | string | File or folder name |
| `size` | number | Size in bytes (0 for directories) |
| `isDirectory` | boolean | `true` if the item is a folder |
| `isEpub` | boolean | `true` if the file has `.epub` extension |
**Notes:**
- Hidden files (starting with `.`) are automatically filtered out
- System folders (`System Volume Information`, `XTCache`) are hidden
---
### POST `/upload` - Upload File
Uploads a file to the SD card via multipart form data.
**Request:**
```bash
# Upload to root directory
curl -X POST -F "file=@mybook.epub" http://crosspoint.local/upload
# Upload to specific directory
curl -X POST -F "file=@mybook.epub" "http://crosspoint.local/upload?path=/Books"
```
**Query Parameters:**
| Parameter | Required | Default | Description |
| --------- | -------- | ------- | ------------------------------- |
| `path` | No | `/` | Target directory for the upload |
**Response (200 OK):**
```
File uploaded successfully: mybook.epub
```
**Error Responses:**
| Status | Body | Cause |
| ------ | ----------------------------------------------- | --------------------------- |
| 400 | `Failed to create file on SD card` | Cannot create file |
| 400 | `Failed to write to SD card - disk may be full` | Write error during upload |
| 400 | `Failed to write final data to SD card` | Error flushing final buffer |
| 400 | `Upload aborted` | Client aborted the upload |
| 400 | `Unknown error during upload` | Unspecified error |
**Notes:**
- Existing files with the same name will be overwritten
- Uses a 4KB buffer for efficient SD card writes
---
### POST `/mkdir` - Create Folder
Creates a new folder on the SD card.
**Request:**
```bash
curl -X POST -d "name=NewFolder&path=/" http://crosspoint.local/mkdir
```
**Form Parameters:**
| Parameter | Required | Default | Description |
| --------- | -------- | ------- | ---------------------------- |
| `name` | Yes | - | Name of the folder to create |
| `path` | No | `/` | Parent directory path |
**Response (200 OK):**
```
Folder created: NewFolder
```
**Error Responses:**
| Status | Body | Cause |
| ------ | ----------------------------- | ----------------------------- |
| 400 | `Missing folder name` | `name` parameter not provided |
| 400 | `Folder name cannot be empty` | Empty folder name |
| 400 | `Folder already exists` | Folder with same name exists |
| 500 | `Failed to create folder` | SD card error |
---
### POST `/delete` - Delete File or Folder
Deletes a file or folder from the SD card.
**Request:**
```bash
# Delete a file
curl -X POST -d "path=/Books/mybook.epub&type=file" http://crosspoint.local/delete
# Delete an empty folder
curl -X POST -d "path=/OldFolder&type=folder" http://crosspoint.local/delete
```
**Form Parameters:**
| Parameter | Required | Default | Description |
| --------- | -------- | ------- | -------------------------------- |
| `path` | Yes | - | Path to the item to delete |
| `type` | No | `file` | Type of item: `file` or `folder` |
**Response (200 OK):**
```
Deleted successfully
```
**Error Responses:**
| Status | Body | Cause |
| ------ | --------------------------------------------- | ----------------------------- |
| 400 | `Missing path` | `path` parameter not provided |
| 400 | `Cannot delete root directory` | Attempted to delete `/` |
| 400 | `Folder is not empty. Delete contents first.` | Non-empty folder |
| 403 | `Cannot delete system files` | Hidden file (starts with `.`) |
| 403 | `Cannot delete protected items` | Protected system folder |
| 404 | `Item not found` | Path does not exist |
| 500 | `Failed to delete item` | SD card error |
**Protected Items:**
- Files/folders starting with `.`
- `System Volume Information`
- `XTCache`
---
## WebSocket Endpoint
### Port 81 - Fast Binary Upload
A WebSocket endpoint for high-speed binary file uploads. More efficient than HTTP multipart for large files.
**Connection:**
```
ws://crosspoint.local:81/
```
**Protocol:**
1. **Client** sends TEXT message: `START:<filename>:<size>:<path>`
2. **Server** responds with TEXT: `READY`
3. **Client** sends BINARY messages with file data chunks
4. **Server** sends TEXT progress updates: `PROGRESS:<received>:<total>`
5. **Server** sends TEXT when complete: `DONE` or `ERROR:<message>`
**Example Session:**
```
Client -> "START:mybook.epub:1234567:/Books"
Server -> "READY"
Client -> [binary chunk 1]
Client -> [binary chunk 2]
Server -> "PROGRESS:65536:1234567"
Client -> [binary chunk 3]
...
Server -> "PROGRESS:1234567:1234567"
Server -> "DONE"
```
**Error Messages:**
| Message | Cause |
| --------------------------------- | ---------------------------------- |
| `ERROR:Failed to create file` | Cannot create file on SD card |
| `ERROR:Invalid START format` | Malformed START message |
| `ERROR:No upload in progress` | Binary data received without START |
| `ERROR:Write failed - disk full?` | SD card write error |
**Example with `websocat`:**
```bash
# Interactive session
websocat ws://crosspoint.local:81
# Then type:
START:mybook.epub:1234567:/Books
# Wait for READY, then send binary data
```
**Notes:**
- Progress updates are sent every 64KB or at completion
- Disconnection during upload will delete the incomplete file
- Existing files with the same name will be overwritten
---
## Network Modes
The device can operate in two network modes:
### Station Mode (STA)
- Device connects to an existing WiFi network
- IP address assigned by router/DHCP
- `mode` field in `/api/status` returns `"STA"`
- `rssi` field shows signal strength
### Access Point Mode (AP)
- Device creates its own WiFi hotspot
- Default IP is typically `192.168.4.1`
- `mode` field in `/api/status` returns `"AP"`
- `rssi` field returns `0`
---
## Notes
- These examples use `crosspoint.local`. If your network does not support mDNS or the address does not resolve, replace it with the specific **IP Address** displayed on your device screen (e.g., `http://192.168.1.102/`).
- All paths on the SD card start with `/`
- Trailing slashes are automatically stripped (except for root `/`)
- The webserver uses chunked transfer encoding for file listings

View File

@ -170,9 +170,57 @@ This is useful for organizing your ebooks by genre, author, or series.
--- ---
## Command Line File Management ## Troubleshooting
For power users, you can manage files directly from your terminal using `curl` while the device is in File Upload mode a detailed documentation can be found [here](./webserver-endpoints.md). ### Cannot See the Device on the Network
**Problem:** Browser shows "Cannot connect" or "Site can't be reached"
**Solutions:**
1. Verify both devices are on the **same WiFi network**
- Check your computer/phone WiFi settings
- Confirm the CrossPoint Reader shows "Connected" status
2. Double-check the IP address
- Make sure you typed it correctly
- Include `http://` at the beginning
3. Try disabling VPN if you're using one
4. Some networks have "client isolation" enabled - check with your network administrator
### Connection Drops or Times Out
**Problem:** WiFi connection is unstable
**Solutions:**
1. Move closer to the WiFi router
2. Check signal strength on the device (should be at least `||` or better)
3. Avoid interference from other devices
4. Try a different WiFi network if available
### Upload Fails
**Problem:** File upload doesn't complete or shows an error
**Solutions:**
1. Ensure the file is a valid `.epub` file
2. Check that the SD card has enough free space
3. Try uploading a smaller file first to test
4. Refresh the browser page and try again
### Saved Password Not Working
**Problem:** Device fails to connect with saved credentials
**Solutions:**
1. When connection fails, you'll be prompted to "Forget Network"
2. Select **Yes** to remove the saved password
3. Reconnect and enter the password again
4. Choose to save the new password
---
## Security Notes ## Security Notes
@ -221,5 +269,4 @@ Your uploaded files will be immediately available in the file browser!
## Related Documentation ## Related Documentation
- [User Guide](../USER_GUIDE.md) - General device operation - [User Guide](../USER_GUIDE.md) - General device operation
- [Troubleshooting](./troubleshooting.md) - Troubleshooting
- [README](../README.md) - Project overview and features - [README](../README.md) - Project overview and features

View File

@ -1,195 +0,0 @@
# 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

@ -22,7 +22,8 @@ void EpdFont::getTextBounds(const char* string, const int startX, const int star
const EpdGlyph* glyph = getGlyph(cp); const EpdGlyph* glyph = getGlyph(cp);
if (!glyph) { if (!glyph) {
glyph = getGlyph(REPLACEMENT_GLYPH); // TODO: Replace with fallback glyph property?
glyph = getGlyph('?');
} }
if (!glyph) { if (!glyph) {

View File

@ -5,6 +5,7 @@
#include <cstdint> #include <cstdint>
/// Font data stored PER GLYPH /// Font data stored PER GLYPH
#pragma pack(push, 1)
typedef struct { typedef struct {
uint8_t width; ///< Bitmap dimensions in pixels uint8_t width; ///< Bitmap dimensions in pixels
uint8_t height; ///< Bitmap dimensions in pixels uint8_t height; ///< Bitmap dimensions in pixels
@ -13,7 +14,9 @@ typedef struct {
int16_t top; ///< Y dist from cursor pos to UL corner int16_t top; ///< Y dist from cursor pos to UL corner
uint16_t dataLength; ///< Size of the font data. uint16_t dataLength; ///< Size of the font data.
uint32_t dataOffset; ///< Pointer into EpdFont->bitmap uint32_t dataOffset; ///< Pointer into EpdFont->bitmap
bool compressed;
} EpdGlyph; } EpdGlyph;
#pragma pack(pop)
/// Glyph interval structure /// Glyph interval structure
typedef struct { typedef struct {

View File

@ -33,10 +33,23 @@
#include <builtinFonts/notosans_18_bolditalic.h> #include <builtinFonts/notosans_18_bolditalic.h>
#include <builtinFonts/notosans_18_italic.h> #include <builtinFonts/notosans_18_italic.h>
#include <builtinFonts/notosans_18_regular.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_bold.h>
#include <builtinFonts/ubuntu_10_regular.h> #include <builtinFonts/ubuntu_10_regular.h>
#include <builtinFonts/ubuntu_12_bold.h> #include <builtinFonts/ubuntu_12_bold.h>
#include <builtinFonts/ubuntu_12_regular.h> #include <builtinFonts/ubuntu_12_regular.h>
// Custom fonts registry (generated by convert-builtin-fonts.sh)
#include <builtinFonts/custom/customFonts.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

@ -1,99 +0,0 @@
/**
* 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

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

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