## Summary
Adds define to omit optional fonts from the build. This reduces time to
flash from >31s to <13s. Useful for development that doesn't require
fonts. Addresses #193
Invoke it like this during development:
`PLATFORMIO_BUILD_FLAGS="-D OMIT_FONTS" pio run --target upload && pio
device monitor`
Changing the define causes `pio` to do a full rebuild (but it will be
quick if you keep the define).
---
### 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? NO
When picking a random sleep image from a set of custom images, compare
the randomly chosen index against a cached value in settings. If the
value matches, use the next image (rolling over if it's the last image).
Cache the chosen image index to settings in either case.
## Summary
Implements a tweak on the custom sleep image feature that ensures that
the user gets a new image every time the device goes to sleep.
This change adds a new setting (perhaps there's a better place to cache
this?) that stores the most recently used file index. During picking the
random image index, we compare this against the random index and choose
the next one (modulo the number of image files) if it matches, ensuring
we get a new image.
## Additional Context
As mentioned, I used settings to cache this value since it is a
persisted store, perhaps that's overkill. Open to suggestions on if
there's a better way.
## Summary
Adds support for browsing and downloading books from a Calibre-web
server via OPDS.
How it works
1. Configure server URL in Settings → Calibre Web URL (e.g.,
https://myserver.com:port I use Cloudflare tunnel to make my server
accessible anywhere fwiw)
2. "Calibre Library" will now show on the the home screen
3. Browse the catalog - navigate through categories like "By Newest",
"By Author", "By Series", etc.
4. Download books - select a book and press Confirm to download the EPUB
to your device
Navigation
- Up/Down - Move through entries
- Confirm - Open folder or download book
- Back - Go to parent catalog, or exit to home if at root
- Navigation entries show with > prefix, books show title and author
- Button hints update dynamically ("Open" for folders, "Download" for
books)
Technical details
- Fetches OPDS catalog from {server_url}/opds
- Parses both navigation feeds (catalog links) and acquisition feeds
(downloadable books)
- Maintains navigation history stack for back navigation
- Handles absolute paths in OPDS links correctly (e.g.,
/books/opds/navcatalog/...)
- Downloads EPUBs directly to the SD card root
Note
The server URL should be typed to include https:// if the server
requires it - HTTP→HTTPS redirects may cause SSL errors on ESP32.
## Additional Context
* I also changed the home titles to use uppercase for each word and
added a setting to change the size of the side margins
---------
Co-authored-by: Dave Allie <dave@daveallie.com>
## 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 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).
---------
Co-authored-by: ratedcounsel <hello@ratedcounsel.com>
Co-authored-by: Dave Allie <dave@daveallie.com>
## Summary
* **What is the goal of this PR?** Fixes#199 - Device falls asleep
during WiFi file transfer after 10 minutes of inactivity, disconnecting
the web server.
* **What changes are included?**
- Add `preventAutoSleep()` virtual method to `Activity` base class
- Modify main loop to reset inactivity timer when `preventAutoSleep()`
returns true
- Override `preventAutoSleep()` in `CrossPointWebServerActivity`
(returns true when web server running)
- Override `preventAutoSleep()` in `OtaUpdateActivity` (returns true
during update check/download)
## Additional Context
* The existing `skipLoopDelay()` method controls loop timing (yield vs
delay) for HTTP responsiveness. The new `preventAutoSleep()` method is
semantically separate - it explicitly signals that an activity should
keep the device awake.
* `CrossPointWebServerActivity` uses both methods: `skipLoopDelay()` for
responsive HTTP handling, `preventAutoSleep()` for staying awake.
* `OtaUpdateActivity` only needs `preventAutoSleep()` since the OTA
library handles HTTP internally.
## Summary
* Update EpdFontFamily::Style to be u8 instead of u32 (saving 3 bytes
per word)
* Update layout width/height to be u16 from int
* Update page element count to be u16 from u32
* Update text block element count to be u16 from u32
* Bumped section bin version to version 8
## Summary
* Swap from Aleo to Bookerly for wider glyph support
* Swap from Space Grotesk to a small Noto Sans
## Additional Context
* 0.11.0 swapped to Aleo which has a few issues (things like Cyrillic
support for eg)
## Summary
* Swap to updated SDCardManager which uses SdFat
* Add exFAT support
* Swap to using FsFile everywhere
* Use newly exposed `SdMan` macro to get to static instance of
SDCardManager
* Move a bunch of FsHelpers up to SDCardManager
## Summary
**What is the goal of this PR?**
Adds a setting to swap the front buttons. The default functionality are:
Back/Confirm/Left/Right. When this setting is enabled they become:
Left/Right/Back/Confirm. This makes it more comfortable to use when
holding in your right hand since your thumb can more easily rest on the
next button. The original firmware has a similar setting.
**What changes are included?**
- Add the new setting.
- Create a mapper to dynamically switch the buttons based on the
setting.
- Use mapper on the various activity screens.
- Update the button hints to reflect the swapped buttons.
## Additional Context
Full disclosure: I used Codex CLI to put this PR together, but did
review it to make sure it makes sense.
Also tested on my device:
https://share.cleanshot.com/k76891NY
## Summary
* **What is the goal of this PR?**
Add a "Continue Reading" feature to improve user experience when
returning to a previously opened book.
* **What changes are included?**
- Add dynamic "Continue: <book name>" menu item in Home screen when a
book was previously opened
- File browser now starts from the folder of the last opened book
instead of always starting from root directory
- Menu dynamically shows 3 or 4 items based on reading history:
- Without history: `Browse`, `File transfer`, `Settings`
- With history: `Continue: <book>`, `Browse`, `File transfer`,
`Settings`
## Additional Context
* This feature leverages the existing `APP_STATE.openEpubPath` which
already persists the last opened book path
* The Continue Reading menu only appears if the book file still exists
on the SD card
* Book name in the menu is truncated to 25 characters with "..." suffix
if too long
* If the last book's folder was deleted, the file browser gracefully
falls back to root directory
* No new dependencies or significant memory overhead - reuses existing
state management
## Summary
* Use single unified cache file for book spine, table of contents, and
core metadata (title, author, cover image)
* Use new temp item store file in OPF parsing to store items to be
rescaned when parsing spine
* This avoids us holding these items in memory
* Use new toc.bin.tmp and spine.bin.tmp to build out partial toc / spine
data as part of parsing content.opf and the NCX file
* These files are re-read multiple times to ultimately build book.bin
## Additional Context
* Spec for file format included below as an image
* This should help with:
* #10
* #60
* #99
## Summary
* Prevent SD card error causing boot loop
* We need the screen and fonts to be initialized to show the full screen
error message
* Prior to this change, trying to render the font would crash the
firmware and boot loop it
Improves the duration for which the power button needs to be held - see
#53.
I left the measurement code for the calibration value in, as it will
likely change if we move the settings to NVS.
## Summary
* Swap from `wasReleased` to `isPressed` when checking power button
duration
* In practice it makes the power down experience feel a lot snappier
* Remove the unnecessary 1000ms delay when powering off
## Additional Context
* A little discussion in here:
https://github.com/daveallie/crosspoint-reader/discussions/53#discussioncomment-15309707
## Summary
* Unset openEpubPath on boot and set once epub fully loaded
## Additional Context
* If an epub was crashing when loading, it was possible to get the
device stuck into a loop. There was no way to get back to the home
screen as we'd always load you back into old epub
* Break this loop by clearing the stored value when we boot, still
jumping to the last open epub, but only resetting that value once the
epub has been fully loaded
## Summary
- **What is the goal of this PR?**
Implements wireless EPUB file management via a built-in web server,
enabling users to upload, browse, organize, and delete EPUB files from
any device on the same WiFi network without needing a computer cable
connection.
- **What changes are included?**
- **New Web Server**
([`CrossPointWebServer.cpp`](src/CrossPointWebServer.cpp),
[`CrossPointWebServer.h`](src/CrossPointWebServer.h)):
- HTTP server on port 80 with a responsive HTML/CSS interface
- Home page showing device status (version, IP, free memory)
- File Manager with folder navigation and breadcrumb support
- EPUB file upload with progress tracking
- Folder creation and file/folder deletion
- XSS protection via HTML escaping
- Hidden system folders (`.` prefixed, "System Volume Information",
"XTCache")
- **WiFi Screen** ([`WifiScreen.cpp`](src/screens/WifiScreen.cpp),
[`WifiScreen.h`](src/screens/WifiScreen.h)):
- Network scanning with signal strength indicators
- Visual indicators for encrypted (`*`) and saved (`+`) networks
- State machine managing: scanning, network selection, password entry,
connecting, save/forget prompts
- 15-second connection timeout handling
- Integration with web server (starts on connect, stops on exit)
- **WiFi Credential Storage**
([`WifiCredentialStore.cpp`](src/WifiCredentialStore.cpp),
[`WifiCredentialStore.h`](src/WifiCredentialStore.h)):
- Persistent storage in `/sd/.crosspoint/wifi.bin`
- XOR obfuscation for stored passwords (basic protection against casual
reading)
- Up to 8 saved networks with add/remove/update operations
- **On-Screen Keyboard**
([`OnScreenKeyboard.cpp`](src/screens/OnScreenKeyboard.cpp),
[`OnScreenKeyboard.h`](src/screens/OnScreenKeyboard.h)):
- Reusable QWERTY keyboard component with shift support
- Special keys: Shift, Space, Backspace, Done
- Support for password masking mode
- **Settings Screen Integration**
([`SettingsScreen.h`](src/screens/SettingsScreen.h)):
- Added WiFi action to navigate to the new WiFi screen
- **Documentation** ([`docs/webserver.md`](docs/webserver.md)):
- Comprehensive user guide covering WiFi setup, web interface usage,
file management, troubleshooting, and security notes
- See this for more screenshots!
- Working "displays the right way in GitHub" on my repo:
https://github.com/olearycrew/crosspoint-reader/blob/feature/connect-to-wifi/docs/webserver.md
**Video demo**
https://github.com/user-attachments/assets/283e32dc-2d9f-4ae2-848e-01f41166a731
## Additional Context
- **Security considerations**: The web server has no
authentication—anyone on the same WiFi network can access files. This is
documented as a limitation, recommending use only on trusted private
networks. Password obfuscation in the credential store is XOR-based, not
cryptographically secure.
- **Memory implications**: The web server and WiFi stack consume
significant memory. The implementation properly cleans up (stops server,
disconnects WiFi, sets `WIFI_OFF` mode) when exiting the WiFi screen to
free resources.
- **Async operations**: Network scanning and connection use async
patterns with FreeRTOS tasks to prevent blocking the UI. The display
task handles rendering on a dedicated thread with mutex protection.
- **Browser compatibility**: The web interface uses standard
HTML5/CSS3/JavaScript and is tested to work with all modern browsers on
desktop and mobile.
---------
Co-authored-by: Dave Allie <dave@daveallie.com>
Adresses #53
Please check if we still need the code to "Give the user up to 1000ms to
start holding the power button, and must hold for
SETTINGS.getPowerButtonDuration()" - the power button should be pressed
already when waking up...
Also, decided to return before the delay to wait more to make the
behavior more immediate.
---------
Co-authored-by: Dave Allie <dave@daveallie.com>
## Problem
`SD.begin()` return value was ignored. If the SD card fails to
initialize, the device continues and crashes when trying to load
settings/state.
## Fix
Check return value and display "SD card error" message instead of
proceeding with undefined state.
## Testing
- Builds successfully with `pio run`
- Affects: `src/main.cpp`
## Summary
* This PR drastically reshapes the structure of the codebase, moving
from the concept of "Screens" to "Activities", restructing the files and
setting up the concept of subactivities.
* This should help with keep the main file clean and containing all
functional logic in the relevant activity.
* CrossPointState is now also a global singleton which should help with
accessing it from within activities.
## Additional Context
* This is probably going to be a bit disruptive for people with open
PRs, sorry 😞
* white sleep screen
* quicker pwr button
* no extra spacing between paragraphs
* Added settings class with de/serialization and whiteSleepScreen setting to control inverting the sleep screen
* Added Settings screen for real, made settings a global singleton
* Added setting for extra paragraph spacing.
* fixed typo
* Rework after feedback
* Fixed type from bool to uint8
* First pass at moving to SDK EInkDisplay library
* Add 2-bit grayscale text and anti-aliased rendering of text
* Render status bar for empty chapters
* Refresh screen every 15 pages to avoid ghosting
* Simplify boot and sleep screens
* Give FileSelectionScreen task more stack memory
* Move text around slightly on Boot and Sleep screens
* Re-use existing buffer and write to whole screen for 'partial update'