Compare commits
194 Commits
feature/gl
...
crosspoint
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3853bfe113 | ||
|
|
fbe7d2feb4 | ||
|
|
520a0cb124 | ||
|
|
be8b02efd6 | ||
|
|
448ce55bb4 | ||
|
|
5464d9de3a | ||
|
|
48267ad848 | ||
|
|
dd630dcf72 | ||
|
|
ef705d3ac6 | ||
|
|
bab374a675 | ||
|
|
c171813045 | ||
|
|
d5e42b9e40 | ||
|
|
168c8fdb69 | ||
|
|
492cf976f5 | ||
|
|
25e255af50 | ||
|
|
a4adbb9dfe | ||
|
|
6ceba56620 | ||
|
|
62643ae933 | ||
|
|
8b41dccfb9 | ||
|
|
3204fa0339 | ||
|
|
bc6dc357eb | ||
|
|
ffe2aebd7e | ||
|
|
4965e63ad4 | ||
|
|
4db384edb6 | ||
|
|
f3075002c1 | ||
|
|
3e3be8bd23 | ||
|
|
800b07a2e5 | ||
|
|
2a31559747 | ||
|
|
c052512b1b | ||
|
|
bd95bfd44d | ||
|
|
fe446d4690 | ||
|
|
23e73312b4 | ||
|
|
e8d332e34f | ||
|
|
54004d5a5b | ||
|
|
d6e17c09ca | ||
|
|
7288e6499d | ||
|
|
5dab3ad5a3 | ||
|
|
82165c1022 | ||
|
|
e1fcec7d69 | ||
|
|
69a26ccb0e | ||
|
|
245d5a7dd8 | ||
|
|
e991fb10a6 | ||
|
|
4080184b27 | ||
|
|
8288cd2890 | ||
|
|
80c9e7a1d6 | ||
|
|
c2a966a6ea | ||
|
|
158caacfe0 | ||
|
|
1496ce68a6 | ||
|
|
0ab8e516f4 | ||
|
|
8687af738a | ||
|
|
a04388fd6c | ||
|
|
7349fbb208 | ||
|
|
9a723fead8 | ||
|
|
5fd1da5d2e | ||
|
|
0a2c661b8b | ||
|
|
8fb6402023 | ||
|
|
3b99459b82 | ||
|
|
1442521d0c | ||
|
|
7bbdf95aff | ||
|
|
76e9cf8f75 | ||
|
|
397abe1ef0 | ||
|
|
bc4edeef26 | ||
|
|
c90304f59b | ||
|
|
6ffd19a7e8 | ||
|
|
ff0392b9d2 | ||
|
|
03a18fb298 | ||
|
|
f01f3979bc | ||
|
|
3cee01b43d | ||
|
|
8920c62957 | ||
|
|
991b6b5a01 | ||
|
|
d8b8c5bad9 | ||
|
|
31199f9dd1 | ||
|
|
25b75b706f | ||
|
|
aa87b3f294 | ||
|
|
7a4af97ae8 | ||
|
|
703d95523b | ||
|
|
1a38fd96af | ||
|
|
5f4fa3bebe | ||
|
|
94a7c2c0b8 | ||
|
|
41eabba0d4 | ||
|
|
f739869519 | ||
|
|
99702a342c | ||
|
|
a707cc6da2 | ||
|
|
d8bee1d21f | ||
|
|
2f7312e6a0 | ||
|
|
d02e2e5b5e | ||
|
|
2c24ee3f81 | ||
|
|
cda8a5ec6d | ||
|
|
6e0cc4cf46 | ||
|
|
4d74cd795a | ||
|
|
08adc91bbe | ||
|
|
5996936c2e | ||
|
|
af58eb1987 | ||
|
|
e9e9ef68da | ||
|
|
91c8cc67ce | ||
|
|
fedc14bcb4 | ||
|
|
2b2bc95cf2 | ||
|
|
6bedc4ffec | ||
|
|
ecff988a29 | ||
|
|
c87a06edb8 | ||
|
|
7fce5b347d | ||
|
|
2f21f55512 | ||
|
|
1e20d30875 | ||
|
|
5c3828efe8 | ||
|
|
2952d7554c | ||
|
|
881f866d86 | ||
|
|
e3ae125f3c | ||
|
|
67494a7c90 | ||
|
|
59f493d293 | ||
|
|
ac1251282b | ||
|
|
16caa66b4a | ||
|
|
cf16d33710 | ||
|
|
51a4faddd4 | ||
|
|
a91bb0b1b8 | ||
|
|
481b8210fb | ||
|
|
c166b89f7b | ||
|
|
d5a9873bd7 | ||
|
|
6b533207e1 | ||
|
|
9493fb1f18 | ||
|
|
ff22a82563 | ||
|
|
3ce11f14ce | ||
|
|
47ef92e8fd | ||
|
|
1e506cce39 | ||
|
|
e3d6e32609 | ||
|
|
d399afb53d | ||
|
|
838993259d | ||
|
|
cc74039cab | ||
|
|
72fa6f8395 | ||
|
|
87d6c032a5 | ||
|
|
c9b5462370 | ||
|
|
e548bfc0e1 | ||
|
|
73c30748d8 | ||
|
|
fd6ea01f64 | ||
|
|
8f3d226bf3 | ||
|
|
5c9412b141 | ||
|
|
750a6ee1d8 | ||
|
|
be2de1123b | ||
|
|
20b6d4d055 | ||
|
|
57379a6590 | ||
|
|
6d68466891 | ||
|
|
8824c87490 | ||
|
|
5fef99c641 | ||
|
|
7a792a5384 | ||
|
|
f69cddf2cc | ||
|
|
7185e5d287 | ||
|
|
12940cc546 | ||
|
|
be10b90a71 | ||
|
|
94ce987f2c | ||
|
|
21277e03eb | ||
|
|
4eef2b5793 | ||
|
|
5a55fa1c6e | ||
|
|
c98ba142e8 | ||
|
|
c1c94c0112 | ||
|
|
eb84bcee7c | ||
|
|
d45f355e87 | ||
|
|
56ec3dfb6d | ||
|
|
e517945aaa | ||
|
|
489220832f | ||
|
|
3ee10b31ab | ||
|
|
a946c83a07 | ||
|
|
847786e342 | ||
|
|
c2fb8ce55d | ||
|
|
ed05554d74 | ||
|
|
9a9dc044ce | ||
|
|
1c027ce2cd | ||
|
|
49f97b69ca | ||
|
|
14643d0225 | ||
|
|
fecd1849b9 | ||
|
|
2040e088e7 | ||
|
|
65d23910a3 | ||
|
|
52995fa722 | ||
|
|
d4f8eda154 | ||
|
|
33b8fa0e19 | ||
|
|
16c760b2d2 | ||
|
|
8f3df7e10e | ||
|
|
0165fab581 | ||
|
|
66b100c6ca | ||
|
|
41bda43899 | ||
|
|
82f21f3c1d | ||
|
|
a9242fe61f | ||
|
|
88d0d90471 | ||
|
|
97c4871316 | ||
|
|
66811bf50b | ||
|
|
87287012ba | ||
|
|
d4ae108d9b | ||
|
|
7240cd52a9 | ||
|
|
0bae3bbf64 | ||
|
|
2b12a65011 | ||
|
|
46fa186b82 | ||
|
|
0cc2c64df2 | ||
|
|
1f956e972b | ||
|
|
9c573e6f7f | ||
|
|
0edb2baced | ||
|
|
b792b792bf |
41
.gitea/workflows/ci.yml
Normal file
41
.gitea/workflows/ci.yml
Normal file
@ -0,0 +1,41 @@
|
||||
name: CI
|
||||
'on':
|
||||
push:
|
||||
branches: [master, crosspoint-ef]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Python
|
||||
run: |
|
||||
# Use system Python on self-hosted runner
|
||||
python3 --version
|
||||
python3 -m pip install --upgrade pip
|
||||
|
||||
- name: Install PlatformIO Core
|
||||
run: python3 -m pip install --upgrade platformio
|
||||
|
||||
- name: Run cppcheck
|
||||
run: pio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high
|
||||
|
||||
- name: Run clang-format
|
||||
run: |
|
||||
# Use system clang-format if available, skip if not
|
||||
if command -v clang-format &> /dev/null; then
|
||||
./bin/clang-format-fix && git diff --exit-code || (echo "Please run 'bin/clang-format-fix' to fix formatting issues" && exit 1)
|
||||
else
|
||||
echo "clang-format not found, skipping format check"
|
||||
fi
|
||||
|
||||
- name: Generate Dictionary Index
|
||||
run: |
|
||||
python3 scripts/generate_dict_index.py --zip dict-en-en.zip --output lib/StarDict/DictPrefixIndex.generated.h
|
||||
|
||||
- name: Build CrossPoint
|
||||
run: pio run
|
||||
40
.gitea/workflows/pr-formatting-check.yml
Normal file
40
.gitea/workflows/pr-formatting-check.yml
Normal file
@ -0,0 +1,40 @@
|
||||
name: "PR Formatting"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- edited
|
||||
- synchronize
|
||||
|
||||
jobs:
|
||||
title-check:
|
||||
name: Title Check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check PR Title Format
|
||||
run: |
|
||||
PR_TITLE="${{ github.event.pull_request.title }}"
|
||||
echo "Checking PR title: $PR_TITLE"
|
||||
|
||||
# Conventional commit pattern: type(scope): description or type: description
|
||||
# Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
||||
PATTERN="^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([a-zA-Z0-9_-]+\))?: .+"
|
||||
|
||||
if echo "$PR_TITLE" | grep -qE "$PATTERN"; then
|
||||
echo "✓ PR title follows conventional commit format"
|
||||
else
|
||||
echo "✗ PR title does not follow conventional commit format"
|
||||
echo ""
|
||||
echo "Expected format: type(scope): description"
|
||||
echo " or: type: description"
|
||||
echo ""
|
||||
echo "Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " feat(reader): add bookmark sync feature"
|
||||
echo " fix: resolve memory leak in epub parser"
|
||||
echo " docs: update README with new instructions"
|
||||
exit 1
|
||||
fi
|
||||
40
.gitea/workflows/release.yml
Normal file
40
.gitea/workflows/release.yml
Normal file
@ -0,0 +1,40 @@
|
||||
name: Compile Release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Python
|
||||
run: |
|
||||
# Use system Python on self-hosted runner
|
||||
python3 --version
|
||||
python3 -m pip install --upgrade pip
|
||||
|
||||
- name: Install PlatformIO Core
|
||||
run: python3 -m pip install --upgrade platformio
|
||||
|
||||
- name: Generate Dictionary Index
|
||||
run: |
|
||||
python3 scripts/generate_dict_index.py --zip dict-en-en.zip --output lib/StarDict/DictPrefixIndex.generated.h
|
||||
|
||||
- name: Build CrossPoint
|
||||
run: pio run -e gh_release
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: CrossPoint-${{ github.ref_name }}
|
||||
path: |
|
||||
.pio/build/gh_release/bootloader.bin
|
||||
.pio/build/gh_release/firmware.bin
|
||||
.pio/build/gh_release/firmware.elf
|
||||
.pio/build/gh_release/firmware.map
|
||||
.pio/build/gh_release/partitions.bin
|
||||
15
.github/PULL_REQUEST_TEMPLATE.md
vendored
15
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,9 +1,18 @@
|
||||
## Summary
|
||||
|
||||
* **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 is the goal of this PR?** (e.g., Implements the new feature for file uploading.)
|
||||
* **What changes are included?**
|
||||
|
||||
## Additional Context
|
||||
|
||||
* Add any other information that might be helpful for the reviewer (e.g., performance implications, potential risks, specific areas to focus on).
|
||||
* Add any other information that might be helpful for the reviewer (e.g., performance implications, potential risks,
|
||||
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 >**_
|
||||
|
||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -7,11 +7,11 @@ name: CI
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.14'
|
||||
|
||||
26
.github/workflows/pr-formatting-check.yml
vendored
Normal file
26
.github/workflows/pr-formatting-check.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
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 }}
|
||||
3
.github/workflows/release.yml
vendored
3
.github/workflows/release.yml
vendored
@ -7,17 +7,18 @@ on:
|
||||
jobs:
|
||||
build-release:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
~/.cache/pip
|
||||
~/.platformio/.cache
|
||||
key: ${{ runner.os }}-pio
|
||||
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.14'
|
||||
|
||||
15
.gitignore
vendored
15
.gitignore
vendored
@ -2,5 +2,20 @@
|
||||
.idea
|
||||
.DS_Store
|
||||
.vscode
|
||||
.cursor/
|
||||
chat-summaries/
|
||||
lib/EpdFont/fontsrc
|
||||
*.generated.h
|
||||
.vs
|
||||
build
|
||||
**/__pycache__/
|
||||
test/epubs/
|
||||
CrossPoint-ef.md
|
||||
Serial_print.code-search
|
||||
|
||||
# Gitea Release note drafts
|
||||
release-notes-*.md
|
||||
|
||||
# Gitea Actions runner config (contains credentials)
|
||||
.runner
|
||||
.runner.*
|
||||
|
||||
4
.gitmodules
vendored
4
.gitmodules
vendored
@ -1,3 +1,5 @@
|
||||
[submodule "open-x4-sdk"]
|
||||
path = open-x4-sdk
|
||||
url = https://github.com/open-x4-epaper/community-sdk.git
|
||||
url = https://code.cottongin.xyz/cottongin/community-sdk.git
|
||||
branch = crosspoint-ef
|
||||
ignore = dirty
|
||||
|
||||
15
README.md
15
README.md
@ -1,4 +1,15 @@
|
||||
# CrossPoint Reader
|
||||
# CrossPoint Reader (ef fork)
|
||||
|
||||
> **Note:** This is **crosspoint-ef**, a heavily customized fork of [CrossPoint Reader](https://github.com/crosspoint-reader/crosspoint-reader) with additional features, UI improvements, and bug fixes. It also uses a [forked community-sdk](https://code.cottongin.xyz/cottongin/community-sdk) with additional hardware support.
|
||||
>
|
||||
> **Documentation:**
|
||||
> - [Feature Overview](./docs/crosspoint-ef-features.md) - What's new in this fork
|
||||
> - [User Guide](./docs/crosspoint-ef-user-guide.md) - How to use the new features
|
||||
> - [Technical Comparison](./docs/branch-comparison-summary.md) - Detailed diff from upstream
|
||||
>
|
||||
> **Disclaimer:** Much of the code in this fork was developed with assistance from [Claude](https://claude.ai), an AI assistant by Anthropic.
|
||||
|
||||
---
|
||||
|
||||
Firmware for the **Xteink X4** e-paper display reader (unaffiliated with Xteink).
|
||||
Built using **PlatformIO** and targeting the **ESP32-C3** microcontroller.
|
||||
@ -41,6 +52,8 @@ This project is **not affiliated with Xteink**; it's built as a community projec
|
||||
- [ ] Full UTF support
|
||||
- [x] Screen rotation
|
||||
|
||||
Multi-language support: Read EPUBs in various languages, including English, Spanish, French, German, Italian, Portuguese, Russian, Ukrainian, Polish, Swedish, Norwegian, [and more](./USER_GUIDE.md#supported-languages).
|
||||
|
||||
See [the user guide](./USER_GUIDE.md) for instructions on operating CrossPoint.
|
||||
|
||||
## Installing
|
||||
|
||||
146
USER_GUIDE.md
146
USER_GUIDE.md
@ -1,17 +1,37 @@
|
||||
# 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
|
||||
|
||||
The device utilises the standard buttons on the Xtink X4 (in the same layout as the manufacturer firmware, by default):
|
||||
|
||||
### Button Layout
|
||||
| Location | Buttons |
|
||||
|-----------------|--------------------------------------------|
|
||||
| **Bottom Edge** | **Back**, **Confirm**, **Left**, **Right** |
|
||||
| **Right Side** | **Power**, **Volume Up**, **Volume Down** |
|
||||
| Location | Buttons |
|
||||
| --------------- | ---------------------------------------------------- |
|
||||
| **Bottom Edge** | **Back**, **Confirm**, **Left**, **Right** |
|
||||
| **Right Side** | **Power**, **Volume Up**, **Volume Down**, **Reset** |
|
||||
|
||||
Button layout can be customized in **[Settings](#35-settings)**.
|
||||
|
||||
@ -21,8 +41,10 @@ Button layout can be customized in **[Settings](#35-settings)**.
|
||||
|
||||
### Power On / Off
|
||||
|
||||
To turn the device on or off, **press and hold the Power button for half a second**. In **[Settings](#35-settings)** you can configure
|
||||
the power button to trigger on a short press instead of a long one.
|
||||
To turn the device on or off, **press and hold the Power button for approximately half a second**.
|
||||
In **[Settings](#35-settings)** you can configure the power button to turn the device off with 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
|
||||
|
||||
@ -37,15 +59,13 @@ Upon turning the device on for the first time, you will be placed on the **[Home
|
||||
|
||||
### 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
|
||||
|
||||
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.
|
||||
* **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.
|
||||
* **Open Selection:** Press **Confirm** to open a folder or read a selected book.
|
||||
|
||||
### 3.3 Reading Mode
|
||||
@ -54,42 +74,81 @@ See [Reading Mode](#4-reading-mode) below for more information.
|
||||
|
||||
### 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.
|
||||
|
||||
> [!TIP]
|
||||
> Advanced users can also manage files programmatically or via the command line using `curl`. See the [webserver docs](./docs/webserver.md) for details.
|
||||
|
||||
### 3.4.1 Calibre Wireless Transfers
|
||||
|
||||
CrossPoint supports sending books from Calibre using the CrossPoint Reader device plugin.
|
||||
|
||||
1. Install the plugin in Calibre:
|
||||
- Head to https://github.com/crosspoint-reader/calibre-plugins/releases to download the latest version of the crosspoint_reader plugin.
|
||||
- Download the zip file.
|
||||
- Open Calibre → Preferences → Plugins → Load plugin from file → Select the zip file.
|
||||
2. On the device: File Transfer → Connect to Calibre → Join a network.
|
||||
3. Make sure your computer is on the same WiFi network.
|
||||
4. In Calibre, click "Send to device" to transfer books.
|
||||
|
||||
### 3.5 Settings
|
||||
|
||||
The Settings screen allows you to configure the device's behavior. There are a few settings you can adjust:
|
||||
- **Sleep Screen**: Which sleep screen to display when the device sleeps, options are:
|
||||
- "Dark" (default) - The default dark sleep screen
|
||||
- **Sleep Screen**: Which sleep screen to display when the device sleeps:
|
||||
- "Dark" (default) - The default dark Crosspoint logo sleep screen
|
||||
- "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)
|
||||
- **Status Bar**: Configure the status bar displayed while reading, options are:
|
||||
- "None" - A blank screen
|
||||
- **Sleep Screen Cover Mode**: How to display the book cover when "Cover" sleep screen is selected:
|
||||
- "Fit" (default) - Scale the image down to fit centered on the screen, padding with white borders as necessary
|
||||
- "Crop" - Scale the image down and crop as necessary to try to to fill the screen (Note: this is experimental and may not work as expected)
|
||||
- **Sleep Screen Cover Filter**: What filter will be applied to the book cover when "Cover" sleep screen is selected
|
||||
- "None" (default) - The cover image will be converted to a grayscale image and displayed as it is
|
||||
- "Contrast" - The image will be displayed as a black & white image without grayscale conversion
|
||||
- "Inverted" - The image will be inverted as in white&black and will be displayed without grayscale conversion
|
||||
- **Status Bar**: Configure the status bar displayed while reading:
|
||||
- "None" - No status bar
|
||||
- "No Progress" - Show status bar without reading progress
|
||||
- "Full" - Show status bar with reading progress
|
||||
- **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 word indentation.
|
||||
- **Short Power Button Click**: Whether to trigger the power button on a short press or a long press.
|
||||
- **Reading Orientation**: Set the screen orientation for reading, options are:
|
||||
- **Hide Battery %**: Configure where to suppress the battery pecentage display in the status bar; the battery icon will still be shown:
|
||||
- "Never" - Always show battery percentage (default)
|
||||
- "In Reader" - Show battery percentage everywhere except in reading mode
|
||||
- "Always" - Always hide battery percentage
|
||||
- **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
|
||||
- "Landscape CW" - Landscape, rotated clockwise
|
||||
- "Inverted" - Portrait, upside down
|
||||
- "Landscape CCW" - Landscape, rotated counter-clockwise
|
||||
- **Front Button Layout**: Configure the order of the bottom edge buttons, options are:
|
||||
- "Bck, Cnfrm, Lft, Rght" (default) - Back, Confirm, Left, Right
|
||||
- "Lft, Rght, Bck, Cnfrm" - Left, Right, Back, Confirm
|
||||
- "Lft, Bck, Cnfrm, Rght" - Left, Back, Confirm, Right
|
||||
- **Side Button Layout**: Swap the order of the 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:
|
||||
- **Front Button Layout**: Configure the order of the bottom edge buttons:
|
||||
- Back, Confirm, Left, Right (default)
|
||||
- Left, Right, Back, Confirm
|
||||
- Left, Back, Confirm, Right
|
||||
- Back, Confirm, Right, Left
|
||||
- **Side Button Layout (reader)**: Swap the order of the up and down volume buttons from Previous/Next to Next/Previous. This change is only in effect when reading.
|
||||
- **Long-press Chapter Skip**: Set whether long-pressing page turn buttons skip to the next/previous chapter.
|
||||
- "Chapter Skip" (default) - Long-pressing skips to next/previous chapter
|
||||
- "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
|
||||
- "Noto Sans" - Google's sans-serif font
|
||||
- "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 Line Spacing**: Adjust the spacing between lines, options are "Tight", "Normal", or "Wide".
|
||||
- **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 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.
|
||||
|
||||
### 3.6 Sleep Screen
|
||||
@ -97,9 +156,7 @@ 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:
|
||||
|
||||
- **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]
|
||||
> You'll need to set the **Sleep Screen** setting to **Custom** in order to use these images.
|
||||
@ -117,19 +174,35 @@ Once you have opened a book, the button layout changes to facilitate reading.
|
||||
|
||||
### Page Turning
|
||||
| Action | Buttons |
|
||||
|-------------------|--------------------------------------|
|
||||
| ----------------- | ------------------------------------ |
|
||||
| **Previous Page** | Press **Left** _or_ **Volume Up** |
|
||||
| **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
|
||||
* **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.
|
||||
|
||||
This feature can be disabled in **[Settings](#35-settings)** to help avoid changing chapters by mistake.
|
||||
|
||||
|
||||
### System Navigation
|
||||
* **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 **Back** to close the book and return to the **[Home](#31-home-screen)** screen.
|
||||
* **Return to Home:** Press and **hold** the **Back** button to close the book and return to the **[Home](#31-home-screen)** screen.
|
||||
* **Chapter Menu:** Press **Confirm** to open the **[Table of Contents/Chapter Selection](#5-chapter-selection-screen)**.
|
||||
|
||||
### Supported Languages
|
||||
|
||||
CrossPoint renders text using the following Unicode character blocks, enabling support for a wide range of languages:
|
||||
|
||||
* **Latin Script (Basic, Supplement, Extended-A):** Covers English, German, French, Spanish, Portuguese, Italian, Dutch, Swedish, Norwegian, Danish, Finnish, Polish, Czech, Hungarian, Romanian, Slovak, Slovenian, Turkish, and others.
|
||||
* **Cyrillic Script (Standard and Extended):** Covers Russian, Ukrainian, Belarusian, Bulgarian, Serbian, Macedonian, Kazakh, Kyrgyz, Mongolian, and others.
|
||||
|
||||
What is not supported: Chinese, Japanese, Korean, Vietnamese, Hebrew, Arabic and Farsi.
|
||||
|
||||
---
|
||||
|
||||
## 5. Chapter Selection Screen
|
||||
@ -144,7 +217,6 @@ Accessible by pressing **Confirm** while inside a book.
|
||||
|
||||
## 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.
|
||||
|
||||
137
claude_notes/ghosting-bisect-debug_2026-01-27_09-42-35.md
Normal file
137
claude_notes/ghosting-bisect-debug_2026-01-27_09-42-35.md
Normal file
@ -0,0 +1,137 @@
|
||||
# Ghosting Issue Bisect Debug Summary
|
||||
|
||||
**Date:** 2026-01-27
|
||||
**Branch:** `catch-up-PR-merges`
|
||||
**Issue:** Text ghosting on page turns when anti-aliasing enabled
|
||||
|
||||
---
|
||||
|
||||
## Problem Description
|
||||
|
||||
After merging 15 upstream PRs, ghosting artifacts appeared when turning pages in the EPUB reader. The ghosting manifested as residual edges/outlines of previous page text, visible only when text anti-aliasing was enabled.
|
||||
|
||||
---
|
||||
|
||||
## The 15 Merged PRs (in merge order)
|
||||
|
||||
| Order | Commit | PR | Description |
|
||||
|-------|--------|-----|-------------|
|
||||
| 1 | `703d955` | #466 | fix: Add .vs folder to .gitignore |
|
||||
| 2 | `7a4af97` | #530 | docs: Update README with supported languages for EPUB |
|
||||
| 3 | `aa87b3f` | #547 | docs: add font generation commands to builtin font headers |
|
||||
| 4 | `25b75b7` | #425 | fix: Allow line break after ellipsis and underscore |
|
||||
| 5 | `31199f9` | #507 | fix: remove decimal places from progress % |
|
||||
| 6 | `d8b8c5b` | #526 | fix: add txt books to recent tab |
|
||||
| 7 | `991b6b5` | #498 | feat: treat .md files as .txt |
|
||||
| 8 | `8920c62` | #525 | fix: line break - flush word before br tag |
|
||||
| 9 | `3cee01b` | #460 | feat: add new configuration for front buttons |
|
||||
| 10 | `f01f397` | #557 | fix: rotate origin in drawImage |
|
||||
| 11 | `03a18fb` | #484 | UX improvement to Forget Network page |
|
||||
| 12 | `ff0392b` | #492 | fix: Validate settings on read |
|
||||
| 13 | `6ffd19a` | #482 | fix: short-press power button to wakeup |
|
||||
| 14 | `c90304f` | #465 | fix: cover artifacts - merge crop parameter |
|
||||
| 15 | `bc4edee` | #404 | Refactor: Replace CalibreWirelessActivity with CalibreConnectActivity |
|
||||
|
||||
**Base commit:** `1a38fd9` (before any PR merges)
|
||||
**Checkpoint commit:** `397abe1` (after all PR merges)
|
||||
|
||||
---
|
||||
|
||||
## Bisect Process
|
||||
|
||||
### Initial State
|
||||
- **GOOD:** `1a38fd9` - no ghosting
|
||||
- **BAD:** `397abe1` (HEAD) - ghosting present
|
||||
|
||||
### Bisect Steps
|
||||
|
||||
| Step | Commit | PR | Result | Remaining |
|
||||
|------|--------|-----|--------|-----------|
|
||||
| 1 | `991b6b5` | #498 (midpoint) | NO ghosting | Bug in commits 8-15 |
|
||||
| 2 | `ff0392b` | #492 (midpoint of 8-15) | NO ghosting | Bug in commits 13-15 |
|
||||
| 3 | `c90304f` | #465 | NO ghosting | Bug in commits 15 or checkpoint |
|
||||
| 4 | `bc4edee` | #404 | NO ghosting | Bug in checkpoint only |
|
||||
|
||||
### Compilation Issue During Bisect
|
||||
|
||||
A conflict from PR #526 merge left `RECENT_BOOKS.addBook()` with 1 argument instead of 3. This caused compilation failures at intermediate commits. Temporary fix applied at each step:
|
||||
|
||||
```cpp
|
||||
// Changed from:
|
||||
RECENT_BOOKS.addBook(txt->getPath());
|
||||
// To:
|
||||
RECENT_BOOKS.addBook(txt->getPath(), txt->getTitle(), "");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Root Cause Finding
|
||||
|
||||
**The ghosting was NOT caused by any upstream PR.**
|
||||
|
||||
After testing all commits, the bisect pointed to the checkpoint commit `397abe1`. However, the diff between `bc4edee` and `397abe1` only contained:
|
||||
- The `addBook` fix (unrelated to display)
|
||||
- Removing duplicate `handleDownload` (unrelated to display)
|
||||
|
||||
### Actual Cause: Uncommitted Local Changes
|
||||
|
||||
The ghosting was caused by **uncommitted local changes in the IDE working directory**. These changes were being preserved across `git checkout` operations because they existed in IDE buffers.
|
||||
|
||||
When `git checkout -f catch-up-PR-merges` was executed (force checkout), all local changes were discarded and the ghosting disappeared.
|
||||
|
||||
---
|
||||
|
||||
## Local Changes That Were Present
|
||||
|
||||
The following modifications existed in the working directory but were NOT in the checkpoint commit:
|
||||
|
||||
- `CrossPointSettings.h/cpp` - enum `_COUNT` suffixes, `readAndValidate`, OPDS auth fields
|
||||
- `ChapterHtmlSlimParser.h/cpp` - `flushPartWordBuffer()` function
|
||||
- `SleepActivity.cpp` - `drawImage` coordinate changes
|
||||
- `JpegToBmpConverter.h/cpp` - `crop` parameter
|
||||
- `HomeActivity.cpp` - "OPDS Browser" label
|
||||
- `SettingsActivity.cpp` - front button layout options
|
||||
- `CrossPointWebServer.h/cpp` - UDP discovery, `WsUploadStatus`
|
||||
|
||||
**Important:** These changes were actually already committed in the PR merge commits. The confusion arose because:
|
||||
1. Checking out older commits removed these changes
|
||||
2. IDE buffers or manual re-application restored them as "local changes"
|
||||
3. This created a mismatch between committed code and working directory
|
||||
|
||||
---
|
||||
|
||||
## Resolution
|
||||
|
||||
1. Force checkout to HEAD: `git checkout -f catch-up-PR-merges`
|
||||
2. Verified all PR changes are properly committed
|
||||
3. Built and tested - no ghosting
|
||||
4. Working directory is now clean (matches committed state)
|
||||
|
||||
---
|
||||
|
||||
## Key Lessons
|
||||
|
||||
1. **Always check `git status` before bisecting** - local changes can persist across checkouts
|
||||
2. **Use `git checkout -f` or `git checkout <commit> -- .`** to ensure clean state
|
||||
3. **IDE buffers can reintroduce changes** - close/reload files after checkout if needed
|
||||
4. **Bisecting with compilation errors** requires temporary fixes that don't affect the bug being investigated
|
||||
5. **The "bug" may not be in commits at all** - it could be in uncommitted working directory changes
|
||||
|
||||
---
|
||||
|
||||
## Commands Reference
|
||||
|
||||
```bash
|
||||
# Force checkout to discard local changes
|
||||
git checkout -f <branch>
|
||||
|
||||
# Checkout specific commit with clean state
|
||||
git checkout <commit> -- . && git checkout <commit>
|
||||
|
||||
# Check for uncommitted changes
|
||||
git status
|
||||
git diff --stat
|
||||
|
||||
# View what's in a specific commit
|
||||
git show <commit>:path/to/file
|
||||
```
|
||||
70
claude_notes/missing-serial-guards-2026-01-28.md
Normal file
70
claude_notes/missing-serial-guards-2026-01-28.md
Normal file
@ -0,0 +1,70 @@
|
||||
# Serial.printf Calls Without `if (Serial)` Guards
|
||||
|
||||
**Date:** 2026-01-28
|
||||
**Status:** Informational (not blocking issues)
|
||||
|
||||
## Summary
|
||||
|
||||
The codebase contains **408 Serial print calls** across 27 files in `src/`. Of these, only **16 calls** (in 2 files) have explicit `if (Serial)` guards.
|
||||
|
||||
**This is not a problem** because `Serial.setTxTimeoutMs(0)` is called in `setup()` before any activity code runs, making all Serial output non-blocking globally.
|
||||
|
||||
## Protection Mechanism
|
||||
|
||||
In `src/main.cpp` (lines 467-468):
|
||||
```cpp
|
||||
Serial.begin(115200);
|
||||
Serial.setTxTimeoutMs(0); // Non-blocking TX - critical for USB disconnect handling
|
||||
```
|
||||
|
||||
This ensures that even without `if (Serial)` guards, Serial.printf calls will return immediately when USB is disconnected instead of blocking indefinitely.
|
||||
|
||||
## Files with `if (Serial)` Guards (16 calls)
|
||||
|
||||
| File | Protected Calls |
|
||||
|------|-----------------|
|
||||
| `src/activities/reader/EpubReaderActivity.cpp` | 15 |
|
||||
| `src/main.cpp` | 1 |
|
||||
|
||||
## Files Without Guards (392 calls)
|
||||
|
||||
These calls are protected by `Serial.setTxTimeoutMs(0)` but don't have explicit guards:
|
||||
|
||||
| File | Unguarded Calls |
|
||||
|------|-----------------|
|
||||
| `src/network/CrossPointWebServer.cpp` | 106 |
|
||||
| `src/activities/network/CrossPointWebServerActivity.cpp` | 49 |
|
||||
| `src/activities/boot_sleep/SleepActivity.cpp` | 33 |
|
||||
| `src/BookManager.cpp` | 25 |
|
||||
| `src/activities/reader/TxtReaderActivity.cpp` | 20 |
|
||||
| `src/activities/home/HomeActivity.cpp` | 16 |
|
||||
| `src/network/OtaUpdater.cpp` | 16 |
|
||||
| `src/util/Md5Utils.cpp` | 15 |
|
||||
| `src/main.cpp` | 13 (plus 1 guarded) |
|
||||
| `src/WifiCredentialStore.cpp` | 12 |
|
||||
| `src/network/HttpDownloader.cpp` | 12 |
|
||||
| `src/BookListStore.cpp` | 11 |
|
||||
| `src/activities/network/WifiSelectionActivity.cpp` | 11 |
|
||||
| `src/activities/settings/OtaUpdateActivity.cpp` | 9 |
|
||||
| `src/activities/browser/OpdsBookBrowserActivity.cpp` | 9 |
|
||||
| `src/activities/settings/ClearCacheActivity.cpp` | 7 |
|
||||
| `src/BookmarkStore.cpp` | 6 |
|
||||
| `src/RecentBooksStore.cpp` | 5 |
|
||||
| `src/activities/reader/ReaderActivity.cpp` | 4 |
|
||||
| `src/activities/Activity.h` | 3 |
|
||||
| `src/CrossPointSettings.cpp` | 3 |
|
||||
| `src/activities/network/CalibreConnectActivity.cpp` | 2 |
|
||||
| `src/activities/home/ListViewActivity.cpp` | 2 |
|
||||
| `src/activities/home/MyLibraryActivity.cpp` | 1 |
|
||||
| `src/activities/dictionary/DictionarySearchActivity.cpp` | 1 |
|
||||
| `src/CrossPointState.cpp` | 1 |
|
||||
|
||||
## Recommendation
|
||||
|
||||
No immediate action required. The global `Serial.setTxTimeoutMs(0)` protection is sufficient.
|
||||
|
||||
If desired, `if (Serial)` guards could be added to high-frequency logging paths for minor performance optimization (skipping format string processing), but this is low priority.
|
||||
|
||||
## Note on open-x4-sdk
|
||||
|
||||
The `open-x4-sdk` submodule also contains Serial calls (in `EInkDisplay.cpp`, `SDCardManager.cpp`). These are also protected by the global timeout setting since `Serial.begin()` and `setTxTimeoutMs()` are called before any SDK code executes.
|
||||
125
claude_notes/serial-blocking-debug-2026-01-28.md
Normal file
125
claude_notes/serial-blocking-debug-2026-01-28.md
Normal file
@ -0,0 +1,125 @@
|
||||
# Serial Blocking Debug Session Summary
|
||||
|
||||
**Date:** 2026-01-28
|
||||
**Issue:** Device freezes when booted without USB connected
|
||||
**Resolution:** `Serial.setTxTimeoutMs(0)` - make Serial TX non-blocking
|
||||
|
||||
## Problem Description
|
||||
|
||||
During release preparation for ef-0.15.9, the device was discovered to freeze completely when:
|
||||
1. Unplugged from USB
|
||||
2. Powered on via power button
|
||||
3. Book page displays, then device becomes unresponsive
|
||||
4. No button presses register
|
||||
|
||||
The device worked perfectly when USB was connected.
|
||||
|
||||
## Investigation Process
|
||||
|
||||
### Initial Hypotheses Tested
|
||||
|
||||
Multiple hypotheses were systematically investigated:
|
||||
|
||||
1. **Hypothesis A-D:** Display/rendering mutex issues
|
||||
- Added mutex logging to SD card
|
||||
- Mutex operations completed successfully
|
||||
- Ruled out as root cause
|
||||
|
||||
2. **Hypothesis E:** FreeRTOS task creation issues
|
||||
- Task created and ran successfully
|
||||
- First render completed normally
|
||||
- Ruled out
|
||||
|
||||
3. **Hypothesis F-G:** Main loop execution
|
||||
- Added loop counter logging to SD card
|
||||
- **Key finding:** Main loop never started logging
|
||||
- Setup() completed but loop() never executed meaningful work
|
||||
|
||||
4. **Hypothesis H-J:** Various timing and initialization issues
|
||||
- Tested different delays and initialization orders
|
||||
- No improvement
|
||||
|
||||
### Root Cause Discovery
|
||||
|
||||
The breakthrough came from analyzing the boot sequence:
|
||||
|
||||
1. `setup()` completes successfully
|
||||
2. `EpubReaderActivity::onEnter()` runs and calls `Serial.printf()` to log progress
|
||||
3. **Device hangs at Serial.printf() call**
|
||||
|
||||
On ESP32-C3 with USB CDC (USB serial), `Serial.printf()` blocks indefinitely waiting for the TX buffer to drain when USB is not connected. The default behavior expects a host to read the data.
|
||||
|
||||
### Evidence
|
||||
|
||||
- When USB connected: `Serial.printf()` returns immediately (data sent to host)
|
||||
- When USB disconnected: `Serial.printf()` blocks forever waiting for TX buffer space
|
||||
- The hang occurred specifically in `EpubReaderActivity.cpp` during progress logging
|
||||
|
||||
## Solution
|
||||
|
||||
### Primary Fix
|
||||
|
||||
Configure Serial to be non-blocking in `src/main.cpp`:
|
||||
|
||||
```cpp
|
||||
// Always initialize Serial but make it non-blocking
|
||||
Serial.begin(115200);
|
||||
Serial.setTxTimeoutMs(0); // Non-blocking TX - critical for USB disconnect handling
|
||||
```
|
||||
|
||||
`Serial.setTxTimeoutMs(0)` tells the ESP32 Arduino core to return immediately from Serial write operations if the buffer is full, rather than blocking.
|
||||
|
||||
### Secondary Protection (Belt and Suspenders)
|
||||
|
||||
Added `if (Serial)` guards to high-traffic Serial calls in `EpubReaderActivity.cpp`:
|
||||
|
||||
```cpp
|
||||
if (Serial) Serial.printf("[%lu] [ERS] Loaded progress...\n", millis());
|
||||
```
|
||||
|
||||
This provides an additional check before attempting to print, though it's not strictly necessary with the timeout set to 0.
|
||||
|
||||
## Files Changed
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `src/main.cpp` | Added `Serial.setTxTimeoutMs(0)` after `Serial.begin()` |
|
||||
| `src/main.cpp` | Added `if (Serial)` guard to auto-sleep log |
|
||||
| `src/main.cpp` | Added `if (Serial)` guard to max loop duration log |
|
||||
| `src/activities/reader/EpubReaderActivity.cpp` | Added 16 `if (Serial)` guards |
|
||||
|
||||
## Verification
|
||||
|
||||
After applying the fix:
|
||||
1. Device boots successfully when unplugged from USB
|
||||
2. Book pages render correctly
|
||||
3. Button presses register normally
|
||||
4. Sleep/wake cycle works
|
||||
5. No functionality lost when USB is connected
|
||||
|
||||
## Lessons Learned
|
||||
|
||||
1. **ESP32-C3 USB CDC behavior:** Serial output can block indefinitely without a connected host
|
||||
2. **Always set non-blocking:** `Serial.setTxTimeoutMs(0)` should be standard for battery-powered devices
|
||||
3. **Debug logging location matters:** When debugging hangs, SD card logging proved essential since Serial was the problem
|
||||
4. **Systematic hypothesis testing:** Ruled out many red herrings (mutex, task, rendering) before finding the true cause
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Why This Affects ESP32-C3 Specifically
|
||||
|
||||
The ESP32-C3 uses native USB CDC for serial communication (no external USB-UART chip). The Arduino core's default behavior is to wait for TX buffer space, which requires an active USB host connection.
|
||||
|
||||
### Alternative Approaches Considered
|
||||
|
||||
1. **Only initialize Serial when USB connected:** Partially implemented, but insufficient because USB can be disconnected after boot
|
||||
2. **Add `if (Serial)` guards everywhere:** Too invasive (400+ calls)
|
||||
3. **Disable Serial entirely:** Would lose debug output when USB connected
|
||||
|
||||
The chosen solution (`setTxTimeoutMs(0)`) provides the best balance: debug output works when USB is connected, device operates normally when disconnected.
|
||||
|
||||
## References
|
||||
|
||||
- ESP32 Arduino Core Serial documentation
|
||||
- ESP-IDF USB CDC documentation
|
||||
- FreeRTOS queue behavior (initial red herring investigation)
|
||||
132
claude_notes/usb-serial-blocking-fix-2026-01-28.md
Normal file
132
claude_notes/usb-serial-blocking-fix-2026-01-28.md
Normal file
@ -0,0 +1,132 @@
|
||||
# USB Serial Blocking Issue - Root Cause and Fix
|
||||
|
||||
**Date:** 2026-01-28
|
||||
**Issue:** Device blocking/hanging when USB is not connected at boot
|
||||
|
||||
---
|
||||
|
||||
## Problem Description
|
||||
|
||||
The device would hang or behave unpredictably when booted without USB connected. This was traced to improper Serial handling on ESP32-C3 with USB CDC.
|
||||
|
||||
## Root Cause Analysis
|
||||
|
||||
### Factor A: `checkForFlashCommand()` Called Without Serial Initialization
|
||||
|
||||
The most critical issue was in `checkForFlashCommand()`, which is called at the start of every `loop()` iteration:
|
||||
|
||||
```cpp
|
||||
void loop() {
|
||||
checkForFlashCommand(); // Called EVERY loop iteration
|
||||
// ...
|
||||
}
|
||||
|
||||
void checkForFlashCommand() {
|
||||
while (Serial.available()) { // Called even when Serial.begin() was never called!
|
||||
char c = Serial.read();
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When USB is not connected at boot, `Serial.begin()` is never called. Then in `loop()`, `checkForFlashCommand()` calls `Serial.available()` and `Serial.read()` on an uninitialized Serial object. On ESP32-C3 with USB CDC, this causes undefined behavior or blocking.
|
||||
|
||||
### Factor B: Removed `while (!Serial)` Wait Loop
|
||||
|
||||
The upstream 0.16.0 code included a 3-second wait loop after `Serial.begin()`:
|
||||
|
||||
```cpp
|
||||
if (isUsbConnected()) {
|
||||
Serial.begin(115200);
|
||||
unsigned long start = millis();
|
||||
while (!Serial && (millis() - start) < 3000) {
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This wait loop was removed in an earlier attempt to fix boot delays, but it may be necessary for proper USB CDC initialization.
|
||||
|
||||
### Factor C: `Serial.setTxTimeoutMs(0)` Added Too Early
|
||||
|
||||
`Serial.setTxTimeoutMs(0)` was added immediately after `Serial.begin()` to make TX non-blocking. However, calling this before the Serial connection is fully established may interfere with USB CDC initialization.
|
||||
|
||||
---
|
||||
|
||||
## The Fix
|
||||
|
||||
### 1. Guard `checkForFlashCommand()` with Serial Check
|
||||
|
||||
```cpp
|
||||
void checkForFlashCommand() {
|
||||
if (!Serial) return; // Early exit if Serial not initialized
|
||||
while (Serial.available()) {
|
||||
// ... rest unchanged
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Restore Upstream Serial Initialization Pattern
|
||||
|
||||
```cpp
|
||||
void setup() {
|
||||
t1 = millis();
|
||||
|
||||
// Only start serial if USB connected
|
||||
pinMode(UART0_RXD, INPUT);
|
||||
if (isUsbConnected()) {
|
||||
Serial.begin(115200);
|
||||
// Wait up to 3 seconds for Serial to be ready to catch early logs
|
||||
unsigned long start = millis();
|
||||
while (!Serial && (millis() - start) < 3000) {
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
// ... rest of setup
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Remove `Serial.setTxTimeoutMs(0)`
|
||||
|
||||
This call was removed entirely as it's not present in upstream and may cause issues.
|
||||
|
||||
### 4. Remove Unnecessary `if (Serial)` Guards
|
||||
|
||||
The 15 `if (Serial)` guards added to `EpubReaderActivity.cpp` were removed. `Serial.printf()` is safe to call when Serial isn't initialized (it simply returns 0), so guards around output calls are unnecessary.
|
||||
|
||||
**Key distinction:**
|
||||
- `Serial.printf()` / `Serial.println()` - Safe without guards (no-op when not initialized)
|
||||
- `Serial.available()` / `Serial.read()` - **MUST** be guarded (undefined behavior when not initialized)
|
||||
|
||||
---
|
||||
|
||||
## Files Changed
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `src/main.cpp` | Removed `Serial.setTxTimeoutMs(0)`, restored `while (!Serial)` wait, added guard to `checkForFlashCommand()` |
|
||||
| `src/activities/reader/EpubReaderActivity.cpp` | Removed all 15 `if (Serial)` guards |
|
||||
|
||||
---
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
After applying fixes, verify:
|
||||
|
||||
1. ✅ Boot with USB connected, serial monitor open - should work
|
||||
2. ✅ Boot with USB connected, NO serial monitor - should work (3s delay then continue)
|
||||
3. ✅ Boot without USB - should work immediately (no blocking)
|
||||
4. ✅ Sleep without USB, plug in USB during sleep, wake - should work
|
||||
5. ✅ Sleep with USB, unplug during sleep, wake - should work
|
||||
|
||||
---
|
||||
|
||||
## Lessons Learned
|
||||
|
||||
1. **Always guard Serial input operations**: `Serial.available()` and `Serial.read()` must be guarded with `if (Serial)` or `if (!Serial) return` when Serial initialization is conditional.
|
||||
|
||||
2. **Serial output is safe without guards**: `Serial.printf()` and similar output functions are safe to call even when Serial is not initialized - they simply return 0.
|
||||
|
||||
3. **Don't remove initialization waits without understanding why they exist**: The `while (!Serial)` wait loop exists for proper USB CDC initialization and shouldn't be removed without careful testing.
|
||||
|
||||
4. **Upstream patterns exist for a reason**: When diverging from upstream behavior, especially around low-level hardware initialization, be extra cautious and test thoroughly.
|
||||
BIN
dict-en-en.zip
Normal file
BIN
dict-en-en.zip
Normal file
Binary file not shown.
422
docs/branch-comparison-summary.md
Normal file
422
docs/branch-comparison-summary.md
Normal file
@ -0,0 +1,422 @@
|
||||
# Branch Comparison Summary: crosspoint-ef vs 0.16.0
|
||||
|
||||
This document provides a comprehensive comparison between the `crosspoint-ef` branch and the upstream `0.16.0` release for merge planning and implementation decisions.
|
||||
|
||||
## Branch History
|
||||
|
||||
| Branch | Base | Commits Since Base | Status |
|
||||
|--------|------|-------------------|--------|
|
||||
| `crosspoint-ef` | 0.15.0 | 90+ | Active development |
|
||||
| `0.16.0` | 0.15.0 | 30 | Released |
|
||||
|
||||
Both branches diverged from `0.15.0` at commit `3ce11f14`.
|
||||
|
||||
---
|
||||
|
||||
## Feature Comparison Matrix
|
||||
|
||||
### Major Features
|
||||
|
||||
| Feature | crosspoint-ef | 0.16.0 | Notes |
|
||||
|---------|:-------------:|:------:|-------|
|
||||
| Dictionary Support | Yes | No | StarDict format with word selection |
|
||||
| Bookmark System | Yes | No | Per-book bookmarks with visual indicator |
|
||||
| Quick Menu | Yes | No | Power button quick access |
|
||||
| Library Search | Yes | No | Character picker with weighted search |
|
||||
| CSS Parsing | Yes | No | Element, class, inline styles |
|
||||
| Inline Images (PNG/JPEG) | Yes | No | With caching and dithering |
|
||||
| Custom Fonts | Yes | No | Atkinson Hyperlegible, Fern Micro |
|
||||
| Enhanced Web Server | Yes | Partial | File ops, MD5 API, mDNS |
|
||||
| Companion App API | Yes | No | Deep links, WebSocket uploads |
|
||||
| Reading Lists | Yes | No | With pinning support |
|
||||
| Tab Bar Enhancements | Yes | No | Scrolling, overflow indicators |
|
||||
| High Contrast Mode | Yes | No | System-wide |
|
||||
| Bezel Compensation | Yes | No | Edge defect compensation |
|
||||
| Sleep Screen Edge Detection | Yes | No | Dominant color fill |
|
||||
| Recents Improvements | Yes | No | Badges, removal, clearing |
|
||||
| Progress Bar Status Bar | Yes | Yes | Same feature |
|
||||
| Spanish Hyphenation | No | Yes | Missing in crosspoint-ef |
|
||||
| XTC/XTCH Author Extraction | No | Yes | Missing in crosspoint-ef |
|
||||
| OTA Rework | No | Yes | Different implementation |
|
||||
| KOReader MD5 Binary Matching | No | Yes | Missing in crosspoint-ef |
|
||||
| Relative Position on Settings Change | No | Yes | Missing in crosspoint-ef |
|
||||
| Multi-line Keyboard Entry | No | Yes | Missing in crosspoint-ef |
|
||||
| Italics on Image Alt | No | Yes | Missing in crosspoint-ef |
|
||||
| Page Turn on Button Press (UX) | No | Yes | When chapter skip disabled |
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
| Fix | crosspoint-ef | 0.16.0 | Notes |
|
||||
|-----|:-------------:|:------:|-------|
|
||||
| Large EPUB indexing O(n²)→O(n) | Yes | Yes | Same fix |
|
||||
| Settings validation on read | Yes | Yes | Same fix |
|
||||
| Line break fixes | Yes | Yes | Similar fixes |
|
||||
| Rotate origin in drawImage | Yes | Yes | Same fix |
|
||||
| Short-press power wakeup | Yes | Yes | Same fix |
|
||||
| TXT books in recent tab | Yes | Yes | Same fix |
|
||||
| B&W filters for covers | Yes | Yes | Same fix |
|
||||
| Cover fit artifacts | Yes | Yes | Same fix |
|
||||
| Grayscale state corruption | Yes | No | Unique to crosspoint-ef |
|
||||
| Memory graceful degradation | Yes | No | Unique to crosspoint-ef |
|
||||
| Chapter Selection UI (KOReader) | No | Yes | Missing in crosspoint-ef |
|
||||
| Front layout in mapLabels() | No | Yes | Missing in crosspoint-ef |
|
||||
|
||||
---
|
||||
|
||||
## Files Changed Summary
|
||||
|
||||
### crosspoint-ef Unique Files (New)
|
||||
|
||||
| Category | Files |
|
||||
|----------|-------|
|
||||
| Dictionary | `src/activities/dictionary/` (8 files), `lib/StarDict/` (4 files) |
|
||||
| Bookmarks | `src/BookmarkStore.cpp/.h`, `src/activities/home/BookmarkListActivity.cpp/.h` |
|
||||
| Quick Menu | `src/activities/util/QuickMenuActivity.cpp/.h` |
|
||||
| CSS | `lib/Epub/Epub/css/` (3 files) |
|
||||
| Images | `lib/Epub/Epub/blocks/ImageBlock.cpp/.h`, `lib/Epub/Epub/converters/` (6 files) |
|
||||
| Custom Fonts | `src/customFonts.cpp`, `src/fontIds.h`, `lib/EpdFont/builtinFonts/custom/` (50+ files) |
|
||||
| Utils | `src/util/Md5Utils.cpp/.h`, `src/util/StringUtils.cpp/.h` |
|
||||
| Lists | `src/BookListStore.cpp/.h` |
|
||||
| Docs | `docs/webserver-api-reference.md`, `docs/companion-app-deep-link-API.md`, `docs/troubleshooting.md` |
|
||||
|
||||
### crosspoint-ef Modified Files (Significant Changes)
|
||||
|
||||
| File | Changes |
|
||||
|------|---------|
|
||||
| `src/network/CrossPointWebServer.cpp` | +1083 lines (file ops, API, WebSocket) |
|
||||
| `src/activities/home/MyLibraryActivity.cpp` | +700 lines (tabs, search, badges) |
|
||||
| `src/main.cpp` | +255 lines (feature integration) |
|
||||
| `lib/GfxRenderer/GfxRenderer.cpp` | +439 lines (contrast, bezel) |
|
||||
| `lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp` | +596 lines (CSS integration) |
|
||||
| `src/CrossPointSettings.cpp/.h` | New settings fields |
|
||||
| `src/activities/boot_sleep/SleepActivity.cpp` | Edge detection, caching |
|
||||
| `src/RecentBooksStore.cpp` | Badges, removal, metadata |
|
||||
| `src/ScreenComponents.cpp` | Tab bar enhancements |
|
||||
|
||||
### 0.16.0 Unique Files/Changes
|
||||
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| `lib/Epub/Epub/hyphenation/generated/hyph-es.trie.h` | Spanish hyphenation (removed in ef) |
|
||||
| `lib/KOReaderSync/` | KOReader credential handling (removed in ef) |
|
||||
| `src/network/OtaUpdater.cpp` | OTA rework |
|
||||
|
||||
---
|
||||
|
||||
## Merge Strategy Recommendations
|
||||
|
||||
### Phase 1: Cherry-pick 0.16.0 Fixes into crosspoint-ef
|
||||
|
||||
**Low Risk - Recommended First:**
|
||||
|
||||
1. **Spanish hyphenation support** (#558)
|
||||
- Add `hyph-es.trie.h` back
|
||||
- Update `LanguageRegistry.cpp`
|
||||
|
||||
2. **Render keyboard entry over multiple lines** (#567)
|
||||
- Update `KeyboardEntryActivity.cpp`
|
||||
|
||||
3. **Correctly render italics on image alt** (#569)
|
||||
- Minimal change to text rendering
|
||||
|
||||
4. **Page turning on button pressed** (#451)
|
||||
- UX improvement when chapter skip disabled
|
||||
|
||||
5. **Missing front layout in mapLabels()** (#564)
|
||||
- Bug fix for button mapping
|
||||
|
||||
**Medium Risk:**
|
||||
|
||||
6. **KOReader document MD5 binary matching** (#529)
|
||||
- May conflict with MD5Utils changes
|
||||
|
||||
7. **Chapter Selection UI bugs** (#501)
|
||||
- Review for conflicts with tab bar changes
|
||||
|
||||
8. **Relative position on settings change** (#486)
|
||||
- Reader state management change
|
||||
|
||||
**Higher Risk:**
|
||||
|
||||
9. **OTA feature rework** (#509)
|
||||
- Compare implementations, may need reconciliation
|
||||
- crosspoint-ef has different OTA changes
|
||||
|
||||
10. **Extract author from XTC/XTCH** (#563)
|
||||
- XTC format was removed in crosspoint-ef
|
||||
- Evaluate if needed
|
||||
|
||||
### Phase 2: Potential Upstream Contributions from crosspoint-ef
|
||||
|
||||
**High Value, Moderate Complexity:**
|
||||
|
||||
1. **Dictionary Support**
|
||||
- Self-contained feature
|
||||
- New files, minimal integration points
|
||||
- Requires shipping dictionary data
|
||||
|
||||
2. **Bookmark System**
|
||||
- Clean implementation
|
||||
- New files with reader integration
|
||||
|
||||
3. **Quick Menu**
|
||||
- Simple overlay feature
|
||||
- Depends on bookmark and dictionary
|
||||
|
||||
4. **CSS Parsing**
|
||||
- Significant EPUB improvement
|
||||
- Well-isolated in `lib/Epub/Epub/css/`
|
||||
|
||||
**High Value, Higher Complexity:**
|
||||
|
||||
5. **Inline Image Support**
|
||||
- Major EPUB enhancement
|
||||
- Multiple new converters
|
||||
- Memory management considerations
|
||||
|
||||
6. **Library Search**
|
||||
- Integrated into MyLibraryActivity
|
||||
- Tab bar changes included
|
||||
|
||||
7. **Enhanced Web Server**
|
||||
- Large changes to CrossPointWebServer
|
||||
- New API endpoints
|
||||
- WebSocket uploads
|
||||
|
||||
**Medium Value:**
|
||||
|
||||
8. **Custom Fonts**
|
||||
- Large binary additions (font headers)
|
||||
- Clean integration
|
||||
|
||||
9. **Display Enhancements**
|
||||
- High contrast, bezel compensation
|
||||
- Settings additions
|
||||
|
||||
10. **Reading Lists**
|
||||
- New feature with web API
|
||||
|
||||
---
|
||||
|
||||
## Potential Conflicts
|
||||
|
||||
### High Conflict Risk
|
||||
|
||||
| Area | crosspoint-ef | 0.16.0 | Resolution |
|
||||
|------|---------------|--------|------------|
|
||||
| `MyLibraryActivity.cpp` | Major restructure | Minor fixes | Manual merge required |
|
||||
| `CrossPointWebServer.cpp` | Extensive additions | Minimal changes | crosspoint-ef likely compatible |
|
||||
| `CrossPointSettings.h` | Many new fields | Few changes | Additive, low conflict |
|
||||
| `main.cpp` | Feature integration | Minor changes | Review integration points |
|
||||
| `OtaUpdater.cpp` | Modified | Reworked (#509) | Compare implementations |
|
||||
|
||||
### Low Conflict Risk
|
||||
|
||||
| Area | Notes |
|
||||
|------|-------|
|
||||
| Dictionary files | All new, no conflicts |
|
||||
| Bookmark files | All new, no conflicts |
|
||||
| CSS parser files | All new, no conflicts |
|
||||
| Image converter files | All new, no conflicts |
|
||||
| Custom font files | All new, no conflicts |
|
||||
| StarDict library | All new, no conflicts |
|
||||
|
||||
---
|
||||
|
||||
## Testing Considerations
|
||||
|
||||
### Regression Testing Required
|
||||
|
||||
After any merge:
|
||||
|
||||
1. **EPUB Reading**
|
||||
- Page navigation
|
||||
- Chapter selection
|
||||
- CSS styling
|
||||
- Image rendering
|
||||
- Bookmark indicators
|
||||
|
||||
2. **Library Functions**
|
||||
- Tab navigation
|
||||
- Search functionality
|
||||
- Recent books display
|
||||
- List management
|
||||
|
||||
3. **Dictionary**
|
||||
- Word selection
|
||||
- Lookup accuracy
|
||||
- Definition display
|
||||
|
||||
4. **Web Server**
|
||||
- File upload/download
|
||||
- API endpoints
|
||||
- WebSocket uploads
|
||||
- mDNS discovery
|
||||
|
||||
5. **Settings**
|
||||
- All new settings persist correctly
|
||||
- Settings migration from older versions
|
||||
|
||||
6. **Display**
|
||||
- High contrast mode
|
||||
- Bezel compensation (all orientations)
|
||||
- Sleep screen variations
|
||||
|
||||
### Memory Testing
|
||||
|
||||
crosspoint-ef includes memory optimization fixes. After merge:
|
||||
|
||||
1. Test with large EPUBs (2000+ chapters)
|
||||
2. Test opening multiple books in sequence
|
||||
3. Test anti-aliasing under memory pressure
|
||||
4. Monitor for ghosting/artifacts
|
||||
|
||||
---
|
||||
|
||||
## Priority Recommendations
|
||||
|
||||
### Immediate (For crosspoint-ef Stability)
|
||||
|
||||
1. Cherry-pick Spanish hyphenation (#558)
|
||||
2. Cherry-pick multi-line keyboard entry (#567)
|
||||
3. Cherry-pick italics on image alt (#569)
|
||||
4. Cherry-pick front layout fix (#564)
|
||||
|
||||
### Short-term (Feature Completeness)
|
||||
|
||||
5. Evaluate OTA rework (#509) - compare implementations
|
||||
6. Cherry-pick page turn UX (#451)
|
||||
7. Cherry-pick relative position fix (#486)
|
||||
|
||||
### Long-term (Upstream Contribution)
|
||||
|
||||
8. Prepare dictionary feature as PR
|
||||
9. Prepare bookmark system as PR
|
||||
10. Prepare CSS parsing as PR
|
||||
11. Evaluate inline image support for upstream
|
||||
|
||||
---
|
||||
|
||||
## File Inventory for Merge
|
||||
|
||||
### Files to Add to 0.16.0 Base (for upstream contribution)
|
||||
|
||||
```
|
||||
src/activities/dictionary/
|
||||
DictionaryMargins.h
|
||||
DictionaryMenuActivity.cpp
|
||||
DictionaryMenuActivity.h
|
||||
DictionaryResultActivity.cpp
|
||||
DictionaryResultActivity.h
|
||||
DictionarySearchActivity.cpp
|
||||
DictionarySearchActivity.h
|
||||
EpubWordSelectionActivity.cpp
|
||||
EpubWordSelectionActivity.h
|
||||
|
||||
src/activities/util/
|
||||
QuickMenuActivity.cpp
|
||||
QuickMenuActivity.h
|
||||
|
||||
src/activities/home/
|
||||
BookmarkListActivity.cpp
|
||||
BookmarkListActivity.h
|
||||
|
||||
src/
|
||||
BookmarkStore.cpp
|
||||
BookmarkStore.h
|
||||
BookListStore.cpp
|
||||
BookListStore.h
|
||||
customFonts.cpp
|
||||
fontIds.h
|
||||
BadgeConfig.h
|
||||
|
||||
src/util/
|
||||
Md5Utils.cpp
|
||||
Md5Utils.h
|
||||
StringUtils.cpp
|
||||
StringUtils.h
|
||||
|
||||
src/images/
|
||||
LockIcon.h
|
||||
|
||||
lib/StarDict/
|
||||
StarDict.cpp
|
||||
StarDict.h
|
||||
DictHtmlParser.cpp
|
||||
DictHtmlParser.h
|
||||
DictPrefixIndex.generated.h
|
||||
|
||||
lib/Epub/Epub/css/
|
||||
CssParser.cpp
|
||||
CssParser.h
|
||||
CssStyle.h
|
||||
|
||||
lib/Epub/Epub/blocks/
|
||||
ImageBlock.cpp
|
||||
ImageBlock.h
|
||||
BlockStyle.h
|
||||
|
||||
lib/Epub/Epub/converters/
|
||||
FramebufferWriter.cpp
|
||||
FramebufferWriter.h
|
||||
ImageDecoderFactory.cpp
|
||||
ImageDecoderFactory.h
|
||||
ImageToFramebufferDecoder.cpp
|
||||
ImageToFramebufferDecoder.h
|
||||
JpegToFramebufferConverter.cpp
|
||||
JpegToFramebufferConverter.h
|
||||
PngToFramebufferConverter.cpp
|
||||
PngToFramebufferConverter.h
|
||||
|
||||
lib/EpdFont/builtinFonts/custom/
|
||||
[All font header files]
|
||||
|
||||
docs/
|
||||
webserver-api-reference.md
|
||||
companion-app-deep-link-API.md
|
||||
troubleshooting.md
|
||||
crosspoint-ef-features.md
|
||||
crosspoint-ef-user-guide.md
|
||||
```
|
||||
|
||||
### Files to Merge Carefully
|
||||
|
||||
```
|
||||
src/main.cpp
|
||||
src/CrossPointSettings.cpp
|
||||
src/CrossPointSettings.h
|
||||
src/network/CrossPointWebServer.cpp
|
||||
src/network/CrossPointWebServer.h
|
||||
src/network/OtaUpdater.cpp
|
||||
src/network/OtaUpdater.h
|
||||
src/activities/home/MyLibraryActivity.cpp
|
||||
src/activities/home/MyLibraryActivity.h
|
||||
src/activities/reader/EpubReaderActivity.cpp
|
||||
src/activities/settings/SettingsActivity.cpp
|
||||
src/activities/settings/CategorySettingsActivity.cpp
|
||||
src/ScreenComponents.cpp
|
||||
src/ScreenComponents.h
|
||||
src/RecentBooksStore.cpp
|
||||
src/RecentBooksStore.h
|
||||
lib/GfxRenderer/GfxRenderer.cpp
|
||||
lib/GfxRenderer/GfxRenderer.h
|
||||
lib/GfxRenderer/BitmapHelpers.cpp
|
||||
lib/GfxRenderer/BitmapHelpers.h
|
||||
lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp
|
||||
lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h
|
||||
lib/Epub/Epub/Section.cpp
|
||||
lib/Epub/Epub/Section.h
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
The `crosspoint-ef` branch represents a significant enhancement over the `0.15.0` baseline with 14+ major features. Most features are cleanly isolated in new files, making selective upstream contribution feasible.
|
||||
|
||||
**Recommended approach:**
|
||||
1. First, bring crosspoint-ef up to date with 0.16.0 bug fixes
|
||||
2. Then, evaluate individual features for upstream PR submission
|
||||
3. Prioritize dictionary, bookmarks, and CSS parsing as highest-value contributions
|
||||
|
||||
The grayscale state corruption fix in crosspoint-ef should also be submitted upstream as a critical bug fix, as it prevents display artifacts under memory pressure.
|
||||
309
docs/companion-app-deep-link-API.md
Normal file
309
docs/companion-app-deep-link-API.md
Normal file
@ -0,0 +1,309 @@
|
||||
# CrossPoint Companion Deep Link API
|
||||
|
||||
This document describes the deep link functionality that allows the CrossPoint Companion Android app to be launched from QR codes displayed on CrossPoint e-reader devices.
|
||||
|
||||
## Overview
|
||||
|
||||
The CrossPoint firmware can generate QR codes containing deep link URLs. When scanned with a mobile device, these URLs launch the companion app directly to a specific tab and optionally auto-connect to the device.
|
||||
|
||||
## URL Scheme
|
||||
|
||||
```
|
||||
crosspoint://<path>?<query_parameters>
|
||||
```
|
||||
|
||||
### Components
|
||||
|
||||
| Component | Description |
|
||||
|-----------|-------------|
|
||||
| `crosspoint://` | Custom URL scheme registered by the app |
|
||||
| `<path>` | Target tab in the app (see [Path Mapping](#path-mapping)) |
|
||||
| `<query_parameters>` | Optional device connection parameters |
|
||||
|
||||
## Path Mapping
|
||||
|
||||
The URL path determines which tab the app navigates to:
|
||||
|
||||
| Path | App Tab | Description |
|
||||
|------|---------|-------------|
|
||||
| `files` | Device | File browser for device storage |
|
||||
| `library` | Library | Local book library |
|
||||
| `lists` | Lists | Reading lists management |
|
||||
| `settings` | Settings | App settings |
|
||||
|
||||
**Note:** Unknown paths default to the Library tab.
|
||||
|
||||
## Query Parameters
|
||||
|
||||
Query parameters provide device connection information for automatic connection:
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|-----------|------|---------|-------------|
|
||||
| `host` | string | *(required for auto-connect)* | IP address or hostname of the device |
|
||||
| `port` | integer | `80` | HTTP API port |
|
||||
| `wsPort` | integer | `81` | WebSocket port for file uploads |
|
||||
|
||||
## URL Examples
|
||||
|
||||
### Basic Navigation (No Auto-Connect)
|
||||
|
||||
Navigate to a specific tab without connecting to a device:
|
||||
|
||||
```
|
||||
crosspoint://files
|
||||
crosspoint://library
|
||||
crosspoint://lists
|
||||
crosspoint://settings
|
||||
```
|
||||
|
||||
### Auto-Connect to Device
|
||||
|
||||
Navigate to Device tab and auto-connect:
|
||||
|
||||
```
|
||||
crosspoint://files?host=192.168.1.100
|
||||
crosspoint://files?host=192.168.1.100&port=80&wsPort=81
|
||||
```
|
||||
|
||||
### Custom Ports
|
||||
|
||||
Connect to a device with non-default ports:
|
||||
|
||||
```
|
||||
crosspoint://files?host=192.168.1.100&port=8080&wsPort=8081
|
||||
```
|
||||
|
||||
### Hostname Instead of IP
|
||||
|
||||
```
|
||||
crosspoint://files?host=crosspoint.local&port=80&wsPort=81
|
||||
```
|
||||
|
||||
## Firmware Implementation
|
||||
|
||||
### QR Code Generation
|
||||
|
||||
The CrossPoint firmware should generate QR codes containing the deep link URL. Example format:
|
||||
|
||||
```
|
||||
crosspoint://files?host=<device_ip>&port=<http_port>&wsPort=<ws_port>
|
||||
```
|
||||
|
||||
Where:
|
||||
- `<device_ip>` is the device's current IP address (e.g., from WiFi connection)
|
||||
- `<http_port>` is the HTTP API port (default: 80)
|
||||
- `<ws_port>` is the WebSocket port (default: 81)
|
||||
|
||||
### Example Firmware Code (C++)
|
||||
|
||||
```cpp
|
||||
String generateDeepLinkUrl(const char* path = "files") {
|
||||
String url = "crosspoint://";
|
||||
url += path;
|
||||
url += "?host=";
|
||||
url += WiFi.localIP().toString();
|
||||
url += "&port=";
|
||||
url += String(HTTP_PORT); // e.g., 80
|
||||
url += "&wsPort=";
|
||||
url += String(WS_PORT); // e.g., 81
|
||||
return url;
|
||||
}
|
||||
|
||||
// Generate QR code with:
|
||||
// String url = generateDeepLinkUrl("files");
|
||||
// displayQRCode(url);
|
||||
```
|
||||
|
||||
## App Behavior
|
||||
|
||||
### Launch Scenarios
|
||||
|
||||
#### 1. App Not Running
|
||||
|
||||
When the app is launched via deep link:
|
||||
1. App starts and parses the deep link URL
|
||||
2. Navigates to the target tab
|
||||
3. If device connection info is present and target is "files":
|
||||
- Checks for existing device with matching IP
|
||||
- If found: uses existing device (preserving user's custom name)
|
||||
- If not found: creates temporary connection
|
||||
- Attempts to connect automatically
|
||||
|
||||
#### 2. App Already Running
|
||||
|
||||
When a deep link is received while the app is open:
|
||||
1. `onNewIntent` receives the new URL
|
||||
2. Navigates to the target tab
|
||||
3. Handles device connection (same as above)
|
||||
|
||||
### Device Matching Logic
|
||||
|
||||
When connecting via deep link:
|
||||
|
||||
```
|
||||
1. Look up device by IP address in database
|
||||
2. If device exists:
|
||||
a. Check if ports match
|
||||
b. If ports differ, update the stored device with new ports
|
||||
c. Connect using the existing device (preserves custom name)
|
||||
3. If device doesn't exist:
|
||||
a. Create temporary Device object (not saved to database)
|
||||
b. Connect using temporary device
|
||||
c. Display as "CrossPoint (<ip>)"
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
| Scenario | Behavior |
|
||||
|----------|----------|
|
||||
| Malformed URL | App opens to Library tab (default) |
|
||||
| Unknown path | App opens to Library tab with warning logged |
|
||||
| Invalid host format | Navigation succeeds, no auto-connect |
|
||||
| Invalid port values | Default ports used (80, 81) |
|
||||
| Connection failure | Error message displayed, user can retry |
|
||||
| Device unreachable | Error message with device IP shown |
|
||||
|
||||
## Android Implementation Details
|
||||
|
||||
### Intent Filter (AndroidManifest.xml)
|
||||
|
||||
```xml
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="crosspoint" />
|
||||
</intent-filter>
|
||||
```
|
||||
|
||||
### Key Classes
|
||||
|
||||
| Class | Purpose |
|
||||
|-------|---------|
|
||||
| `DeepLinkParser` | Parses URI into `DeepLinkData` |
|
||||
| `DeepLinkData` | Data class holding parsed deep link info |
|
||||
| `DeviceConnectionInfo` | Data class for host/port/wsPort |
|
||||
| `MainActivity` | Handles incoming intents |
|
||||
| `CrossPointApp` | Routes navigation based on deep link |
|
||||
| `DeviceBrowserViewModel` | Handles `connectFromDeepLink()` |
|
||||
|
||||
### Data Flow
|
||||
|
||||
```
|
||||
QR Code Scan
|
||||
│
|
||||
▼
|
||||
Android Intent (ACTION_VIEW)
|
||||
│
|
||||
▼
|
||||
MainActivity.onCreate() / onNewIntent()
|
||||
│
|
||||
▼
|
||||
DeepLinkParser.parse(uri)
|
||||
│
|
||||
▼
|
||||
DeepLinkData { targetTab, deviceConnection? }
|
||||
│
|
||||
▼
|
||||
CrossPointApp (LaunchedEffect)
|
||||
│
|
||||
├─► Navigate to targetTab
|
||||
│
|
||||
└─► If targetTab == Device && deviceConnection != null
|
||||
│
|
||||
▼
|
||||
DeviceBrowserScreen
|
||||
│
|
||||
▼
|
||||
DeviceBrowserViewModel.connectFromDeepLink()
|
||||
│
|
||||
├─► Check existing device by IP
|
||||
├─► Update ports if needed
|
||||
└─► Connect and load files
|
||||
```
|
||||
|
||||
## Validation Rules
|
||||
|
||||
### Host Validation
|
||||
|
||||
Valid hosts:
|
||||
- IPv4 addresses: `192.168.1.100`, `10.0.0.1`
|
||||
- Hostnames: `crosspoint.local`, `my-device`
|
||||
|
||||
Invalid hosts (rejected):
|
||||
- Empty strings
|
||||
- Malformed IPs: `192.168.1.256`, `192.168.1`
|
||||
- IPs with invalid octets
|
||||
|
||||
### Port Validation
|
||||
|
||||
- Valid range: 1-65535
|
||||
- Out-of-range values default to 80 (HTTP) or 81 (WebSocket)
|
||||
- Non-numeric values default to standard ports
|
||||
|
||||
## Testing
|
||||
|
||||
### Manual Testing with ADB
|
||||
|
||||
Test deep links without a QR code using ADB:
|
||||
|
||||
```bash
|
||||
# Basic navigation
|
||||
adb shell am start -a android.intent.action.VIEW -d "crosspoint://files"
|
||||
adb shell am start -a android.intent.action.VIEW -d "crosspoint://library"
|
||||
|
||||
# With device connection
|
||||
adb shell am start -a android.intent.action.VIEW -d "crosspoint://files?host=192.168.1.100"
|
||||
adb shell am start -a android.intent.action.VIEW -d "crosspoint://files?host=192.168.1.100&port=80&wsPort=81"
|
||||
|
||||
# Test while app is running (onNewIntent)
|
||||
adb shell am start -a android.intent.action.VIEW -d "crosspoint://settings"
|
||||
```
|
||||
|
||||
### Test Cases
|
||||
|
||||
1. **Valid deep link with connection info**
|
||||
- URL: `crosspoint://files?host=192.168.1.100&port=80&wsPort=81`
|
||||
- Expected: Opens Device tab, auto-connects to device
|
||||
|
||||
2. **Valid deep link without connection info**
|
||||
- URL: `crosspoint://files`
|
||||
- Expected: Opens Device tab, shows device selection
|
||||
|
||||
3. **Unknown path**
|
||||
- URL: `crosspoint://unknown`
|
||||
- Expected: Opens Library tab (default)
|
||||
|
||||
4. **Missing host parameter**
|
||||
- URL: `crosspoint://files?port=80`
|
||||
- Expected: Opens Device tab, no auto-connect
|
||||
|
||||
5. **Invalid host format**
|
||||
- URL: `crosspoint://files?host=invalid..host`
|
||||
- Expected: Opens Device tab, no auto-connect
|
||||
|
||||
6. **Device already exists in database**
|
||||
- Precondition: Device with IP 192.168.1.100 saved as "My Reader"
|
||||
- URL: `crosspoint://files?host=192.168.1.100`
|
||||
- Expected: Connects using "My Reader" name
|
||||
|
||||
7. **Existing device with different ports**
|
||||
- Precondition: Device saved with port=80, wsPort=81
|
||||
- URL: `crosspoint://files?host=192.168.1.100&port=8080&wsPort=8081`
|
||||
- Expected: Updates device ports, then connects
|
||||
|
||||
## Security Considerations
|
||||
|
||||
1. **Local Network Only**: Deep links should only contain local network addresses. The app does not validate this, but firmware should only generate URLs with local IPs.
|
||||
|
||||
2. **No Authentication**: The deep link does not include authentication. Device security relies on network-level access control.
|
||||
|
||||
3. **Temporary Devices**: Devices created from deep links (when no matching device exists) are not persisted, preventing automatic accumulation of device entries.
|
||||
|
||||
4. **No Sensitive Data**: Deep link URLs should not contain sensitive information as QR codes can be photographed.
|
||||
|
||||
## Changelog
|
||||
|
||||
| Version | Changes |
|
||||
|---------|---------|
|
||||
| 1.0.0 | Initial deep link support with `crosspoint://` scheme |
|
||||
603
docs/crosspoint-ef-features.md
Normal file
603
docs/crosspoint-ef-features.md
Normal file
@ -0,0 +1,603 @@
|
||||
# CrossPoint-EF Branch Features
|
||||
|
||||
This document describes the features and enhancements unique to the `crosspoint-ef` branch, which diverged from CrossPoint Reader at version `0.15.0`.
|
||||
|
||||
## Overview
|
||||
|
||||
The `crosspoint-ef` branch introduces significant new functionality including:
|
||||
|
||||
- **Dictionary Support** - Offline StarDict dictionary with word selection from reader
|
||||
- **Bookmark System** - Per-book bookmarks with visual indicators and management
|
||||
- **Quick Menu** - Fast access to common actions via power button
|
||||
- **Library Search** - Search across all books by title, author, or filename
|
||||
- **CSS Support** - Parse and apply CSS styles from EPUB files
|
||||
- **Inline Images** - PNG and Baseline JPEG image rendering within EPUBs
|
||||
- **Custom Fonts** - Atkinson Hyperlegible Next and Fern Micro accessibility fonts
|
||||
- **Enhanced Web Server** - File management, companion app API, mDNS discovery
|
||||
- **Reading Lists** - Create, manage, and pin custom book lists
|
||||
- **Display Enhancements** - High contrast mode, bezel compensation, sleep screen improvements
|
||||
|
||||
---
|
||||
|
||||
## Major Features
|
||||
|
||||
### 1. Dictionary Support
|
||||
|
||||
Full offline dictionary lookup using the StarDict format with fast prefix-indexed search.
|
||||
|
||||
**Features:**
|
||||
- Word selection directly from EPUB pages
|
||||
- Manual word entry via on-screen keyboard
|
||||
- Rich HTML formatting in definitions (bold, italic, lists)
|
||||
- Multi-page definitions with pagination
|
||||
- Synonym support
|
||||
- Case-insensitive search with prefix optimization
|
||||
|
||||
**Access Methods:**
|
||||
- **Quick Menu** → Dictionary
|
||||
- **Power Button** (when configured to `Dictionary` action)
|
||||
|
||||
**Dictionary Format:**
|
||||
- StarDict format with dictzip compression
|
||||
- Files located at `/dictionaries/dict-data` on SD card:
|
||||
- `dict-data.ifo` - Metadata
|
||||
- `dict-data.idx` - Word index
|
||||
- `dict-data.dict.dz` - Compressed definitions
|
||||
- `dict-data.syn` - Synonyms (optional)
|
||||
|
||||
**Technical Implementation:**
|
||||
- Files: `src/activities/dictionary/`, `lib/StarDict/`
|
||||
- Prefix jump table for near-instant lookups
|
||||
- On-demand chunk decompression using miniz
|
||||
- HTML definition parsing with entity decoding
|
||||
|
||||
---
|
||||
|
||||
### 2. Bookmark System
|
||||
|
||||
Per-book bookmark storage with visual indicators and dedicated management interface.
|
||||
|
||||
**Features:**
|
||||
- Add/remove bookmarks from current page
|
||||
- Visual folded-corner indicator on bookmarked pages
|
||||
- Bookmarks tab in library showing all books with bookmarks
|
||||
- Long-press to delete bookmarks
|
||||
- Auto-generated bookmark names ("Chapter Title - Page X")
|
||||
- Maximum 100 bookmarks per book
|
||||
|
||||
**Storage:**
|
||||
- Binary file per book: `/.crosspoint/{epub_|txt_}<hash>/bookmarks.bin`
|
||||
- Stores: name, spine index, content offset, page number, timestamp
|
||||
|
||||
**Technical Implementation:**
|
||||
- Files: `src/BookmarkStore.cpp/.h`, `src/activities/home/BookmarkListActivity.cpp/.h`
|
||||
- Bookmark identification by `spineIndex + contentOffset` (stable across re-renders)
|
||||
|
||||
---
|
||||
|
||||
### 3. Quick Menu
|
||||
|
||||
In-reader quick access menu for common actions, triggered by short power button press.
|
||||
|
||||
**Menu Options:**
|
||||
1. **Dictionary** - Look up a word
|
||||
2. **Bookmark** - Add/Remove bookmark (state-aware text)
|
||||
3. **Clear Cache** - Free up storage space
|
||||
4. **Settings** - Open settings menu
|
||||
|
||||
**Configuration:**
|
||||
- Settings → Controls → Short Power Button Click → `Quick Menu`
|
||||
|
||||
**Technical Implementation:**
|
||||
- File: `src/activities/util/QuickMenuActivity.cpp/.h`
|
||||
- Renders overlay with navigation and selection
|
||||
|
||||
---
|
||||
|
||||
### 4. Library Search with Character Picker
|
||||
|
||||
Search across all books using a dynamic character picker interface.
|
||||
|
||||
**Features:**
|
||||
- Character picker with dynamically generated character set from library content
|
||||
- Weighted search scoring:
|
||||
- Title match: 100 points (+50 if at start)
|
||||
- Author match: 80 points (+40 if at start)
|
||||
- Path match: 30 points
|
||||
- Results sorted by relevance score
|
||||
- Special controls: SPC (space), ← (backspace), CLR (clear)
|
||||
|
||||
**Navigation:**
|
||||
- Left/Right: Select character
|
||||
- Confirm: Add character to query
|
||||
- Up/Down: Switch between picker and results
|
||||
|
||||
**Technical Implementation:**
|
||||
- Integrated in `src/activities/home/MyLibraryActivity.cpp`
|
||||
- Search tab accessible from library tab bar
|
||||
|
||||
---
|
||||
|
||||
### 5. CSS Support for EPUBs
|
||||
|
||||
Parse and apply CSS styles from EPUB stylesheets.
|
||||
|
||||
**Supported Selectors:**
|
||||
- Element selectors: `p`, `div`, `h1`, etc.
|
||||
- Class selectors: `.classname`
|
||||
- Combined selectors: `element.classname`
|
||||
- Grouped selectors: `h1, h2, h3`
|
||||
- Inline styles: `style="..."`
|
||||
|
||||
**Supported Properties:**
|
||||
- `text-align` (left, center, right, justify)
|
||||
- `font-style` (normal, italic)
|
||||
- `font-weight` (normal, bold)
|
||||
- `text-decoration` (underline)
|
||||
- `text-indent`
|
||||
- `margin-top`, `margin-bottom`
|
||||
- `padding-top`, `padding-bottom`
|
||||
|
||||
**Cascade Order:**
|
||||
1. Element styles
|
||||
2. Class styles
|
||||
3. Element.class styles
|
||||
4. Inline styles
|
||||
|
||||
**Technical Implementation:**
|
||||
- Files: `lib/Epub/Epub/css/CssParser.cpp/.h`, `CssStyle.h`
|
||||
- CSS files parsed during EPUB loading
|
||||
- Styles applied during HTML parsing via `ChapterHtmlSlimParser`
|
||||
|
||||
---
|
||||
|
||||
### 6. Inline Image Support (PNG/Baseline JPEG)
|
||||
|
||||
Render embedded images within EPUB content.
|
||||
|
||||
**Supported Formats:**
|
||||
- Baseline JPEG (.jpg, .jpeg)
|
||||
- PNG (.png)
|
||||
|
||||
**Features:**
|
||||
- Images decoded to 2-bit grayscale with dithering
|
||||
- Image caching as `.pxc` files (2 bits per pixel, packed format)
|
||||
- Row-by-row rendering to minimize memory usage
|
||||
- Automatic scaling to fit page width
|
||||
|
||||
**Technical Implementation:**
|
||||
- Files: `lib/Epub/Epub/blocks/ImageBlock.cpp/.h`
|
||||
- Converters: `JpegToFramebufferConverter`, `PngToFramebufferConverter`
|
||||
- Factory: `ImageDecoderFactory` routes to appropriate decoder
|
||||
|
||||
---
|
||||
|
||||
### 7. Custom Fonts
|
||||
|
||||
Additional accessibility-focused fonts beyond the standard Bookerly and Noto Sans.
|
||||
|
||||
**Available Fonts:**
|
||||
1. **Atkinson Hyperlegible Next** - Designed for low-vision readers
|
||||
2. **Fern Micro** - Optimized for small screens
|
||||
|
||||
**Font Sizes:**
|
||||
- 12pt, 14pt, 16pt, 18pt for each font
|
||||
- Full style support: Regular, Italic, Bold, Bold Italic
|
||||
|
||||
**Configuration:**
|
||||
- Settings → Reader → Font Family → Custom
|
||||
- Settings → Reader → Custom Font → [Select font]
|
||||
- Settings → Reader → Fallback Font → [Bookerly/Noto Sans]
|
||||
|
||||
**Technical Implementation:**
|
||||
- Files: `src/customFonts.cpp`, `src/fontIds.h`
|
||||
- Font headers: `lib/EpdFont/builtinFonts/custom/`
|
||||
- Conversion scripts: `lib/EpdFont/scripts/convert-builtin-fonts.sh`
|
||||
|
||||
---
|
||||
|
||||
### 8. Enhanced Web Server
|
||||
|
||||
Extended web server with file management operations and companion app support.
|
||||
|
||||
**File Operations:**
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/api/files` | GET | List files with MD5 hashes for EPUBs |
|
||||
| `/api/status` | GET | Device status (version, IP, heap, uptime) |
|
||||
| `/api/archived` | GET | List archived books |
|
||||
| `/api/hash` | GET | Compute/retrieve MD5 hash for sync |
|
||||
| `/download` | GET | Download files |
|
||||
| `/upload` | POST | Upload files (multipart) |
|
||||
| `/delete` | POST | Delete files/folders |
|
||||
| `/archive` | POST | Archive a book |
|
||||
| `/unarchive` | POST | Restore archived book |
|
||||
| `/rename` | POST | Rename files/folders |
|
||||
| `/copy` | POST | Copy files/folders |
|
||||
| `/move` | POST | Move files/folders |
|
||||
| `/mkdir` | POST | Create folders |
|
||||
| `/list` | GET/POST | Manage reading lists |
|
||||
|
||||
**WebSocket Upload (Port 81):**
|
||||
- Fast binary uploads for large files
|
||||
- Protocol: `START:<filename>:<size>:<path>` → `READY` → binary chunks → `DONE`
|
||||
- Progress updates: `PROGRESS:<received>:<total>`
|
||||
|
||||
**mDNS Discovery:**
|
||||
- Hostname: `crosspoint.local`
|
||||
- Service: `_http._tcp` on port 80
|
||||
- UDP discovery on port 8134
|
||||
|
||||
**Deep Link Support:**
|
||||
- URL scheme: `crosspoint://<path>?host=<ip>&port=<port>&wsPort=<wsPort>`
|
||||
- Paths: `files`, `library`, `lists`, `settings`
|
||||
|
||||
**Technical Implementation:**
|
||||
- Files: `src/network/CrossPointWebServer.cpp/.h`
|
||||
- MD5 Utils: `src/util/Md5Utils.cpp/.h`
|
||||
- Docs: `docs/webserver-api-reference.md`, `docs/companion-app-deep-link-API.md`
|
||||
|
||||
---
|
||||
|
||||
### 9. Reading Lists with Pinning
|
||||
|
||||
Create and manage custom book lists with pinning support.
|
||||
|
||||
**Features:**
|
||||
- Create, load, delete lists
|
||||
- Pin a list to show on home screen
|
||||
- List contents displayed with book metadata
|
||||
- Web API for list upload/download (CSV format)
|
||||
|
||||
**Storage:**
|
||||
- Lists stored in `/.lists/` as `.bin` files
|
||||
- CSV format for API: `order,title,author,path`
|
||||
|
||||
**Configuration:**
|
||||
- Library → Lists tab → Long-press → Pin/Unpin
|
||||
- Pinned list name shown on home screen Lists button
|
||||
|
||||
**Technical Implementation:**
|
||||
- Files: `src/BookListStore.cpp/.h`
|
||||
- Pinned list stored in `SETTINGS.pinnedListName`
|
||||
|
||||
---
|
||||
|
||||
### 10. Display Enhancements
|
||||
|
||||
#### High Contrast Mode
|
||||
|
||||
System-wide display contrast adjustment for improved readability.
|
||||
|
||||
- **Normal mode:** Standard grayscale thresholds
|
||||
- **High contrast mode:** Pushes mid-grays toward black/white
|
||||
|
||||
**Configuration:**
|
||||
- Settings → Display → High Contrast → On/Off
|
||||
|
||||
#### Bezel Compensation
|
||||
|
||||
Compensate for physical screen edge defects with configurable margin.
|
||||
|
||||
- **Range:** 0-10 pixels
|
||||
- **Edges:** Bottom, Top, Left, Right
|
||||
- **Behavior:** Margin rotates with screen orientation
|
||||
|
||||
**Configuration:**
|
||||
- Settings → Display → Bezel Compensation → [0-10]
|
||||
- Settings → Display → Bezel Edge → [Bottom/Top/Left/Right]
|
||||
|
||||
#### Sleep Screen Improvements
|
||||
|
||||
Enhanced sleep screen with edge-aware color filling.
|
||||
|
||||
- **Edge luminance detection:** Samples edge pixels for dominant color
|
||||
- **Letterbox fill:** Fills letterbox regions with edge colors for seamless appearance
|
||||
- **Two-level caching:**
|
||||
- Per-BMP cache: `.bmp.perim` files store edge luminance
|
||||
- Book-level cache: `edge.bin` stores cover data
|
||||
|
||||
---
|
||||
|
||||
### 11. Recents View Improvements
|
||||
|
||||
Enhanced recent books display with metadata and management.
|
||||
|
||||
**Features:**
|
||||
- **Badges:** Extension and suffix tags (e.g., "epub", "X4")
|
||||
- **Metadata display:** Title and author from EPUB
|
||||
- **Remove from recents:** Long-press → Remove from Recents
|
||||
- **Clear all:** Long-press → Clear All Recents
|
||||
|
||||
**Badge Configuration:**
|
||||
- Extension badges: `.epub` → "epub", `.txt` → "txt"
|
||||
- Suffix badges: `-x4` → "X4", `-x4p` → "X4P"
|
||||
|
||||
**Technical Implementation:**
|
||||
- Files: `src/RecentBooksStore.cpp/.h`
|
||||
- Badge config: `src/BadgeConfig.h`
|
||||
- String utils: `src/util/StringUtils.cpp/.h`
|
||||
|
||||
---
|
||||
|
||||
### 12. Enhanced Tab Bar
|
||||
|
||||
Unified tab bar with scrolling and overflow indicators.
|
||||
|
||||
**Features:**
|
||||
- Horizontal scrolling when tabs exceed available width
|
||||
- Overflow indicators (< >) when content extends beyond view
|
||||
- Selected tab highlighting with underline
|
||||
- Bullet cursors for focus mode
|
||||
|
||||
**Tabs:**
|
||||
- Recent, Lists, Bookmarks, Search, Files
|
||||
|
||||
**Technical Implementation:**
|
||||
- Files: `src/ScreenComponents.cpp/.h`
|
||||
- Used in `MyLibraryActivity` for library navigation
|
||||
|
||||
---
|
||||
|
||||
### 13. Progress Bar Status Bar
|
||||
|
||||
Additional status bar option showing visual progress bar.
|
||||
|
||||
**Options:**
|
||||
- `Full w/ Progress Bar` - Full status bar with progress bar
|
||||
- `Progress Bar` - Only progress bar, no other status info
|
||||
|
||||
**Configuration:**
|
||||
- Settings → Display → Status Bar
|
||||
|
||||
---
|
||||
|
||||
### 14. Additional Settings
|
||||
|
||||
New configuration options unique to crosspoint-ef:
|
||||
|
||||
| Setting | Options | Description |
|
||||
|---------|---------|-------------|
|
||||
| Short Power Button Click | Ignore, Sleep, Page Turn, Dictionary, Quick Menu | Map power button to action |
|
||||
| Bezel Compensation | 0-10 pixels | Edge defect compensation |
|
||||
| Bezel Edge | Bottom, Top, Left, Right | Which edge to compensate |
|
||||
| High Contrast | Off, On | System-wide contrast boost |
|
||||
| Custom Font | [Font list] | Select custom font |
|
||||
| Fallback Font | Bookerly, Noto Sans | Fallback for custom fonts |
|
||||
|
||||
---
|
||||
|
||||
### 15. OPDS Browser Enhancements
|
||||
|
||||
Improved OPDS catalog browsing experience.
|
||||
|
||||
**Features:**
|
||||
- **Navigation history stack** - Back button navigates through visited feeds
|
||||
- **Page skipping** - Hold Up/Down for 700ms to skip 23 items at once
|
||||
- **Error retry mechanism** - Retry button on error screens with WiFi status check
|
||||
- **HTTP Basic Authentication** - Username/password support for protected OPDS servers
|
||||
|
||||
**Configuration:**
|
||||
- Settings → System → Calibre Settings → OPDS Server URL
|
||||
- Settings → System → Calibre Settings → Username/Password
|
||||
|
||||
**Technical Implementation:**
|
||||
- Files: `src/activities/browser/OpdsBookBrowserActivity.cpp`
|
||||
- Authentication: `src/network/HttpDownloader.cpp`
|
||||
|
||||
---
|
||||
|
||||
### 16. Development Tools
|
||||
|
||||
Scripts and utilities for firmware development.
|
||||
|
||||
**Scripts:**
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `pre_flash.py` | Displays "Flashing firmware..." screen during upload |
|
||||
| `debugging_monitor.py` | Enhanced serial monitor with memory graphs and color output |
|
||||
| `pio_helper.py` | Interactive PlatformIO workflow helper with presets |
|
||||
| `version_hash.py` | Embeds git commit hash in dev builds |
|
||||
| `build_html.py` | Minifies HTML files for web server |
|
||||
|
||||
**Firmware Flashing Screen:**
|
||||
- Full-screen display during firmware upload
|
||||
- Shows "Flashing firmware..." with version info
|
||||
- Lock icon indicates USB port location
|
||||
- Prevents accidental disconnection
|
||||
|
||||
**Debug/Memory Monitoring:**
|
||||
- `DEBUG_MEMORY` build mode for heap tracking at activity transitions
|
||||
- Periodic memory logging every 10 seconds (when Serial connected)
|
||||
- Loop duration warnings when exceeding 50ms
|
||||
- Detailed heap fragmentation info
|
||||
|
||||
**Technical Implementation:**
|
||||
- Scripts: `scripts/pre_flash.py`, `scripts/debugging_monitor.py`, `scripts/pio_helper.py`
|
||||
- Flash screen: `src/main.cpp` (lines 138-247)
|
||||
- Memory monitoring: `src/main.cpp` (lines 549-562)
|
||||
- Build config: `platformio.ini` (`debug_memory` environment)
|
||||
|
||||
---
|
||||
|
||||
### 17. Power Management Enhancements
|
||||
|
||||
Optimizations for battery life and responsiveness.
|
||||
|
||||
**Features:**
|
||||
- **Auto-sleep prevention** - Background tasks (web server, OTA, downloads) prevent auto-sleep
|
||||
- **USB connection detection** - Serial only starts when USB is connected (saves power)
|
||||
- **Skip loop delay** - Activities can request faster loop execution for responsive HTTP handling
|
||||
- **Power button release wait** - Prevents immediate wake if button is still held
|
||||
|
||||
**Technical Implementation:**
|
||||
- Files: `src/main.cpp`, `src/activities/Activity.h`
|
||||
- Methods: `preventAutoSleep()`, `skipLoopDelay()`
|
||||
|
||||
---
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
### Unique to crosspoint-ef
|
||||
|
||||
1. **Grayscale state corruption fix** - Prevents ghosting and gray filter artifacts when anti-aliasing is enabled under memory pressure
|
||||
2. **Memory optimization** - Graceful degradation when memory is low (skip anti-aliasing instead of corrupting display)
|
||||
|
||||
### Shared with 0.16.0
|
||||
|
||||
- Large EPUB indexing optimization (O(n²) → O(n))
|
||||
- Settings validation on read
|
||||
- Line break fixes (flush word before `<br/>`)
|
||||
- Rotate origin in `drawImage()`
|
||||
- Short-press power button to wakeup
|
||||
- Add txt books to recent tab
|
||||
- B&W filters for cover images
|
||||
|
||||
---
|
||||
|
||||
## Missing or Removed Features from 0.16.0
|
||||
|
||||
The following features are present in the upstream `0.16.0` release but are missing or were removed in `crosspoint-ef`:
|
||||
|
||||
### Removed Features
|
||||
|
||||
#### 1. KOReader Sync Support (Removed)
|
||||
|
||||
The entire KOReader sync functionality has been removed.
|
||||
|
||||
**What was removed:**
|
||||
- `lib/KOReaderSync/` library (8 files deleted)
|
||||
- Progress sync with KOReader sync server (`sync.koreader.rocks`)
|
||||
- Document MD5 binary matching for progress synchronization
|
||||
- KOReader credential storage
|
||||
|
||||
**Impact:**
|
||||
- Cannot sync reading progress with KOReader app
|
||||
- Chapter Selection UI fixes for KOReader sync (#501) not applicable
|
||||
|
||||
**Files deleted:**
|
||||
- `KOReaderSyncClient.cpp/.h`
|
||||
- `KOReaderCredentialStore.cpp/.h`
|
||||
- `KOReaderDocumentId.cpp/.h`
|
||||
- `ProgressMapper.cpp/.h`
|
||||
|
||||
---
|
||||
|
||||
#### 2. Non-English Hyphenation Patterns (Removed)
|
||||
|
||||
Hyphenation pattern files for non-English languages have been removed.
|
||||
|
||||
**What was removed:**
|
||||
- `hyph-es.trie.h` - Spanish hyphenation
|
||||
- `hyph-de.trie.h` - German hyphenation
|
||||
- `hyph-fr.trie.h` - French hyphenation
|
||||
- `hyph-ru.trie.h` - Russian hyphenation
|
||||
|
||||
**Impact:**
|
||||
- Only English hyphenation patterns remain
|
||||
- Non-English books will not hyphenate correctly
|
||||
- Spanish hyphenation support (#558) not available
|
||||
|
||||
**Note:** These can be restored by copying the trie files from 0.16.0.
|
||||
|
||||
---
|
||||
|
||||
#### 3. XTC/XTCH File Support (Removed)
|
||||
|
||||
Support for the XTC/XTCH proprietary format has been removed.
|
||||
|
||||
**What was removed:**
|
||||
- Author extraction from XTC/XTCH files (#563)
|
||||
- XTC format handling in file browsers
|
||||
|
||||
**Impact:**
|
||||
- XTC/XTCH files cannot be read
|
||||
- Author metadata not extracted from these formats
|
||||
|
||||
---
|
||||
|
||||
### Missing Bug Fixes
|
||||
|
||||
The following bug fixes from 0.16.0 have not been applied to crosspoint-ef:
|
||||
|
||||
| PR | Description | Impact |
|
||||
|----|-------------|--------|
|
||||
| #567 | Multi-line keyboard entry | Long text input truncated with "..." instead of wrapping |
|
||||
| #569 | Italics on image alt text | Image alt placeholders don't render in italics |
|
||||
| #564 | Front layout in mapLabels() | Button mapping may be incorrect in some layouts |
|
||||
| #486 | Relative position on settings change | Reader may jump to different location when settings change |
|
||||
| #501 | Chapter Selection UI (KOReader) | N/A - KOReader sync removed |
|
||||
| #529 | KOReader MD5 binary matching | N/A - KOReader sync removed |
|
||||
|
||||
---
|
||||
|
||||
### Missing UX Enhancements
|
||||
|
||||
| PR | Description | Impact |
|
||||
|----|-------------|--------|
|
||||
| #451 | Page turn on button press | When long-press chapter skip is disabled, 0.16.0 allows page turn on button press; crosspoint-ef does not |
|
||||
|
||||
---
|
||||
|
||||
### Different Implementation: OTA Updates
|
||||
|
||||
The OTA update mechanism uses a different implementation:
|
||||
|
||||
| Aspect | crosspoint-ef | 0.16.0 |
|
||||
|--------|---------------|--------|
|
||||
| HTTP Client | Arduino `HTTPClient` | ESP-IDF `esp_http_client` |
|
||||
| OTA Library | Arduino `Update` | ESP-IDF `esp_https_ota` |
|
||||
| Memory Management | Standard | Improved with custom buffer handling |
|
||||
|
||||
**Impact:**
|
||||
- Both implementations work, but 0.16.0's ESP-IDF approach may be more memory-efficient
|
||||
- Consider evaluating 0.16.0's OTA rework (#509) for potential adoption
|
||||
|
||||
---
|
||||
|
||||
### Recommendation for Missing Features
|
||||
|
||||
**High Priority to Cherry-pick:**
|
||||
1. Multi-line keyboard entry (#567) - Improves UX for long inputs
|
||||
2. Front layout fix (#564) - Bug fix for button mapping
|
||||
3. Relative position on settings change (#486) - Improves reader UX
|
||||
|
||||
**Medium Priority:**
|
||||
4. Restore hyphenation patterns for non-English languages
|
||||
5. Italics on image alt (#569) - Minor visual improvement
|
||||
6. Page turn on button press (#451) - UX enhancement
|
||||
|
||||
**Evaluate:**
|
||||
7. OTA rework (#509) - Compare implementations for memory benefits
|
||||
8. KOReader sync - Restore if sync functionality is desired
|
||||
|
||||
---
|
||||
|
||||
## File Summary
|
||||
|
||||
| Feature | Primary Files |
|
||||
|---------|---------------|
|
||||
| Dictionary | `src/activities/dictionary/`, `lib/StarDict/` |
|
||||
| Bookmarks | `src/BookmarkStore.*`, `src/activities/home/BookmarkListActivity.*` |
|
||||
| Quick Menu | `src/activities/util/QuickMenuActivity.*` |
|
||||
| Search | `src/activities/home/MyLibraryActivity.cpp` |
|
||||
| CSS | `lib/Epub/Epub/css/` |
|
||||
| Images | `lib/Epub/Epub/blocks/ImageBlock.*`, `lib/Epub/Epub/converters/` |
|
||||
| Custom Fonts | `src/customFonts.cpp`, `lib/EpdFont/builtinFonts/custom/` |
|
||||
| Web Server | `src/network/CrossPointWebServer.*`, `src/util/Md5Utils.*` |
|
||||
| Lists | `src/BookListStore.*` |
|
||||
| Settings | `src/CrossPointSettings.*` |
|
||||
| Tab Bar | `src/ScreenComponents.*` |
|
||||
| Recents | `src/RecentBooksStore.*`, `src/BadgeConfig.h` |
|
||||
| OPDS Browser | `src/activities/browser/OpdsBookBrowserActivity.*` |
|
||||
| Dev Tools | `scripts/pre_flash.py`, `scripts/debugging_monitor.py`, `scripts/pio_helper.py` |
|
||||
| Power Management | `src/main.cpp`, `src/activities/Activity.h` |
|
||||
|
||||
---
|
||||
|
||||
## Version Information
|
||||
|
||||
- **Base version:** 0.15.0
|
||||
- **Branch:** crosspoint-ef
|
||||
- **Commits since divergence:** 90+
|
||||
- **Files changed:** 250+
|
||||
555
docs/crosspoint-ef-user-guide.md
Normal file
555
docs/crosspoint-ef-user-guide.md
Normal file
@ -0,0 +1,555 @@
|
||||
# CrossPoint-EF User Guide Supplement
|
||||
|
||||
This guide covers the additional features available in the `crosspoint-ef` branch. For basic operation, refer to the main [User Guide](../USER_GUIDE.md).
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Dictionary](#dictionary)
|
||||
- [Bookmarks](#bookmarks)
|
||||
- [Quick Menu](#quick-menu)
|
||||
- [Library Search](#library-search)
|
||||
- [Reading Lists](#reading-lists)
|
||||
- [Display Settings](#display-settings)
|
||||
- [Web Server Features](#web-server-features)
|
||||
- [Custom Fonts](#custom-fonts)
|
||||
- [Additional Settings](#additional-settings)
|
||||
|
||||
---
|
||||
|
||||
## Dictionary
|
||||
|
||||
The dictionary feature provides offline word lookup while reading.
|
||||
|
||||
### Setup
|
||||
|
||||
1. Download a StarDict dictionary (English-English dictionary provided as `dict-en-en.zip`)
|
||||
2. Extract the dictionary files to `/dictionaries/dict-data/` on your SD card
|
||||
3. You should have these files:
|
||||
- `dict-data.ifo`
|
||||
- `dict-data.idx`
|
||||
- `dict-data.dict.dz`
|
||||
- `dict-data.syn` (optional, for synonyms)
|
||||
|
||||
### Using the Dictionary
|
||||
|
||||
#### Method 1: Quick Menu
|
||||
|
||||
1. While reading, press the **Power** button briefly (requires Quick Menu to be configured)
|
||||
2. Select **Dictionary** from the menu
|
||||
3. Choose **Select from Screen** or **Enter a Word**
|
||||
|
||||
#### Method 2: Direct Power Button Access
|
||||
|
||||
1. Go to **Settings → Controls → Short Power Button Click**
|
||||
2. Set to **Dictionary**
|
||||
3. While reading, press the **Power** button briefly to open the dictionary
|
||||
|
||||
### Selecting a Word from the Page
|
||||
|
||||
1. Choose **Select from Screen** from the dictionary menu
|
||||
2. The current page will display with word selection enabled
|
||||
3. Use **Left/Right** to move between words
|
||||
4. Use **Up/Down** to jump between lines
|
||||
5. Press **Confirm** to look up the selected word
|
||||
6. Press **Back** to cancel
|
||||
|
||||
### Viewing Definitions
|
||||
|
||||
- Definitions display with rich formatting (bold, italic, lists)
|
||||
- Use **Left/Right** or **Volume Up/Down** to navigate between pages if the definition is long
|
||||
- Press **Confirm** to search for another word
|
||||
- Press **Back** to return to your book
|
||||
|
||||
---
|
||||
|
||||
## Bookmarks
|
||||
|
||||
Create and manage bookmarks within your books.
|
||||
|
||||
### Adding a Bookmark
|
||||
|
||||
#### Method 1: Quick Menu
|
||||
|
||||
1. Press the **Power** button briefly (requires Quick Menu to be configured)
|
||||
2. Select **Add Bookmark** (or **Remove Bookmark** if already bookmarked)
|
||||
|
||||
#### Method 2: Settings Configuration
|
||||
|
||||
1. Go to **Settings → Controls → Short Power Button Click**
|
||||
2. Set to **Quick Menu**
|
||||
3. Use Quick Menu to toggle bookmarks
|
||||
|
||||
### Bookmark Indicator
|
||||
|
||||
When a page is bookmarked, a small folded corner triangle appears in the top-right corner of the page.
|
||||
|
||||
### Viewing Bookmarks
|
||||
|
||||
1. Go to **Home → Library**
|
||||
2. Select the **Bookmarks** tab
|
||||
3. You'll see a list of books that have bookmarks
|
||||
4. Select a book to view its bookmarks
|
||||
5. Select a bookmark to jump to that location
|
||||
|
||||
### Deleting Bookmarks
|
||||
|
||||
1. Open a book's bookmark list (from Bookmarks tab)
|
||||
2. Navigate to the bookmark you want to delete
|
||||
3. **Long-press Confirm** (hold for about 1 second)
|
||||
4. Confirm deletion when prompted
|
||||
|
||||
### Bookmark Naming
|
||||
|
||||
Bookmarks are automatically named based on:
|
||||
- Chapter title and page number (e.g., "Chapter 3 - Page 42")
|
||||
- Just page number if no chapter title (e.g., "Page 15")
|
||||
|
||||
---
|
||||
|
||||
## Quick Menu
|
||||
|
||||
Fast access to common actions while reading.
|
||||
|
||||
### Enabling Quick Menu
|
||||
|
||||
1. Go to **Settings → Controls → Short Power Button Click**
|
||||
2. Select **Quick Menu**
|
||||
|
||||
### Using Quick Menu
|
||||
|
||||
1. While reading, press the **Power** button briefly
|
||||
2. Navigate with **Up/Down** or **Left/Right**
|
||||
3. Press **Confirm** to select an option
|
||||
4. Press **Back** to close the menu
|
||||
|
||||
### Quick Menu Options
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| **Dictionary** | Look up a word |
|
||||
| **Add/Remove Bookmark** | Toggle bookmark on current page |
|
||||
| **Clear Cache** | Free up storage space |
|
||||
| **Settings** | Open settings menu |
|
||||
|
||||
---
|
||||
|
||||
## Library Search
|
||||
|
||||
Search your library by title, author, or filename.
|
||||
|
||||
### Accessing Search
|
||||
|
||||
1. Go to **Home → Library**
|
||||
2. Select the **Search** tab
|
||||
3. Or from any tab, scroll to the bottom and select **Search...**
|
||||
|
||||
### Using the Character Picker
|
||||
|
||||
The search uses a character picker interface:
|
||||
|
||||
1. **Left/Right** - Move between characters
|
||||
2. **Confirm** - Add character to search query
|
||||
3. **SPC** - Add a space
|
||||
4. **←** - Delete last character (backspace)
|
||||
5. **CLR** - Clear entire query
|
||||
|
||||
### Navigating Results
|
||||
|
||||
1. After entering characters, results appear below
|
||||
2. Press **Down** to move from character picker to results
|
||||
3. **Left/Right** to navigate results
|
||||
4. **Confirm** to open a book
|
||||
5. **Up** to return to character picker
|
||||
|
||||
### Search Scoring
|
||||
|
||||
Results are ranked by relevance:
|
||||
- Title matches rank highest
|
||||
- Author matches rank second
|
||||
- Filename matches rank lowest
|
||||
- Matches at the start of a field rank higher
|
||||
|
||||
---
|
||||
|
||||
## Reading Lists
|
||||
|
||||
Create custom book lists for organizing your library.
|
||||
|
||||
### Viewing Lists
|
||||
|
||||
1. Go to **Home → Library**
|
||||
2. Select the **Lists** tab
|
||||
3. Available lists are displayed
|
||||
|
||||
### Opening a List
|
||||
|
||||
1. Navigate to a list name
|
||||
2. Press **Confirm** to view the list contents
|
||||
3. Select a book to start reading
|
||||
|
||||
### Pinning a List
|
||||
|
||||
Pin a list to quickly access it from the home screen:
|
||||
|
||||
1. In the Lists tab, navigate to a list
|
||||
2. **Long-press Confirm** to open the action menu
|
||||
3. Select **Pin List**
|
||||
|
||||
The pinned list name will appear on the Lists button on the home screen.
|
||||
|
||||
### Unpinning a List
|
||||
|
||||
1. Navigate to the pinned list
|
||||
2. **Long-press Confirm**
|
||||
3. Select **Unpin List**
|
||||
|
||||
### Deleting a List
|
||||
|
||||
1. Navigate to a list
|
||||
2. **Long-press Confirm**
|
||||
3. Select **Delete List**
|
||||
4. Confirm deletion
|
||||
|
||||
### Creating Lists via Web Server
|
||||
|
||||
Lists can be created and uploaded via the web server API. See [Web Server Features](#web-server-features).
|
||||
|
||||
---
|
||||
|
||||
## Display Settings
|
||||
|
||||
### High Contrast Mode
|
||||
|
||||
Increases contrast across the entire UI for better readability.
|
||||
|
||||
1. Go to **Settings → Display → High Contrast**
|
||||
2. Set to **On** or **Off**
|
||||
|
||||
When enabled, mid-gray tones are pushed toward black or white.
|
||||
|
||||
### Bezel Compensation
|
||||
|
||||
Compensate for physical screen edge defects (common on some devices).
|
||||
|
||||
1. Go to **Settings → Display → Bezel Compensation**
|
||||
2. Set value from **0** (disabled) to **10** pixels
|
||||
3. If compensation is enabled, select **Bezel Edge**:
|
||||
- **Bottom** - Default, compensates bottom edge
|
||||
- **Top** - Compensates top edge
|
||||
- **Left** - Compensates left edge
|
||||
- **Right** - Compensates right edge
|
||||
|
||||
The compensation margin automatically rotates with screen orientation.
|
||||
|
||||
### Status Bar Options
|
||||
|
||||
Additional status bar display options:
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| None | No status bar |
|
||||
| No Progress | Status bar without reading progress |
|
||||
| Full w/ Percentage | Status bar with percentage progress |
|
||||
| Full w/ Progress Bar | Status bar with visual progress bar |
|
||||
| Progress Bar | Only progress bar, no other info |
|
||||
|
||||
Configure at **Settings → Display → Status Bar**.
|
||||
|
||||
### Sleep Screen Cover Filter
|
||||
|
||||
When using book cover as sleep screen:
|
||||
|
||||
| Filter | Effect |
|
||||
|--------|--------|
|
||||
| None | Grayscale image as-is |
|
||||
| Contrast | Black and white only (no grays) |
|
||||
| Inverted | Inverted black and white |
|
||||
|
||||
Configure at **Settings → Display → Sleep Screen Cover Filter**.
|
||||
|
||||
---
|
||||
|
||||
## Web Server Features
|
||||
|
||||
The web server provides extended file management and companion app support.
|
||||
|
||||
### Starting the Web Server
|
||||
|
||||
1. Go to **Home → File Transfer**
|
||||
2. Select a WiFi network or create a hotspot
|
||||
3. The web server URL will be displayed
|
||||
|
||||
### File Management
|
||||
|
||||
Access the file manager at `http://<device-ip>/files`
|
||||
|
||||
**Available Operations:**
|
||||
- **Upload** - Upload files via drag-and-drop or file picker
|
||||
- **Download** - Download files to your computer
|
||||
- **Delete** - Remove files and folders
|
||||
- **Rename** - Rename files and folders
|
||||
- **Create Folder** - Create new directories
|
||||
- **Archive/Unarchive** - Archive books (preserves reading progress)
|
||||
- **Copy/Move** - Copy or move files and folders
|
||||
|
||||
### API Access
|
||||
|
||||
The web server provides a JSON API for programmatic access:
|
||||
|
||||
| Endpoint | Description |
|
||||
|----------|-------------|
|
||||
| `GET /api/status` | Device status |
|
||||
| `GET /api/files?path=/` | List files |
|
||||
| `GET /api/archived` | List archived books |
|
||||
| `GET /api/hash?path=/book.epub` | Get MD5 hash |
|
||||
|
||||
### mDNS Discovery
|
||||
|
||||
The device advertises itself as `crosspoint.local` on your network.
|
||||
|
||||
### Companion App Support
|
||||
|
||||
The web server supports the CrossPoint Companion Android app:
|
||||
|
||||
1. **QR Code** - Scan the QR code displayed on the web server screen
|
||||
2. **Deep Links** - URLs like `crosspoint://files?host=192.168.1.100` open the app directly
|
||||
|
||||
### Managing Reading Lists via API
|
||||
|
||||
**Get all lists:**
|
||||
```
|
||||
GET /list
|
||||
```
|
||||
|
||||
**Get specific list:**
|
||||
```
|
||||
GET /list?name=MyList
|
||||
```
|
||||
|
||||
**Upload a list:**
|
||||
```
|
||||
POST /list?action=upload&name=MyList
|
||||
Content-Type: text/plain
|
||||
|
||||
1,Book Title,Author Name,/path/to/book.epub
|
||||
2,Another Book,Another Author,/path/to/another.epub
|
||||
```
|
||||
|
||||
**Delete a list:**
|
||||
```
|
||||
POST /list?action=delete&name=MyList
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Custom Fonts
|
||||
|
||||
Two additional accessibility-focused fonts are available.
|
||||
|
||||
### Available Custom Fonts
|
||||
|
||||
1. **Atkinson Hyperlegible Next** - Designed for low-vision readers with high character differentiation
|
||||
2. **Fern Micro** - Optimized for small screens
|
||||
|
||||
### Enabling Custom Fonts
|
||||
|
||||
1. Go to **Settings → Reader → Font Family**
|
||||
2. Select **Custom**
|
||||
3. Go to **Settings → Reader → Custom Font**
|
||||
4. Select your preferred font
|
||||
|
||||
### Fallback Font
|
||||
|
||||
When using custom fonts, set a fallback for missing glyphs:
|
||||
|
||||
1. Go to **Settings → Reader → Fallback Font**
|
||||
2. Choose **Bookerly** or **Noto Sans**
|
||||
|
||||
---
|
||||
|
||||
## Additional Settings
|
||||
|
||||
### Short Power Button Actions
|
||||
|
||||
Configure what happens when you briefly press the Power button:
|
||||
|
||||
| Option | Action |
|
||||
|--------|--------|
|
||||
| Ignore | No action (default) |
|
||||
| Sleep | Put device to sleep |
|
||||
| Page Turn | Turn to next page |
|
||||
| Dictionary | Open dictionary |
|
||||
| Quick Menu | Open quick menu |
|
||||
|
||||
Configure at **Settings → Controls → Short Power Button Click**.
|
||||
|
||||
### Long-press Chapter Skip
|
||||
|
||||
Control side button long-press behavior:
|
||||
|
||||
- **On** (default) - Long-press Volume buttons to skip chapters
|
||||
- **Off** - Long-press scrolls a page instead
|
||||
|
||||
Configure at **Settings → Controls → Long-press Chapter Skip**.
|
||||
|
||||
### Hyphenation
|
||||
|
||||
Enable word hyphenation for justified text:
|
||||
|
||||
1. Go to **Settings → Reader → Hyphenation**
|
||||
2. Set to **On**
|
||||
|
||||
Hyphenation patterns are available for multiple languages (English, German, French, Spanish, Russian, etc.).
|
||||
|
||||
---
|
||||
|
||||
## Recents View Enhancements
|
||||
|
||||
### Badges
|
||||
|
||||
Books in the Recent tab display badges showing:
|
||||
- **File extension** (epub, txt, md)
|
||||
- **Suffix tags** (X4, X4P for files with `-x4` or `-x4p` suffixes)
|
||||
|
||||
### Removing from Recents
|
||||
|
||||
1. Navigate to a book in the Recent tab
|
||||
2. **Long-press Confirm**
|
||||
3. Select **Remove from Recents**
|
||||
|
||||
### Clearing All Recents
|
||||
|
||||
1. Navigate to any book in the Recent tab
|
||||
2. **Long-press Confirm**
|
||||
3. Select **Clear All Recents**
|
||||
4. Confirm the action
|
||||
|
||||
---
|
||||
|
||||
## Tab Navigation
|
||||
|
||||
The library uses a unified tab bar for navigation.
|
||||
|
||||
### Tabs Available
|
||||
|
||||
| Tab | Contents |
|
||||
|-----|----------|
|
||||
| Recent | Recently opened books |
|
||||
| Lists | Custom reading lists |
|
||||
| Bookmarks | Books with bookmarks |
|
||||
| Search | Search all books |
|
||||
| Files | File browser |
|
||||
|
||||
### Navigating Tabs
|
||||
|
||||
When the tab bar is focused:
|
||||
- **Left/Right** - Switch between tabs
|
||||
- **Down** - Enter the selected tab's content
|
||||
- **Confirm** - Same as Down
|
||||
|
||||
### Tab Overflow
|
||||
|
||||
When tabs don't fit on screen:
|
||||
- **<** indicator appears on left when more tabs exist to the left
|
||||
- **>** indicator appears on right when more tabs exist to the right
|
||||
- Scroll continues automatically when navigating past visible tabs
|
||||
|
||||
---
|
||||
|
||||
## Inline Images
|
||||
|
||||
EPUBs with embedded images now display them inline with text.
|
||||
|
||||
### Supported Formats
|
||||
|
||||
- JPEG (.jpg, .jpeg)
|
||||
- PNG (.png)
|
||||
|
||||
### Image Display
|
||||
|
||||
- Images are automatically scaled to fit the page width
|
||||
- Images are converted to 4-level grayscale with dithering
|
||||
- First load may be slower as images are processed
|
||||
- Subsequent loads use cached versions
|
||||
|
||||
### Image Cache
|
||||
|
||||
Processed images are cached as `.pxc` files in the book's cache directory for faster loading.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Dictionary Not Working
|
||||
|
||||
1. Verify dictionary files are in `/dictionaries/dict-data/`
|
||||
2. Check that all required files exist (.ifo, .idx, .dict.dz)
|
||||
3. File names must match exactly (case-sensitive)
|
||||
|
||||
### Bookmarks Not Saving
|
||||
|
||||
1. Ensure SD card is not write-protected
|
||||
2. Check available storage space
|
||||
3. Bookmarks are saved per-book in `/.crosspoint/`
|
||||
|
||||
### Search Not Finding Books
|
||||
|
||||
1. Search only indexes books in the library
|
||||
2. Ensure books have proper EPUB metadata
|
||||
3. Try searching by filename if metadata is missing
|
||||
|
||||
### Images Not Displaying
|
||||
|
||||
1. Only PNG and JPEG formats are supported
|
||||
2. Very large images may fail to load due to memory constraints
|
||||
3. Check for sufficient free memory (multiple large books open may exhaust memory)
|
||||
|
||||
### Web Server Connection Issues
|
||||
|
||||
1. Ensure device and computer are on the same network
|
||||
2. Try accessing via IP address instead of `crosspoint.local`
|
||||
3. Check that firewall isn't blocking port 80
|
||||
|
||||
---
|
||||
|
||||
## Keyboard Shortcuts Summary
|
||||
|
||||
### In Reader
|
||||
|
||||
| Button | Action |
|
||||
|--------|--------|
|
||||
| Left/Volume Up | Previous page |
|
||||
| Right/Volume Down | Next page |
|
||||
| Left (hold) | Previous chapter |
|
||||
| Right (hold) | Next chapter |
|
||||
| Back | Return to library |
|
||||
| Back (hold) | Return to home |
|
||||
| Confirm | Open chapter selection |
|
||||
| Power (brief) | Configured action (Quick Menu/Dictionary/Sleep/Page Turn) |
|
||||
|
||||
### In Quick Menu
|
||||
|
||||
| Button | Action |
|
||||
|--------|--------|
|
||||
| Up/Down/Left/Right | Navigate options |
|
||||
| Confirm | Select option |
|
||||
| Back | Close menu |
|
||||
|
||||
### In Word Selection
|
||||
|
||||
| Button | Action |
|
||||
|--------|--------|
|
||||
| Left/Right | Move between words |
|
||||
| Up/Down | Move between lines |
|
||||
| Confirm | Look up word |
|
||||
| Back | Cancel |
|
||||
|
||||
### In Library Tabs
|
||||
|
||||
| Button | Action |
|
||||
|--------|--------|
|
||||
| Left/Right | Switch tabs (when tab bar focused) |
|
||||
| Up/Down | Navigate within tab |
|
||||
| Confirm | Select item / Enter tab |
|
||||
| Confirm (hold) | Action menu |
|
||||
| Back | Go back / Exit to home |
|
||||
66
docs/hyphenation-trie-format.md
Normal file
66
docs/hyphenation-trie-format.md
Normal file
@ -0,0 +1,66 @@
|
||||
# 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 node’s 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
|
||||
```
|
||||
86
docs/troubleshooting.md
Normal file
86
docs/troubleshooting.md
Normal file
@ -0,0 +1,86 @@
|
||||
# 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
|
||||
334
docs/webserver-api-reference.md
Normal file
334
docs/webserver-api-reference.md
Normal file
@ -0,0 +1,334 @@
|
||||
# CrossPointWebServer API Reference
|
||||
|
||||
Source: `src/network/CrossPointWebServer.cpp` and `CrossPointWebServer.h`
|
||||
|
||||
## Server Configuration
|
||||
|
||||
- HTTP port: 80 (default)
|
||||
- WebSocket port: 81 (default)
|
||||
- WiFi sleep disabled for responsiveness
|
||||
- Supports both STA (station) and AP (access point) modes
|
||||
|
||||
## HTTP Endpoints
|
||||
|
||||
### GET /
|
||||
**Handler:** `handleRoot()`
|
||||
**Response:** HTML homepage from `HomePageHtml` (generated from `html/HomePage.html`)
|
||||
**Content-Type:** text/html
|
||||
|
||||
### GET /files
|
||||
**Handler:** `handleFileList()`
|
||||
**Response:** HTML file browser page from `FilesPageHtml` (generated from `html/FilesPage.html`)
|
||||
**Content-Type:** text/html
|
||||
|
||||
### GET /api/status
|
||||
**Handler:** `handleStatus()`
|
||||
**Response:** JSON device status
|
||||
**Content-Type:** application/json
|
||||
```json
|
||||
{
|
||||
"version": "CROSSPOINT_VERSION",
|
||||
"ip": "192.168.x.x",
|
||||
"mode": "AP" | "STA",
|
||||
"rssi": -50, // 0 in AP mode
|
||||
"freeHeap": 123456,
|
||||
"uptime": 3600 // seconds
|
||||
}
|
||||
```
|
||||
|
||||
### GET /api/files
|
||||
**Handler:** `handleFileListData()`
|
||||
**Query params:**
|
||||
- `path` (optional): Directory path, defaults to "/"
|
||||
- `showHidden` (optional): "true" to show dot-files (except .crosspoint)
|
||||
**Response:** JSON array of files
|
||||
**Content-Type:** application/json
|
||||
```json
|
||||
[
|
||||
{"name": "book.epub", "size": 123456, "isDirectory": false, "isEpub": true},
|
||||
{"name": "folder", "size": 0, "isDirectory": true, "isEpub": false}
|
||||
]
|
||||
```
|
||||
**Notes:**
|
||||
- Hidden by default: files starting with ".", "System Volume Information", "XTCache"
|
||||
- Always hidden: ".crosspoint" (internal cache folder)
|
||||
- Streamed response (chunked encoding) to reduce memory usage
|
||||
|
||||
### GET /api/archived
|
||||
**Handler:** `handleArchivedList()`
|
||||
**Response:** JSON array of archived books
|
||||
**Content-Type:** application/json
|
||||
```json
|
||||
[
|
||||
{"filename": "archived_file.epub", "originalPath": "/Books/archived_file.epub"}
|
||||
]
|
||||
```
|
||||
**Notes:** Uses `BookManager::listArchivedBooks()` and `BookManager::getArchivedBookOriginalPath()`
|
||||
|
||||
### GET /download
|
||||
**Handler:** `handleDownload()`
|
||||
**Query params:**
|
||||
- `path` (required): File path to download
|
||||
**Response:** File binary with Content-Disposition attachment header
|
||||
**Content-Type:** application/octet-stream
|
||||
**Errors:**
|
||||
- 400: Missing path, path is directory
|
||||
- 403: Hidden/system file, protected item
|
||||
- 404: File not found
|
||||
**Notes:**
|
||||
- Streams in 4KB chunks
|
||||
- Updates `totalBytesDownloaded` and `totalFilesDownloaded` stats
|
||||
- Security: rejects paths with "..", files starting with ".", protected items
|
||||
|
||||
### POST /upload
|
||||
**Handler:** `handleUpload()` (multipart handler), `handleUploadPost()` (response handler)
|
||||
**Query params:**
|
||||
- `path` (optional): Upload directory, defaults to "/"
|
||||
**Form data:** multipart/form-data with file
|
||||
**Response:** "File uploaded successfully: filename" or error message
|
||||
**Notes:**
|
||||
- Uses 4KB write buffer for SD card efficiency
|
||||
- Overwrites existing files
|
||||
- Clears epub cache after upload via `clearEpubCacheIfNeeded()`
|
||||
- Updates `totalBytesUploaded` and `totalFilesUploaded` stats
|
||||
- Logs progress every 100KB
|
||||
|
||||
### POST /mkdir
|
||||
**Handler:** `handleCreateFolder()`
|
||||
**Form params:**
|
||||
- `name` (required): Folder name
|
||||
- `path` (optional): Parent directory, defaults to "/"
|
||||
**Response:** "Folder created: foldername" or error
|
||||
**Errors:**
|
||||
- 400: Missing name, empty name, folder exists
|
||||
|
||||
### POST /delete
|
||||
**Handler:** `handleDelete()`
|
||||
**Form params:**
|
||||
- `path` (required): Item path to delete
|
||||
- `type` (optional): "file" (default) or "folder"
|
||||
- `archived` (optional): "true" for archived books
|
||||
**Response:** "Deleted successfully" or error
|
||||
**Errors:**
|
||||
- 400: Missing path, root directory, folder not empty
|
||||
- 403: Hidden/system file, protected item
|
||||
- 404: Item not found
|
||||
- 500: Delete failed
|
||||
**Notes:**
|
||||
- For files: uses `BookManager::deleteBook()` which handles cache and recent books cleanup
|
||||
- For folders: must be empty first
|
||||
- For archived: passes filename to `BookManager::deleteBook(filename, true)`
|
||||
|
||||
### POST /archive
|
||||
**Handler:** `handleArchive()`
|
||||
**Form params:**
|
||||
- `path` (required): Book path to archive
|
||||
**Response:** "Book archived successfully" or error
|
||||
**Notes:** Uses `BookManager::archiveBook()`
|
||||
|
||||
### POST /unarchive
|
||||
**Handler:** `handleUnarchive()`
|
||||
**Form params:**
|
||||
- `filename` (required): Archived book filename
|
||||
**Response:** JSON with original path
|
||||
**Content-Type:** application/json
|
||||
```json
|
||||
{"success": true, "originalPath": "/Books/book.epub"}
|
||||
```
|
||||
**Notes:** Uses `BookManager::unarchiveBook()` and `BookManager::getArchivedBookOriginalPath()`
|
||||
|
||||
### POST /rename
|
||||
**Handler:** `handleRename()`
|
||||
**Form params:**
|
||||
- `path` (required): Current item path
|
||||
- `newName` (required): New name (filename only, no path separators)
|
||||
**Response:** "Renamed successfully" or error
|
||||
**Errors:**
|
||||
- 400: Missing params, empty name, name contains "/" or "\\", root directory, destination exists
|
||||
- 403: System file, protected item
|
||||
- 404: Source not found
|
||||
- 500: Rename failed
|
||||
**Notes:**
|
||||
- Renames in place (same directory, new name)
|
||||
- Uses `SdMan.rename()`
|
||||
- Clears epub cache after rename via `clearEpubCacheIfNeeded()`
|
||||
|
||||
### POST /copy
|
||||
**Handler:** `handleCopy()`
|
||||
**Form params:**
|
||||
- `srcPath` (required): Source path
|
||||
- `destPath` (required): Full destination path (including new name)
|
||||
**Response:** "Copied successfully" or error
|
||||
**Errors:**
|
||||
- 400: Missing params, root directory, destination exists, copy into self
|
||||
- 403: System file, protected item
|
||||
- 404: Source not found
|
||||
- 500: Copy failed
|
||||
**Notes:**
|
||||
- Uses `copyFile()` for files (4KB buffer chunks)
|
||||
- Uses `copyFolder()` for recursive directory copy
|
||||
- Skips hidden files in folder copy
|
||||
|
||||
### POST /move
|
||||
**Handler:** `handleMove()`
|
||||
**Form params:**
|
||||
- `srcPath` (required): Source path
|
||||
- `destPath` (required): Full destination path (including new name)
|
||||
**Response:** "Moved successfully" or error
|
||||
**Errors:** Same as copy
|
||||
**Notes:**
|
||||
- First attempts atomic `SdMan.rename()` (fast)
|
||||
- Falls back to copy+delete if rename fails
|
||||
- Uses `deleteFolderRecursive()` for folder cleanup
|
||||
|
||||
### GET /list
|
||||
**Handler:** `handleListGet()`
|
||||
**Query params:**
|
||||
- `name` (optional): Specific list name to retrieve
|
||||
**Response:** JSON array of lists (if no name) or single list details (if name specified)
|
||||
**Content-Type:** application/json
|
||||
|
||||
**Response (all lists - no name param):**
|
||||
```json
|
||||
[
|
||||
{"name": "MyReadingList", "path": "/.lists/MyReadingList.bin", "bookCount": 5},
|
||||
{"name": "Favorites", "path": "/.lists/Favorites.bin", "bookCount": 12}
|
||||
]
|
||||
```
|
||||
|
||||
**Response (specific list - with name param):**
|
||||
```json
|
||||
{
|
||||
"name": "MyReadingList",
|
||||
"path": "/.lists/MyReadingList.bin",
|
||||
"books": [
|
||||
{"order": 1, "title": "The Great Gatsby", "author": "F. Scott Fitzgerald", "path": "/Books/gatsby.epub"},
|
||||
{"order": 2, "title": "1984", "author": "George Orwell", "path": "/Books/1984.epub"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Errors:**
|
||||
- 404: List not found (when `name` specified but doesn't exist)
|
||||
|
||||
**Notes:**
|
||||
- Lists are stored in `/.lists/` directory as `.bin` files
|
||||
- Uses `BookListStore::listAllLists()` and `BookListStore::loadList()`
|
||||
|
||||
### POST /list
|
||||
**Handler:** `handleListPost()`
|
||||
**Query params:**
|
||||
- `action` (required): "upload" or "delete"
|
||||
- `name` (required): List name (without .bin extension)
|
||||
**Request body (for upload):** CSV text with one book per line
|
||||
**Content-Type:** text/plain (for upload body)
|
||||
|
||||
**Input format (POST body for upload action):**
|
||||
```
|
||||
1,The Great Gatsby,F. Scott Fitzgerald,/Books/gatsby.epub
|
||||
2,1984,George Orwell,/Books/1984.epub
|
||||
3,Pride and Prejudice,Jane Austen,/Books/pride.epub
|
||||
```
|
||||
Format: `order,title,author,path` (one per line)
|
||||
|
||||
**Response (upload success):**
|
||||
```json
|
||||
{"success": true, "path": "/.lists/MyReadingList.bin"}
|
||||
```
|
||||
|
||||
**Response (delete success):**
|
||||
```json
|
||||
{"success": true}
|
||||
```
|
||||
|
||||
**Errors:**
|
||||
- 400: Missing action or name parameter, empty name, failed to parse list data
|
||||
- 404: List not found (for delete action)
|
||||
- 500: Failed to save/delete list
|
||||
|
||||
**Notes:**
|
||||
- Lists are stored as binary files in `/.lists/` directory
|
||||
- Uses `BookListStore::parseFromText()`, `BookListStore::saveList()`, `BookListStore::deleteList()`
|
||||
- Order field determines display order (books are sorted by order when loaded)
|
||||
- Overwrites existing list with same name on upload
|
||||
|
||||
## WebSocket Protocol (port 81)
|
||||
|
||||
**Handler:** `onWebSocketEvent()` via `wsEventCallback()` trampoline
|
||||
|
||||
### Upload Protocol
|
||||
|
||||
1. Client connects
|
||||
2. Server: (implicit connection acknowledgment)
|
||||
3. Client TEXT: `START:<filename>:<size>:<path>`
|
||||
4. Server TEXT: `READY` or `ERROR:<message>`
|
||||
5. Client BIN: file data chunks (any size, recommend 64KB)
|
||||
6. Server TEXT: `PROGRESS:<received>:<total>` (every 64KB or at end)
|
||||
7. Server TEXT: `DONE` or `ERROR:<message>`
|
||||
|
||||
### Events
|
||||
- `WStype_CONNECTED`: Client connected, logs connection
|
||||
- `WStype_DISCONNECTED`: Cleanup incomplete upload, delete partial file
|
||||
- `WStype_TEXT`: Parse control messages (START)
|
||||
- `WStype_BIN`: Write file data, send progress, complete upload
|
||||
|
||||
### Notes
|
||||
- Faster than HTTP multipart for large files
|
||||
- Direct binary writes to SD card
|
||||
- Clears epub cache after upload
|
||||
- Updates traffic statistics
|
||||
|
||||
## Security
|
||||
|
||||
### Protected Items (HIDDEN_ITEMS[])
|
||||
- "System Volume Information"
|
||||
- "XTCache"
|
||||
|
||||
### Always Hidden
|
||||
- ".crosspoint" (internal cache)
|
||||
|
||||
### Security Checks Applied To
|
||||
- `/delete`: Rejects dot-files (unless archived), protected items
|
||||
- `/download`: Rejects dot-files, protected items, path traversal (..)
|
||||
- `/rename`: Rejects dot-files, protected items
|
||||
- `/copy`: Rejects dot-files, protected items
|
||||
- `/move`: Rejects dot-files, protected items
|
||||
|
||||
## Helper Functions
|
||||
|
||||
### clearEpubCacheIfNeeded(filePath)
|
||||
- Location: anonymous namespace at top of file
|
||||
- Clears epub cache if file ends with ".epub"
|
||||
- Uses `Epub(filePath, "/.crosspoint").clearCache()`
|
||||
- Called by: upload, WebSocket upload, rename
|
||||
|
||||
### scanFiles(path, callback, showHidden)
|
||||
- Iterates directory, calls callback for each FileInfo
|
||||
- Yields and resets watchdog during iteration
|
||||
- Filters hidden items based on showHidden flag
|
||||
|
||||
### copyFile(srcPath, destPath) / copyFolder(srcPath, destPath)
|
||||
- 4KB buffer for file copy
|
||||
- Recursive for folders
|
||||
- Returns bool success
|
||||
|
||||
### deleteFolderRecursive(path)
|
||||
- Static helper for move fallback
|
||||
- Recursively deletes contents then directory
|
||||
|
||||
## Traffic Statistics (mutable, updated from const handlers)
|
||||
- `totalBytesUploaded`
|
||||
- `totalBytesDownloaded`
|
||||
- `totalFilesUploaded`
|
||||
- `totalFilesDownloaded`
|
||||
- `serverStartTime` (for uptime calculation)
|
||||
|
||||
## Dependencies
|
||||
- `<WebServer.h>` - ESP32 HTTP server
|
||||
- `<WebSocketsServer.h>` - WebSocket support
|
||||
- `<ArduinoJson.h>` - JSON serialization
|
||||
- `<SDCardManager.h>` - SD card operations (SdMan singleton)
|
||||
- `<Epub.h>` - Epub cache management
|
||||
- `BookListStore.h` - Book list management (lists feature)
|
||||
- `BookManager.h` - Book deletion, archiving, recent books
|
||||
- `StringUtils.h` - File extension checking
|
||||
331
docs/webserver-endpoints.md
Normal file
331
docs/webserver-endpoints.md
Normal file
@ -0,0 +1,331 @@
|
||||
# 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
|
||||
@ -170,57 +170,9 @@ This is useful for organizing your ebooks by genre, author, or series.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
## Command Line File Management
|
||||
|
||||
### 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
|
||||
|
||||
---
|
||||
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).
|
||||
|
||||
## Security Notes
|
||||
|
||||
@ -269,4 +221,5 @@ Your uploaded files will be immediately available in the file browser!
|
||||
## Related Documentation
|
||||
|
||||
- [User Guide](../USER_GUIDE.md) - General device operation
|
||||
- [Troubleshooting](./troubleshooting.md) - Troubleshooting
|
||||
- [README](../README.md) - Project overview and features
|
||||
|
||||
195
ef-CHANGELOG.md
Normal file
195
ef-CHANGELOG.md
Normal file
@ -0,0 +1,195 @@
|
||||
# crosspoint-ef Changelog
|
||||
|
||||
All notable changes to the crosspoint-ef fork are documented here.
|
||||
|
||||
Base: CrossPoint Reader 0.15.0
|
||||
|
||||
---
|
||||
|
||||
## ef-1.0.5
|
||||
|
||||
**Stability & Memory Improvements**
|
||||
|
||||
### Bug Fixes - Webserver
|
||||
|
||||
- **File Transfer Stability**: Removed blocking MD5 hash computation from file listings that caused EAGAIN errors and connection stalls
|
||||
- **JSON Batching**: Implemented 2KB batch streaming for file listings with pacing to prevent TCP buffer overflow
|
||||
- **Simplified Flow Control**: Removed unnecessary yield/delay logic from content streaming
|
||||
|
||||
### Bug Fixes - Memory
|
||||
|
||||
- **QR Code Caching**: Generate QR codes once on server start instead of regenerating on each screen render
|
||||
- **WiFi Scan Optimization**: Replaced memory-heavy `std::map` deduplication with in-place vector search, limited results to 20 networks, earlier `WiFi.scanDelete()` for faster memory recovery
|
||||
- **Cover Buffer Leak**: Fixed 48KB memory leak when navigating from Home to File Transfer (cover buffer now explicitly freed)
|
||||
|
||||
### Bug Fixes - EPUB Reader
|
||||
|
||||
- **Errant Underlining**: Fixed words before styled inline elements (like `<a>` tags with CSS underline) incorrectly receiving the element's style by flushing the text buffer before style changes
|
||||
|
||||
### Bug Fixes - Flashing Screen
|
||||
|
||||
- **Version String Overflow**: Fixed flash notification parsing failing on longer version strings (buffer limit increased from 30 to 50 characters)
|
||||
- **Display Quality**: Changed flashing screen to half refresh for cleaner appearance
|
||||
- **Timing**: Adjusted pre-flash script timing for half refresh completion
|
||||
|
||||
### Upstream Merges
|
||||
|
||||
- **PR #522 - HAL Abstraction Layer**: Merged hardware abstraction layer refactor introducing `HalDisplay` and `HalGPIO` classes, decoupling application code from direct hardware access
|
||||
- **PR #603 - Sunlight Fading Fix**: Added user-toggleable setting to turn off display between refreshes, mitigating the sunlight fading issue on e-ink displays
|
||||
- New "Sunlight Fading Fix" toggle in Display settings (OFF/ON)
|
||||
- Passes `turnOffScreen` parameter through display stack when enabled
|
||||
|
||||
### Files Changed
|
||||
|
||||
- `src/main.cpp` - flash screen fixes, cover buffer free on File Transfer entry, fading fix integration
|
||||
- `scripts/pre_flash.py` - timing adjustments for full refresh
|
||||
- `src/network/CrossPointWebServer.cpp` - JSON batching, removed MD5 from listings
|
||||
- `src/network/CrossPointWebServer.h` - removed md5 from FileInfo, simplified sendContentSafe
|
||||
- `src/activities/network/CrossPointWebServerActivity.cpp` - QR code caching
|
||||
- `src/activities/network/CrossPointWebServerActivity.h` - QR code cache members
|
||||
- `src/activities/network/WifiSelectionActivity.cpp` - WiFi scan memory optimization
|
||||
- `lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp` - flush buffer before style changes
|
||||
- `lib/hal/HalDisplay.h` - new HAL abstraction for display (PR #522), turnOffScreen parameter (PR #603)
|
||||
- `lib/hal/HalDisplay.cpp` - HAL display implementation with fading fix passthrough
|
||||
- `lib/hal/HalGPIO.h` - new HAL abstraction for GPIO (PR #522)
|
||||
- `lib/hal/HalGPIO.cpp` - HAL GPIO implementation
|
||||
- `lib/GfxRenderer/GfxRenderer.h` - updated for HAL layer, added fadingFix member
|
||||
- `lib/GfxRenderer/GfxRenderer.cpp` - updated for HAL layer, passes fadingFix to display
|
||||
- `src/CrossPointSettings.h` - added fadingFix setting
|
||||
- `src/CrossPointSettings.cpp` - fadingFix persistence
|
||||
- `src/activities/settings/SettingsActivity.cpp` - added Sunlight Fading Fix toggle
|
||||
- `open-x4-sdk` - updated submodule with turnOffScreen support in EInkDisplay
|
||||
|
||||
---
|
||||
|
||||
## ef-1.0.4
|
||||
|
||||
**EPUB Rendering & Stability**
|
||||
|
||||
### New Features
|
||||
|
||||
- **End-of-Book "Start Over"**: Press next at end of book to wrap to first page
|
||||
|
||||
### EPUB Rendering Improvements
|
||||
|
||||
- CSS `margin-left`/`padding-left` parsing for block indentation
|
||||
- Vertical bar and italic styling for blockquotes
|
||||
- Left margin indentation for list items (`<ol>`/`<ul>`)
|
||||
- Fixed ordered lists showing bullets instead of numbers
|
||||
- Fixed nested `<p>` inside `<li>` causing marker on separate line
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **Webserver**: Fixed file listing disconnection issues with flow control
|
||||
- **Webserver**: Memory optimization for File Transfer mode (frees heap before starting)
|
||||
- **Dictionary**: Fixed zip dictionary allocation order for better memory allocation success
|
||||
|
||||
---
|
||||
|
||||
## ef-1.0.3
|
||||
|
||||
**Maintenance Release**
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fixed cppcheck CI failure: removed unused `screenWidth` variable in word selection activity
|
||||
|
||||
---
|
||||
|
||||
## ef-1.0.2
|
||||
|
||||
**Quick Menu Enhancements**
|
||||
|
||||
### New Features
|
||||
|
||||
- **Screen Rotation Toggle**: Quick toggle between Portrait and Landscape CCW directly from the quick menu
|
||||
- Automatically reindexes content for new screen dimensions
|
||||
- Preserves reading position via content offset restoration
|
||||
- **Customizable Menu Order**: Reorder quick menu items to your preference
|
||||
- New "Edit List Order" option at bottom of menu
|
||||
- Pick-and-place reordering: select item, navigate to destination, place
|
||||
- Order persists across sessions
|
||||
|
||||
### UI Improvements
|
||||
|
||||
- Added navigation button hints to quick menu (prev/next on front buttons, up/down on side buttons)
|
||||
- Fixed orientation-aware margins for button hint areas in landscape modes
|
||||
- New default menu order: Bookmark, Dictionary, Rotate Screen, Settings, Clear Cache
|
||||
|
||||
---
|
||||
|
||||
## ef-1.0.1
|
||||
|
||||
**Dictionary Stability & UX Improvements**
|
||||
|
||||
### Bug Fixes - Stability
|
||||
|
||||
- Fixed dictionary crashes caused by heap fragmentation from repeated page navigation
|
||||
- Refactored TextBlock/ParsedText from `std::list` to `std::vector`, reducing heap allocations by ~12x per TextBlock
|
||||
- Affects EPUB reader page rendering, dictionary definition display, and word selection
|
||||
- Contiguous memory improves cache locality during text layout and reduces heap fragmentation on the memory-constrained ESP32
|
||||
- Added uncompressed dictionary (`.dict`) support to avoid decompression memory issues with large dictzip chunks (58KB chunks -> direct read)
|
||||
- Implemented chunked on-demand HTML parsing for large definitions, parsing pages as user navigates rather than all at once
|
||||
- Limited cached pages to 4 with re-parse capability for backward navigation beyond cache window
|
||||
- Fixed double-button press bug when loading new dictionary chunks
|
||||
|
||||
### Bug Fixes - UI/Layout
|
||||
|
||||
- Restored proper orientation-aware button hint spacing (front: 45px, side: 50px)
|
||||
- Added side button hints to definition screen with "<" / ">" labels for page navigation
|
||||
- Added side button hints to word selection screen ("UP"/"DOWN" labels, borderless, small font)
|
||||
- Added side button hints to dictionary menu ("< Prev", "Next >")
|
||||
- Moved page indicator up to avoid bezel cutoff in landscape orientations
|
||||
|
||||
---
|
||||
|
||||
## ef-1.0.0
|
||||
|
||||
**First Official Release** (previously ef-0.15.99)
|
||||
|
||||
First milestone release of the crosspoint-ef fork, building on CrossPoint Reader 0.15.0 with 14+ major new features and enhancements.
|
||||
|
||||
### New Features
|
||||
|
||||
- **Dictionary Support**: Offline StarDict dictionary with word selection from reader, fast prefix-indexed search, rich HTML formatting, and multi-page pagination
|
||||
- **Bookmark System**: Per-book bookmarks with visual folded-corner indicators, dedicated management interface, and auto-generated bookmark names
|
||||
- **Quick Menu**: In-reader quick access menu for common actions (Dictionary, Bookmark, Clear Cache, Settings) via short power button press
|
||||
- **Library Search**: Search across all books by title, author, or filename with dynamic character picker and weighted relevance scoring
|
||||
- **CSS Support**: Parse and apply CSS styles from EPUB stylesheets (text-align, font-style, font-weight, text-decoration, margins, padding)
|
||||
- **Inline Image Support**: PNG and Baseline JPEG rendering within EPUB content with 2-bit grayscale dithering and caching
|
||||
- **Custom Fonts**: Atkinson Hyperlegible Next (low-vision readers) and Fern Micro (small screens)
|
||||
- **Enhanced Web Server**: File management (upload, download, delete, rename, copy, move, mkdir), companion app API, WebSocket uploads, mDNS discovery at `crosspoint.local`
|
||||
- **Reading Lists**: Create, manage, and pin custom book lists with web API support (CSV format)
|
||||
- **Enhanced Tab Bar**: Unified tab bar with horizontal scrolling and overflow indicators (Recent, Lists, Bookmarks, Search, Files)
|
||||
- **Progress Bar Status**: Additional status bar option showing visual reading progress
|
||||
- **OPDS Browser Enhancements**: Navigation history, page skipping (hold Up/Down), error retry, HTTP Basic Auth support
|
||||
|
||||
### Display Enhancements
|
||||
|
||||
- **High Contrast Mode**: System-wide contrast adjustment
|
||||
- **Bezel Compensation**: Configurable margin (0-10px) for physical screen edge defects
|
||||
- **Sleep Screen Improvements**: Edge-aware color filling for seamless letterbox appearance
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fixed device hanging when booted without USB connected (Serial.available()/Serial.read() called without Serial.begin())
|
||||
- Fixed grayscale state corruption causing ghosting artifacts when anti-aliasing enabled under memory pressure
|
||||
- Memory optimization with graceful degradation when memory is low
|
||||
|
||||
### Development Tools
|
||||
|
||||
- `pre_flash.py`: Displays "Flashing firmware..." screen during upload
|
||||
- `debugging_monitor.py`: Enhanced serial monitor with memory graphs
|
||||
- `pio_helper.py`: Interactive PlatformIO workflow helper
|
||||
|
||||
---
|
||||
|
||||
## Differences from Upstream 0.16.0
|
||||
|
||||
This fork is based on upstream 0.15.0. The following 0.16.0 features are not included:
|
||||
|
||||
- KOReader sync support
|
||||
- Non-English hyphenation patterns (Spanish, German, French, Russian)
|
||||
- XTC/XTCH file format support
|
||||
|
||||
See [crosspoint-ef-features.md](docs/crosspoint-ef-features.md) for complete feature documentation.
|
||||
@ -22,8 +22,7 @@ void EpdFont::getTextBounds(const char* string, const int startX, const int star
|
||||
const EpdGlyph* glyph = getGlyph(cp);
|
||||
|
||||
if (!glyph) {
|
||||
// TODO: Replace with fallback glyph property?
|
||||
glyph = getGlyph('?');
|
||||
glyph = getGlyph(REPLACEMENT_GLYPH);
|
||||
}
|
||||
|
||||
if (!glyph) {
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
#include <cstdint>
|
||||
|
||||
/// Font data stored PER GLYPH
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint8_t width; ///< Bitmap dimensions in pixels
|
||||
uint8_t height; ///< Bitmap dimensions in pixels
|
||||
@ -14,9 +13,7 @@ typedef struct {
|
||||
int16_t top; ///< Y dist from cursor pos to UL corner
|
||||
uint16_t dataLength; ///< Size of the font data.
|
||||
uint32_t dataOffset; ///< Pointer into EpdFont->bitmap
|
||||
bool compressed;
|
||||
} EpdGlyph;
|
||||
#pragma pack(pop)
|
||||
|
||||
/// Glyph interval structure
|
||||
typedef struct {
|
||||
|
||||
@ -33,23 +33,10 @@
|
||||
#include <builtinFonts/notosans_18_bolditalic.h>
|
||||
#include <builtinFonts/notosans_18_italic.h>
|
||||
#include <builtinFonts/notosans_18_regular.h>
|
||||
#include <builtinFonts/opendyslexic_10_bold.h>
|
||||
#include <builtinFonts/opendyslexic_10_bolditalic.h>
|
||||
#include <builtinFonts/opendyslexic_10_italic.h>
|
||||
#include <builtinFonts/opendyslexic_10_regular.h>
|
||||
#include <builtinFonts/opendyslexic_12_bold.h>
|
||||
#include <builtinFonts/opendyslexic_12_bolditalic.h>
|
||||
#include <builtinFonts/opendyslexic_12_italic.h>
|
||||
#include <builtinFonts/opendyslexic_12_regular.h>
|
||||
#include <builtinFonts/opendyslexic_14_bold.h>
|
||||
#include <builtinFonts/opendyslexic_14_bolditalic.h>
|
||||
#include <builtinFonts/opendyslexic_14_italic.h>
|
||||
#include <builtinFonts/opendyslexic_14_regular.h>
|
||||
#include <builtinFonts/opendyslexic_8_bold.h>
|
||||
#include <builtinFonts/opendyslexic_8_bolditalic.h>
|
||||
#include <builtinFonts/opendyslexic_8_italic.h>
|
||||
#include <builtinFonts/opendyslexic_8_regular.h>
|
||||
#include <builtinFonts/ubuntu_10_bold.h>
|
||||
#include <builtinFonts/ubuntu_10_regular.h>
|
||||
#include <builtinFonts/ubuntu_12_bold.h>
|
||||
#include <builtinFonts/ubuntu_12_regular.h>
|
||||
|
||||
// Custom fonts registry (generated by convert-builtin-fonts.sh)
|
||||
#include <builtinFonts/custom/customFonts.h>
|
||||
|
||||
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
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
lib/EpdFont/builtinFonts/custom/FernMicro/FernMicro-Bold.ttf
Normal file
BIN
lib/EpdFont/builtinFonts/custom/FernMicro/FernMicro-Bold.ttf
Normal file
Binary file not shown.
Binary file not shown.
BIN
lib/EpdFont/builtinFonts/custom/FernMicro/FernMicro-Italic.ttf
Normal file
BIN
lib/EpdFont/builtinFonts/custom/FernMicro/FernMicro-Italic.ttf
Normal file
Binary file not shown.
BIN
lib/EpdFont/builtinFonts/custom/FernMicro/FernMicro-Regular.ttf
Normal file
BIN
lib/EpdFont/builtinFonts/custom/FernMicro/FernMicro-Regular.ttf
Normal file
Binary file not shown.
1555
lib/EpdFont/builtinFonts/custom/atkinsonhyperlegiblenext_12_bold.h
Normal file
1555
lib/EpdFont/builtinFonts/custom/atkinsonhyperlegiblenext_12_bold.h
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1588
lib/EpdFont/builtinFonts/custom/atkinsonhyperlegiblenext_12_italic.h
Normal file
1588
lib/EpdFont/builtinFonts/custom/atkinsonhyperlegiblenext_12_italic.h
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1986
lib/EpdFont/builtinFonts/custom/atkinsonhyperlegiblenext_14_bold.h
Normal file
1986
lib/EpdFont/builtinFonts/custom/atkinsonhyperlegiblenext_14_bold.h
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2012
lib/EpdFont/builtinFonts/custom/atkinsonhyperlegiblenext_14_italic.h
Normal file
2012
lib/EpdFont/builtinFonts/custom/atkinsonhyperlegiblenext_14_italic.h
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2393
lib/EpdFont/builtinFonts/custom/atkinsonhyperlegiblenext_16_bold.h
Normal file
2393
lib/EpdFont/builtinFonts/custom/atkinsonhyperlegiblenext_16_bold.h
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2427
lib/EpdFont/builtinFonts/custom/atkinsonhyperlegiblenext_16_italic.h
Normal file
2427
lib/EpdFont/builtinFonts/custom/atkinsonhyperlegiblenext_16_italic.h
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2978
lib/EpdFont/builtinFonts/custom/atkinsonhyperlegiblenext_18_bold.h
Normal file
2978
lib/EpdFont/builtinFonts/custom/atkinsonhyperlegiblenext_18_bold.h
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3018
lib/EpdFont/builtinFonts/custom/atkinsonhyperlegiblenext_18_italic.h
Normal file
3018
lib/EpdFont/builtinFonts/custom/atkinsonhyperlegiblenext_18_italic.h
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
99
lib/EpdFont/builtinFonts/custom/customFonts.h
Normal file
99
lib/EpdFont/builtinFonts/custom/customFonts.h
Normal file
@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Generated by convert-builtin-fonts.sh
|
||||
* Registry of available custom fonts
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <EpdFont.h>
|
||||
#include <EpdFontFamily.h>
|
||||
|
||||
class GfxRenderer;
|
||||
|
||||
#define CUSTOM_FONT_COUNT 2
|
||||
|
||||
static const char* CUSTOM_FONT_NAMES[] = {
|
||||
"AtkinsonHyperlegibleNext",
|
||||
"FernMicro"
|
||||
};
|
||||
|
||||
// Include all custom font headers
|
||||
#include <builtinFonts/custom/atkinsonhyperlegiblenext_12_regular.h>
|
||||
#include <builtinFonts/custom/atkinsonhyperlegiblenext_12_italic.h>
|
||||
#include <builtinFonts/custom/atkinsonhyperlegiblenext_12_bold.h>
|
||||
#include <builtinFonts/custom/atkinsonhyperlegiblenext_12_bolditalic.h>
|
||||
#include <builtinFonts/custom/atkinsonhyperlegiblenext_14_regular.h>
|
||||
#include <builtinFonts/custom/atkinsonhyperlegiblenext_14_italic.h>
|
||||
#include <builtinFonts/custom/atkinsonhyperlegiblenext_14_bold.h>
|
||||
#include <builtinFonts/custom/atkinsonhyperlegiblenext_14_bolditalic.h>
|
||||
#include <builtinFonts/custom/atkinsonhyperlegiblenext_16_regular.h>
|
||||
#include <builtinFonts/custom/atkinsonhyperlegiblenext_16_italic.h>
|
||||
#include <builtinFonts/custom/atkinsonhyperlegiblenext_16_bold.h>
|
||||
#include <builtinFonts/custom/atkinsonhyperlegiblenext_16_bolditalic.h>
|
||||
#include <builtinFonts/custom/atkinsonhyperlegiblenext_18_regular.h>
|
||||
#include <builtinFonts/custom/atkinsonhyperlegiblenext_18_italic.h>
|
||||
#include <builtinFonts/custom/atkinsonhyperlegiblenext_18_bold.h>
|
||||
#include <builtinFonts/custom/atkinsonhyperlegiblenext_18_bolditalic.h>
|
||||
#include <builtinFonts/custom/fernmicro_12_regular.h>
|
||||
#include <builtinFonts/custom/fernmicro_12_italic.h>
|
||||
#include <builtinFonts/custom/fernmicro_12_bold.h>
|
||||
#include <builtinFonts/custom/fernmicro_12_bolditalic.h>
|
||||
#include <builtinFonts/custom/fernmicro_14_regular.h>
|
||||
#include <builtinFonts/custom/fernmicro_14_italic.h>
|
||||
#include <builtinFonts/custom/fernmicro_14_bold.h>
|
||||
#include <builtinFonts/custom/fernmicro_14_bolditalic.h>
|
||||
#include <builtinFonts/custom/fernmicro_16_regular.h>
|
||||
#include <builtinFonts/custom/fernmicro_16_italic.h>
|
||||
#include <builtinFonts/custom/fernmicro_16_bold.h>
|
||||
#include <builtinFonts/custom/fernmicro_16_bolditalic.h>
|
||||
#include <builtinFonts/custom/fernmicro_18_regular.h>
|
||||
#include <builtinFonts/custom/fernmicro_18_italic.h>
|
||||
#include <builtinFonts/custom/fernmicro_18_bold.h>
|
||||
#include <builtinFonts/custom/fernmicro_18_bolditalic.h>
|
||||
|
||||
// Extern EpdFont declarations for custom fonts
|
||||
extern EpdFont atkinsonhyperlegiblenext12RegularFont;
|
||||
extern EpdFont atkinsonhyperlegiblenext12ItalicFont;
|
||||
extern EpdFont atkinsonhyperlegiblenext12BoldFont;
|
||||
extern EpdFont atkinsonhyperlegiblenext12BoldItalicFont;
|
||||
extern EpdFont atkinsonhyperlegiblenext14RegularFont;
|
||||
extern EpdFont atkinsonhyperlegiblenext14ItalicFont;
|
||||
extern EpdFont atkinsonhyperlegiblenext14BoldFont;
|
||||
extern EpdFont atkinsonhyperlegiblenext14BoldItalicFont;
|
||||
extern EpdFont atkinsonhyperlegiblenext16RegularFont;
|
||||
extern EpdFont atkinsonhyperlegiblenext16ItalicFont;
|
||||
extern EpdFont atkinsonhyperlegiblenext16BoldFont;
|
||||
extern EpdFont atkinsonhyperlegiblenext16BoldItalicFont;
|
||||
extern EpdFont atkinsonhyperlegiblenext18RegularFont;
|
||||
extern EpdFont atkinsonhyperlegiblenext18ItalicFont;
|
||||
extern EpdFont atkinsonhyperlegiblenext18BoldFont;
|
||||
extern EpdFont atkinsonhyperlegiblenext18BoldItalicFont;
|
||||
extern EpdFont fernmicro12RegularFont;
|
||||
extern EpdFont fernmicro12ItalicFont;
|
||||
extern EpdFont fernmicro12BoldFont;
|
||||
extern EpdFont fernmicro12BoldItalicFont;
|
||||
extern EpdFont fernmicro14RegularFont;
|
||||
extern EpdFont fernmicro14ItalicFont;
|
||||
extern EpdFont fernmicro14BoldFont;
|
||||
extern EpdFont fernmicro14BoldItalicFont;
|
||||
extern EpdFont fernmicro16RegularFont;
|
||||
extern EpdFont fernmicro16ItalicFont;
|
||||
extern EpdFont fernmicro16BoldFont;
|
||||
extern EpdFont fernmicro16BoldItalicFont;
|
||||
extern EpdFont fernmicro18RegularFont;
|
||||
extern EpdFont fernmicro18ItalicFont;
|
||||
extern EpdFont fernmicro18BoldFont;
|
||||
extern EpdFont fernmicro18BoldItalicFont;
|
||||
|
||||
// Extern EpdFontFamily declarations for custom fonts
|
||||
extern EpdFontFamily atkinsonhyperlegiblenext12FontFamily;
|
||||
extern EpdFontFamily atkinsonhyperlegiblenext14FontFamily;
|
||||
extern EpdFontFamily atkinsonhyperlegiblenext16FontFamily;
|
||||
extern EpdFontFamily atkinsonhyperlegiblenext18FontFamily;
|
||||
extern EpdFontFamily fernmicro12FontFamily;
|
||||
extern EpdFontFamily fernmicro14FontFamily;
|
||||
extern EpdFontFamily fernmicro16FontFamily;
|
||||
extern EpdFontFamily fernmicro18FontFamily;
|
||||
|
||||
// Function to register all custom fonts with the renderer
|
||||
void registerCustomFonts(GfxRenderer& renderer);
|
||||
|
||||
2174
lib/EpdFont/builtinFonts/custom/fernmicro_12_bold.h
Normal file
2174
lib/EpdFont/builtinFonts/custom/fernmicro_12_bold.h
Normal file
File diff suppressed because it is too large
Load Diff
2144
lib/EpdFont/builtinFonts/custom/fernmicro_12_bolditalic.h
Normal file
2144
lib/EpdFont/builtinFonts/custom/fernmicro_12_bolditalic.h
Normal file
File diff suppressed because it is too large
Load Diff
1918
lib/EpdFont/builtinFonts/custom/fernmicro_12_italic.h
Normal file
1918
lib/EpdFont/builtinFonts/custom/fernmicro_12_italic.h
Normal file
File diff suppressed because it is too large
Load Diff
1932
lib/EpdFont/builtinFonts/custom/fernmicro_12_regular.h
Normal file
1932
lib/EpdFont/builtinFonts/custom/fernmicro_12_regular.h
Normal file
File diff suppressed because it is too large
Load Diff
2746
lib/EpdFont/builtinFonts/custom/fernmicro_14_bold.h
Normal file
2746
lib/EpdFont/builtinFonts/custom/fernmicro_14_bold.h
Normal file
File diff suppressed because it is too large
Load Diff
2677
lib/EpdFont/builtinFonts/custom/fernmicro_14_bolditalic.h
Normal file
2677
lib/EpdFont/builtinFonts/custom/fernmicro_14_bolditalic.h
Normal file
File diff suppressed because it is too large
Load Diff
2405
lib/EpdFont/builtinFonts/custom/fernmicro_14_italic.h
Normal file
2405
lib/EpdFont/builtinFonts/custom/fernmicro_14_italic.h
Normal file
File diff suppressed because it is too large
Load Diff
2474
lib/EpdFont/builtinFonts/custom/fernmicro_14_regular.h
Normal file
2474
lib/EpdFont/builtinFonts/custom/fernmicro_14_regular.h
Normal file
File diff suppressed because it is too large
Load Diff
3393
lib/EpdFont/builtinFonts/custom/fernmicro_16_bold.h
Normal file
3393
lib/EpdFont/builtinFonts/custom/fernmicro_16_bold.h
Normal file
File diff suppressed because it is too large
Load Diff
3332
lib/EpdFont/builtinFonts/custom/fernmicro_16_bolditalic.h
Normal file
3332
lib/EpdFont/builtinFonts/custom/fernmicro_16_bolditalic.h
Normal file
File diff suppressed because it is too large
Load Diff
3001
lib/EpdFont/builtinFonts/custom/fernmicro_16_italic.h
Normal file
3001
lib/EpdFont/builtinFonts/custom/fernmicro_16_italic.h
Normal file
File diff suppressed because it is too large
Load Diff
3074
lib/EpdFont/builtinFonts/custom/fernmicro_16_regular.h
Normal file
3074
lib/EpdFont/builtinFonts/custom/fernmicro_16_regular.h
Normal file
File diff suppressed because it is too large
Load Diff
4121
lib/EpdFont/builtinFonts/custom/fernmicro_18_bold.h
Normal file
4121
lib/EpdFont/builtinFonts/custom/fernmicro_18_bold.h
Normal file
File diff suppressed because it is too large
Load Diff
4051
lib/EpdFont/builtinFonts/custom/fernmicro_18_bolditalic.h
Normal file
4051
lib/EpdFont/builtinFonts/custom/fernmicro_18_bolditalic.h
Normal file
File diff suppressed because it is too large
Load Diff
3648
lib/EpdFont/builtinFonts/custom/fernmicro_18_italic.h
Normal file
3648
lib/EpdFont/builtinFonts/custom/fernmicro_18_italic.h
Normal file
File diff suppressed because it is too large
Load Diff
3706
lib/EpdFont/builtinFonts/custom/fernmicro_18_regular.h
Normal file
3706
lib/EpdFont/builtinFonts/custom/fernmicro_18_regular.h
Normal file
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
Loading…
x
Reference in New Issue
Block a user