117 Commits

Author SHA1 Message Date
Dave Allie
fcfa10bb1f Cut release 0.8.0 0.8.0 2025-12-21 19:02:21 +11:00
Arthur Tazhitdinov
febf79a98a Fix: restores cyrillic glyphs to Pixel Arial font (#70)
## Summary

* adds cyrillic glyphs to pixel arial font, used as Small font in UI

## Additional Context

* with recent changes pixel arial font lost cyrillic glyphs
2025-12-21 19:01:11 +11:00
Dave Allie
424104f8ff Fix incorrect justification of last line in paragraph (#90)
## Summary

* Fix incorrect justification of last line in paragraph
* `words` is changing size due to the slice, so `isLastLine` would
rarely be right, either removing justification mid-paragraph, or
including it in the last line.

## Additional Context

* Introduced in #73
2025-12-21 19:01:00 +11:00
Dave Allie
955c78de64 Book cover sleep screen (#89)
## Summary

* Fix issue with 2-bit bmp rendering
* Add support generate book cover BMP from JPG and use as sleep screen

## Additional Context

* It does not support other image formats beyond JPG at this point
* Something is cooked with my JpegToBmpConverter logic, it generates
weird interlaced looking images for some JPGs

| Book 1 | Book 2|
| --- | --- |
|
![IMG_5653](https://github.com/user-attachments/assets/49bbaeaa-b171-44c7-a68d-14cbe42aef03)
|
![IMG_5652](https://github.com/user-attachments/assets/7db88d70-e09a-49b0-a9a0-4cc729b4ca0c)
|
2025-12-21 18:42:06 +11:00
Dave Allie
958508eb6b Prevent boot loop if last open epub crashes on load (#87)
## 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
2025-12-21 18:41:52 +11:00
Sam Davis
6aa5d41a42 Add info about sleep screen customisation to user guide (#88)
## Summary

- Updates user guide with information about using custom sleep screens

## Additional Context

N/A
2025-12-21 18:32:50 +11:00
Dave Allie
2a27c6d068 Add JPG image support (#23)
## Summary

- Add basic JPG image support
- Map JPG back to 2-bit BMP output
- Can be used to later render the BMP file from disk or directly pass to
output if wanted
- Give the 3 passes over the data needed to render grayscale content,
putting it on disk is preferred to outputting it multiple times

## Additional Context

- WIP, looking forward to BMP support from
https://github.com/daveallie/crosspoint-reader/pull/16
- Addresses some of #11
2025-12-21 17:15:17 +11:00
Dave Allie
b73ae7fe74 Paginate book list and avoid out of bounds rendering (#86)
## Summary

* Paginate book list
* Avoid out of bounds rendering of long book titles, truncate with
ellipsis instead

## Additional Context

* Should partially help with
https://github.com/daveallie/crosspoint-reader/issues/75 as it was
previously rendering a lot of content off screen, will need to test with
a large directory
2025-12-21 17:12:53 +11:00
Dave Allie
f264efdb12 Extract EPUB TOC into temp file before parsing (#85)
## Summary

* Extract EPUB TOC into temp file before parsing
* Streaming ZIP -> XML parser uses up a lot of memory as we're
allocating inflation buffers while also holding a few copies of the
buffer in different forms
* Instead, but streaming the inflated file down to the SD card (like we
do for HTML parsing, we can lower memory usage)

## Additional Context

* This should help with
https://github.com/daveallie/crosspoint-reader/issues/60 and
https://github.com/daveallie/crosspoint-reader/issues/10. It won't
remove those class of issues completely, but will allow for many more
books to be opened.
2025-12-21 17:08:34 +11:00
Dave Allie
0d32d21d75 Small code cleanup (#83)
## Summary

* Fix cppcheck low violations
* Remove teardown method on parsers, use destructor
* Code cleanup
2025-12-21 15:43:53 +11:00
Dave Allie
9b4dfbd180 Allow any file to be uploaded (#84)
## Summary

- Allow any file to be uploaded
- Removes .epub restriction

## Additional Context

- Fixes #74
2025-12-21 15:43:17 +11:00
Jonas Diemer
926c786705 Keep ZipFile open to speed up getting file stats. (#76)
Still a bit raw, but gets the time required to determine the size of
each chapter (for reading progress) down from ~25ms to 0-1ms.

This is done by keeping the zipArchive open (so simple ;)).

Probably we don't need to cache the spine sizes anymore then...

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
2025-12-21 14:38:51 +11:00
Dave Allie
299623927e Build out lines when parsing html and holding >750 words in buffer (#73)
## Summary

* Build out lines for pages when holding over 750 buffered words
* Should fix issues with parsing long blocks of text causing memory
crashes
2025-12-21 13:43:19 +11:00
IFAKA
9a3bb81337 fix: add NULL checks after malloc in drawBmp() (#80)
## Problem
`drawBmp()` allocates two row buffers via `malloc()` but doesn't check
if allocations succeed. On low memory, this causes a crash when the NULL
pointers are dereferenced.

## Fix
Add NULL check after both `malloc()` calls. If either fails, log error
and return early.

Changed `lib/GfxRenderer/GfxRenderer.cpp`.

## Test
- Defensive addition only - no logic changes
- Manual device testing appreciated
2025-12-21 13:36:59 +11:00
IFAKA
73d1839ddd fix: add bounds checks to Epub getter functions (#82)
## Problem
Three Epub getter functions can throw exceptions:
- `getCumulativeSpineItemSize()`: No bounds check before
`.at(spineIndex)`
- `getSpineItem()`: If spine is empty and index invalid, `.at(0)` throws
- `getTocItem()`: If toc is empty and index invalid, `.at(0)` throws

## Fix
- Add bounds check to `getCumulativeSpineItemSize()`, return 0 on error
- Add empty container checks to `getSpineItem()` and `getTocItem()`
- Use static fallback objects for safe reference returns on empty
containers

Changed `lib/Epub/Epub.cpp`.

## Test
- Defensive additions - follows existing bounds check patterns
- No logic changes for valid inputs
- Manual device testing appreciated
2025-12-21 13:36:30 +11:00
IFAKA
cc86533e86 fix: add NULL check after malloc in readFileToMemory() (#81)
## Problem
`readFileToMemory()` allocates an output buffer via `malloc()` at line
120 but doesn't check if allocation succeeds. On low memory, the NULL
pointer is passed to `fread()` causing a crash.

## Fix
Add NULL check after `malloc()` for the output buffer. Follows the
existing pattern already used for `deflatedData` at line 141.

Changed `lib/ZipFile/ZipFile.cpp`.

## Test
- Follows existing validated pattern from same function
- Defensive addition only - no logic changes
2025-12-21 13:35:37 +11:00
IFAKA
bf3f270067 fix: add NULL checks for frameBuffer in GfxRenderer (#79)
## Problem
`invertScreen()`, `storeBwBuffer()`, and `restoreBwBuffer()` dereference
`frameBuffer` without NULL validation. If the display isn't initialized,
these functions will crash.

## Fix
Add NULL checks before using `frameBuffer` in all three functions.
Follows the existing pattern from `drawPixel()` (line 11) which already
validates the pointer.

Changed `lib/GfxRenderer/GfxRenderer.cpp`.

## Test
- Follows existing validated pattern from `drawPixel()`
- No logic changes - only adds early return on NULL
- Manual device testing appreciated
2025-12-21 13:34:58 +11:00
Dave Allie
cfe838e03b Update user guide 2025-12-20 01:44:39 +11:00
Dave Allie
7484fe478c Replace cover.jpg 2025-12-20 01:15:20 +11:00
Brendan O'Leary
d41d539435 Add connect to Wifi and File Manager Webserver (#41)
## 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>
2025-12-20 01:05:43 +11:00
Dave Allie
cf6fec78dc Cleanup indexing layout string 2025-12-20 00:33:55 +11:00
Jonas Diemer
10d76dde12 Randomly load Sleep Screen from /sleep/*bmp (if exists). (#71)
Load a random sleep screen. 

Only works for ".bmp" (not ".BMP"), but I think that's OK (we do the
same for EPUBs).
2025-12-20 00:17:26 +11:00
Jonas Diemer
7b5a63d220 Option to short-press power button. (#56)
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>
2025-12-19 23:37:34 +11:00
IFAKA
c1d5f5d562 Add NULL checks after fopen() in ZipFile (#68)
## Problem
Three `fopen()` calls in ZipFile.cpp did not check for NULL before using
the file handle. If files cannot be opened, `fseek`/`fread`/`fclose`
receive NULL and crash.

## Fix
Added NULL checks with appropriate error logging and early returns for
all three locations:
- `getDataOffset()`
- `readFileToMemory()`
- `readFileToStream()`

## Testing
- Builds successfully with `pio run`
- Affects: `lib/ZipFile/ZipFile.cpp`
2025-12-19 23:28:43 +11:00
IFAKA
adfeee063f Handle empty spine in getBookSize() and calculateProgress() (#67)
## Problem
- `getBookSize()` calls `getCumulativeSpineItemSize(getSpineItemsCount()
- 1)` which passes -1 when spine is empty
- `calculateProgress()` then divides by zero when book size is 0

## Fix
- Return 0 from `getBookSize()` if spine is empty
- Return 0 from `calculateProgress()` if book size is 0

## Testing
- Builds successfully with `pio run`
- Affects: `lib/Epub/Epub.cpp`
2025-12-19 23:28:36 +11:00