Compare commits

...
Author SHA1 Message Date
Justin Mitchell 9cfdaa46a1 Reformat touch reader controls enum definition 2026-08-13 15:51:38 -04:00
Justin Mitchell 58b2f6d41e Move tap for reader menu setting to Controls category
Changed the category of the tapForReaderMenu setting from STR_CAT_READER to STR_CAT_CONTROLS for better organization in the settings UI.
2026-08-13 15:26:33 -04:00
Justin Mitchell 6bf0dd746a Add inverted tap mode for touch reader controls
Adds a new touch control mode that swaps the left/right tap zones, allowing users to navigate forward by tapping the left side and backward by tapping the right side. The inverted behavior is applied when the TOUCH_READER_INVERTED_TAP setting is selected.
2026-08-13 15:21:52 -04:00
Justin Mitchell c0b2d3c2ad Add toggle to disable tap-for-reader-menu gesture
Introduces a new setting 'tapForReaderMenu' that allows users to disable the center-third tap gesture for opening the reader menu. This option is only shown on devices with a capacitive Home key, since those devices can still access the menu via long-press. On devices without a Home key, the tap gesture remains the primary access method and cannot be disabled.
2026-08-13 15:14:41 -04:00
Justin Mitchell 8a4efefe25 Add Reader Menu option for long-press action on homekey boards
Adds a new long-press menu option that opens the reader menu. This option is conditionally available only on boards with a Home key. The new option allows users to configure long-press to open the reader menu directly, which is useful for devices with capacitive Home keys that provide long-press actions.
2026-08-13 03:25:38 -04:00
Justin Mitchell b26bc5d531 Avoid restart on WiFi exit for touch devices
On devices with capacitive touch, external power rails for touch and frontlight are not cycled during software reset. Instead of restarting, cleanly shut down WiFi and SNTP in place to preserve peripheral state. Also handle Home gesture alongside Back button for exit responsiveness in the web server activity.
2026-08-13 03:20:14 -04:00
Justin Mitchell 2b3379569a Add power button confirm action for capacitive touch
Adds PWR_CONFIRM option to short power button settings, allowing the power button to act as a confirm button on capacitive touch devices. Includes special handling for X4 Pro's frontlight double-click window to avoid conflicts.
2026-08-13 03:14:02 -04:00
Justin Mitchell 9ebb824dfd Add Home key long-press action support in reader
Implements long-press detection for the Home key on devices without a front Confirm button. The long-press triggers the user-configured action (bookmark, KOSync, dictionary, or disabled) similar to the Confirm button long-press behavior.
2026-08-13 03:10:11 -04:00
Justin Mitchell 8891d49669 Prevent light sleep when frontlight is active
Add frontlight state check to sleep exclusion conditions to avoid visible flashing caused by LEDC PWM suspension during light sleep cycles. This prevents the ESP from entering light sleep when the frontlight is on, similar to existing WiFi and USB exclusions.
2026-08-13 00:05:01 -04:00
Justin Mitchell 3c3e695340 Add X4 Pro support for recovery mode detection
X4 Pro uses a different button (DOWN instead of UP) and requires shorter debounce time (20ms vs 500ms) for recovery mode detection. The DOWN button is used to avoid GPIO0 boot-strap pin conflicts on X4 Pro hardware.
2026-08-12 23:47:17 -04:00
Justin Mitchell 2a3f08ddcd Add vertical bounds to reader menu tap zone
The tap zone for opening the reader menu now checks both horizontal and vertical bounds, restricting it to the center third of the screen in both dimensions. Previously only horizontal bounds were checked, allowing taps anywhere vertically in the middle third horizontally to open the menu.
2026-08-12 23:30:47 -04:00
Justin Mitchell 4ff215f4e1 Merge branch 'develop' into feat-x4-papermono-support
# Conflicts:
#	src/activities/settings/SettingsActivity.cpp
2026-08-12 23:16:56 -04:00
Justin Mitchell 9361115e46 Skip power button hold verification for X4 Pro
X4 Pro wakes on any power button press, so it should bypass the hold-duration verification like boards without a power button. This ensures the wake is treated as valid immediately.
2026-08-12 23:16:22 -04:00
Justin Mitchell 9b1fb712de fix: Guard GPIO13 power control for Xteink C3 boards only (#2998) 2026-08-12 22:06:52 -04:00
Justin Mitchell e715532f90 fix: settings UI not updating after language change & line height padding (#2997) 2026-08-12 21:32:03 -04:00
Justin Mitchell 1020f66723 Merge remote-tracking branch 'origin/develop' into feat-x4-papermono-support 2026-08-12 21:13:26 -04:00
Brian Pugh 70faa29dac perf: light-sleep idle + refresh downclock — ~3.2x active reading time (X3-measured) (#2525)
## Summary

Reduces active-reading power draw ~3.2x, measured end-to-end on an X3
with a [Nordic
PPK2](https://www.nordicsemi.com/Products/Development-hardware/Power-Profiler-Kit-2)
at the battery terminals (slim build, USB cable removed, 3.8v). Three
independent changes:

1. **Light-sleep between input polls when idle** (the big one): after 1
s of inactivity the main loop replaces its busy `delay(50)` with 50 ms
timer-paced `esp_light_sleep_start()` slices. Poll cadence and input
latency are unchanged — the CPU sleeps between polls instead of spinning
at 10 MHz. Guards: never sleeps while a `HalPowerManager::Lock` is held
(render in flight), WiFi is up, or USB is connected (light sleep kills
the CDC link).
2. **Two-stage idle backoff**: downclock at 500 ms, light sleep at 1 s,
replacing the flat 3 s full-speed window. Renders re-raise the clock via
`Lock` the moment they start, so the full-speed tail only ever served
loop bookkeeping. (The 3 s value in #852 was a placeholder;
responsiveness verified on device against stock.)
3. **Refresh BUSY-wait downclock**: drops the CPU to 10 MHz while
`pollBusy()` polls the BUSY pin (0.3–2 s per refresh), via new optional
hooks in the SDK — **depends on Free-Ink/freeink-sdk/pull/8**. Plus a 1
Hz throttle on the X3's I2C-based USB detection (was polled every loop).

(1+2) reduced average static-page-current from 9.68mA to 3.45mA.
Reducing the battery-monitor polling frequency further reduced it to
2.78mA.

Before merging, we'll need to update the submodule reference.

## Measured results (PPK2, X3)

| Metric | Before | After |
|---|---|---|
| Idle on a static page | 9.68 mA | **2.78 mA** |
| Fast page turn (incl. post-turn behavior) | ~100 mC | **28.98 mC** |
| Post-turn 160 MHz tail | 21.2 mA x 3 s | eliminated |
| Session average @ 30 s/page | ~11.6 mA | **~3.6 mA (~3.2x reading
time)** |
| Deep sleep | 12.8 µA | unchanged |

## Typical-day profiles

Assuming someone spends 30s per page.

- **Light**: 1 h reading, 10 lock/wake cycles, remaining ~23 h deep
sleep
- **Heavy**: 2 h reading, 20 lock/wake cycles, remaining ~22 h deep
sleep
- Per-day cost components: reading 11.6 → 3.6 mA (session avg),
lock+wake cycle
0.113 → 0.099 mAh each (sleep-screen mode), deep sleep 12.8 µA
(unchanged,
  ~0.29 mAh/day)
- Excluded: WiFi sessions, cold chapter indexing, self-discharge

### Days per charge (650mAh)

| Profile | Before | After | Ratio |
|---|---|---|---|
| Light (1 h/day, 10 locks) | 13.0 mAh/day → ~50 days | 4.9 mAh/day →
~133 days | 2.7Ă— |
| Heavy (2 h/day, 20 locks) | 25.7 mAh/day → ~25 days | 9.5 mAh/day →
~68 days | 2.7Ă— |
| Pure active reading | 11.6 mA → ~56 h | 3.6 mA → ~180 h | 3.2× |

### Caveats

- "After" saturates in reality: Li-ion self-discharge (~2–3%/month) is
not modeled
  and becomes the limiter once firmware draw is this low.
- Faster page-turners trend toward ~2.8Ă—, slower readers slightly above
3.2Ă—.
- Frequent locking dilutes the ratio (wake = full cold boot, barely
touched by the
power branch): at 10–20 locks/day, cycles are ~20% of the "after"
budget.
---

### 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**_

---------
2026-08-12 20:57:45 -04:00
Justin Mitchell 144f5740db fix: install full penv_setup dependency set for espressif32 builds
platform-espressif32's own penv bootstrap isn't reliably installing
its required python packages in this runner image, so pin the full
list (littlefs-python, fatfs-ng, and friends) explicitly instead of
discovering missing modules one build at a time.
2026-08-12 18:50:17 -04:00
Justin Mitchell 7d15decbc6 fix: install littlefs-python for PlatformIO CI builds
pioarduino's espressif32 builder imports littlefs unconditionally,
which was never installed alongside platformio-core, breaking every
build and cppcheck job.
2026-08-12 18:42:25 -04:00
Justin Mitchell a30d59ef97 Downgrade CI Python version from 3.14 to 3.13
Update all GitHub Actions workflows to use Python 3.13 instead of 3.14, likely due to 3.14 not being available or stable yet.
2026-08-12 18:22:02 -04:00
Justin Mitchell af3fe731ca Add grayscale base display handling for e-ink panels
Introduce displayBaseWithRefreshCycle to handle B/W base layer display differently for panels that combine grayscale bases vs those that don't. Panels with combined bases defer activation to avoid visible flashing when grayscale pass re-drives text. Also add cleanup call to flush deferred activations for combined-base panels.
2026-08-12 18:10:30 -04:00
Justin Mitchell e9eb7b8d6d Add combined grayscale base rendering for Paper Mono
Implements a new rendering path for Paper Mono displays that defers base activation so grayscale planes can be combined with the base in a single waveform. This prevents visible flashing that occurs when the base is displayed separately and the gray pass re-drives the text body. The feature is controlled by combinesGrayscaleBase() checks throughout the rendering pipeline.
2026-08-12 18:04:02 -04:00
Justin Mitchell a97e850279 Add matrix build for multiple board variants
Consolidates duplicate build jobs into a single matrix-based job that builds firmware for default, sticky, x4pro, and papermono boards. Adds a new release workflow that builds all board variants with release-specific environments when tags are pushed. Artifacts are named to match OtaUpdater's expected format (firmware.bin for C3, firmware-<board>.bin for others).
2026-08-12 17:59:47 -04:00
Leopoldo Pla SempereandJulia Nguyen cb995809ba fix: backport File Transfer guard from CrossInk (#2990)
Co-authored-by: Julia Nguyen <julia@uxj.io>
2026-08-13 00:19:03 +03:00
Uri Tauber f16451c729 feat: render HTML dictionary definitions via EPUB engine (#2836) 2026-08-12 17:17:25 -04:00
Justin Mitchell 4af91daaee Remove manual row height scaling for wrapped labels
The list() function now handles per-row sizing for wrapped items automatically, so manual scaling of row height by line count is no longer needed. Updated comments to reflect that wrapped labels grow only their own row while dense height is preserved for other rows.
2026-08-12 17:01:05 -04:00
Justin Mitchell 595edde489 Add back-to-file-browser setting to settings list
Include STR_BACK_SHORT_TO_FILE_BROWSER in the settings condition check alongside the existing sunlight fading fix setting.
2026-08-12 16:39:44 -04:00
Justin Mitchell 788e1d5901 Merge branch 'feat-x4-papermono-support' of https://github.com/crosspoint-reader/crosspoint-reader into feat-x4-papermono-support 2026-08-12 16:35:13 -04:00
Justin Mitchell 1c4ded42ff Scale list row height by label line count
When a list label can wrap to multiple lines, scale the entire row height by the label's maxLines instead of flooring against the raw font line-height. This preserves the theme's proportional padding for dense rows and prevents wrapped text from bleeding into the next row. Applied to UiListActivity, UiTabListActivity, and WifiSelectionActivity (list/tab/wifi selection screens) replacing the previous wrappedMin floor logic with rowHeight *= maxLines for labelText.maxLines > 1.
2026-08-12 16:34:29 -04:00
Leopoldo Pla SempereandPablo Cabeza 268c27f7d0 feat: add transparent sleep overlays (#2937)
Co-authored-by: Pablo Cabeza <josepablocg@gmail.com>
2026-08-12 23:21:43 +03:00
Justin Mitchell 6c2be7bb1e Reformat multi-line expressions for consistency
Adjust line breaks in WifiSelectionActivity and FrontlightPanelActivity to improve code formatting consistency. No functional changes.
2026-08-12 16:04:56 -04:00
Justin Mitchell a6db9c7bab Persist frontlight 'on' only if user changed
Add a lightOnChanged flag to FrontlightPanelActivity (src/activities/util/FrontlightPanelActivity.h) and initialize it in onEnter. Set the flag whenever the user toggles the light or adjustments implicitly turn it on. onExit now only updates SETTINGS.frontlightOn when lightOnChanged is true; brightness/warmth continue to be persisted as before. This avoids overwriting the saved "was on" preference with the live hardware state when the user didn't interact with the control.
2026-08-12 16:04:21 -04:00
Justin Mitchell 30a3137a69 Ensure list rows accommodate wrapped labels
Floor list row heights to the label's required lines where labels may wrap. UiListActivity, UiTabListActivity and WifiSelectionActivity now compute a wrappedMin = lineHeight * maxLines and increase rowHeight if needed to prevent the second wrapped line from bleeding into the next row. Also update SettingsActivity's language selection flow to save settings and rebuild the settings lists on return so row labels reflect the new language immediately.
2026-08-12 15:37:16 -04:00
Uri Tauber b1d53ba810 feat: add orangutan translation (#2992)
Translated by Dr Horace Worblehat, B. Thau, D.M.
2026-08-12 22:18:39 +03:00
Justin Mitchell f55580888f Add XteinkX3Uc8279 board to GPIO configuration
Include XteinkX3Uc8279 board in the active board check condition for GPIO handling.
2026-08-12 14:34:40 -04:00
Justin Mitchell 96dd6f6d6e Add bounds check before accessing recent books list
Clear rowItems before bounds checking to prevent accessing stale row indices. The interaction table can deliver row indices captured before list modifications, so validate the index is within current list bounds before proceeding.
2026-08-12 14:30:59 -04:00
Justin Mitchell 6953859576 Merge remote-tracking branch 'origin/develop' into feat-x4-papermono-support
# Conflicts:
#	freeink-sdk
#	src/MappedInputManager.cpp
#	src/MappedInputManager.h
#	src/activities/reader/EpubReaderMenuActivity.cpp
#	src/activities/reader/EpubReaderMenuActivity.h
#	src/activities/reader/ReaderUtils.h
#	src/activities/settings/OpdsServerListActivity.cpp
#	src/activities/settings/OpdsSettingsActivity.cpp
#	src/components/OptionPopup.h
#	src/components/UiAppHelpers.h
#	src/components/UiAppHost.cpp
#	src/components/UiAppHost.h
#	src/components/themes/BaseTheme.cpp
2026-08-12 13:51:39 -04:00
Justin Mitchell 35be6872a2 Remove duplicate screenInverted setting 2026-08-12 00:45:51 -04:00
Justin Mitchell 4baa19f05a Remove setInverted method from HalDisplay
Removes the setInverted method that was wrapping einkDisplay.setInverted. Callers should use the underlying einkDisplay method directly if needed.
2026-08-12 00:29:51 -04:00
Justin Mitchell fd281a5351 Remove duplicate night mode translation string 2026-08-12 00:21:11 -04:00
Justin Mitchell 55fe65e06b Merge remote-tracking branch 'origin/develop' into feat-x4-papermono-support 2026-08-12 00:19:27 -04:00
Justin Mitchell 72404c20af Update freeink-sdk submodule
Update freeink-sdk submodule from c1d96ba to 65d9eba.
2026-08-12 00:14:23 -04:00
Justin Mitchell ddc4c6a250 Add frontlight restore setting and X4 Pro toggle
Add optional setting to restore frontlight on/off state after wake (brightness/warmth always restored). Implement double-click power button to toggle frontlight on X4 Pro. Silent reboots preserve light state regardless of setting to avoid unexpected darkness.
2026-08-12 00:12:54 -04:00
Justin Mitchell b76b999266 Add frontlight control and display inversion support
Implements HalFrontlight wrapper around SDK frontlight manager with brightness, warmth, and on/off controls. Adds display inversion methods to HalDisplay. Includes special power management for PaperMono device using M5PM1 PMIC for shutdown. Adds corresponding UI strings for night mode and frontlight settings.
2026-08-12 00:10:53 -04:00
Justin Mitchell 2780802830 Add capacitive Home key support for X4 Pro
Implements Home key detection through the touch controller for X4 Pro hardware. The Home gesture now checks for a capacitive Home key tap if available, falling back to the bottom-edge swipe gesture on devices without the key. Also adds X4 Pro device detection and display controller probing.
2026-08-11 23:48:37 -04:00
Justin Mitchell 6b5600cd3b Return to reader menu when cancelling sub-screens
When users cancel (via Back button/gesture) from menu-launched sub-screens like text settings or footnotes, return them to the reader menu instead of the reading surface. This provides more intuitive navigation flow. Home gesture exits are unaffected as ActivityManager handles the stack.
2026-08-11 23:04:05 -04:00
Justin Mitchell cccdea96f4 Reformat array initializers for consistency
Adjust whitespace and line breaks in array initializer lists across settings activities to improve code formatting consistency. No functional changes.
2026-08-11 22:50:54 -04:00
Justin Mitchell 3c83f45f93 Cache list row data to avoid per-render allocations
Prebuild and cache ListItem/label buffers for list screens to eliminate repeated per-render heap allocations. Many activities were changed to build rowItems/rowLabels/rowValues once (on construction, onEnter(), or when data changes) and reuse them during paint: OpdsBookBrowser, RecentBooks, NetworkModeSelection, EndOfBookOptions, EpubReaderFootnotes, EpubReaderMenu, XtcReaderChapterSelection, FontDownload, KOReaderSettings, LanguageSelect, OpdsServerList, OpdsSettings, Settings, StatusBarSettings, and TextSettings. Added rebuildRowItems()/rowsDirty_ flags and fixed-capacity arrays where appropriate (NetworkModeSelection, KOReader, etc.). Behavior unchanged; this reduces CPU and heap churn during repaints.
2026-08-11 22:44:00 -04:00
Justin Mitchell ae478fb179 Clarify FUI row-cache guidance
Updates the touch/UI contribution guide to recommend activity-owned row caches for FUI list screens. It adds a concrete rebuildRows pattern, points contributors to FileBrowserActivity for the real-world implementation, and explains why per-render std::vector allocations are avoidable and harmful to steady-state rendering.
2026-08-11 22:13:48 -04:00
Justin Mitchell ee4db8e1fd Preserve denser list rows on non-touch devices
Restore the pre-FreeInkUI list density for non-touch hardware by selecting denser theme metrics where appropriate.

- Added optional hasSubtitle parameter to UiListActivity::syncListViewport and UiTabListActivity::syncTabListViewport so callers can choose subtitle-aware row heights.
- When mappedInput/gpio reports no touch, activities now override props.rowHeight with UITheme metrics (listRowHeight or listWithSubtitleRowHeight) so lists show more rows on X3/X4 devices.
- Updated callers across activities (RecentBooks, Network/WiFi screens, bookmarks, font/opds lists, reader actions, etc.) and added necessary includes.

This keeps touch-target sizing for touch devices while restoring denser layouts on non-touch hardware.
2026-08-11 22:08:19 -04:00
Justin Mitchell 3702925755 Cache list rows/strings for list screens
Introduce cached row buffers to avoid composing strings and allocating ListItems on every repaint. Added networkStatuses/networkRowItems + rebuildNetworkRowItems() (WifiSelectionActivity.cpp/.h), bookmarkSubtitles/bookmarkRowItems + rebuildBookmarkRowItems() (EpubReaderBookmarksActivity.cpp/.h), and tocLabels/tocRowItems + buildTocRowItems() (EpubReaderChapterSelectionActivity.cpp/.h). buildScreen() now reuses these cached arrays; caches are rebuilt when underlying data changes (scan results, bookmark delete, onEnter for TOC). Reduces per-frame allocations and CPU work during cursor moves/taps.
2026-08-11 18:09:14 -04:00
Justin Mitchell a4edce3961 Cache file-list rows to avoid per-render allocs
Add cached per-row buffers (rowNames, rowExtensions, rowItems) and rebuildRowItems() to FileBrowserActivity. loadFiles() now populates/clears the cache and error paths call rebuildRowItems(); buildScreen() reuses cached rowItems and invalidates them on theme change. Caches are cleared in onExit(). Changes in src/activities/home/FileBrowserActivity.h and .cpp. This prevents allocating hundreds of strings/ListItem objects on every repaint for large directories, reducing heap churn and improving UI responsiveness.
2026-08-11 17:58:06 -04:00
Justin Mitchell 07b27ff6df Restore popup borders in option dialogs
Explicitly apply themed popup border styles in the Wi‑Fi prompt and generic option popup dialogs. This restores the missing frame around option dialogs by setting the same border color, thickness, and corner radius used by the theme metrics, matching the prior OptionPopup rendering and keeping the UI consistent.
2026-08-11 16:50:54 -04:00
Justin Mitchell 3198b293f3 Clarify list data flow with improved comments
Rename 'items' to 'entries' to distinguish activity data from transient render items. Add comments explaining that 'entries' holds loaded data while 'rows' is the per-render vector of ListItems passed to the UI component.
2026-08-10 15:33:28 -04:00
Justin Mitchell bba8c21b1a Use UI font for titles in all builds
Remove OMIT_FONTS conditional and always use UI_FONT_ID for titles instead of NOTOSANS_14_FONT_ID. UI fonts provide better script coverage (Hebrew, CJK) for book and directory titles, matching the font used in develop's drawHeader.
2026-08-10 15:26:41 -04:00
Justin Mitchell 6dea6b31f4 Deprecate touch bridge helpers in favor of FreeInkUI
Mandate FreeInkUI components for all new screens. The old touch bridge helpers (rowTouch, colTouch, wasTapInRect, manual rect contains checks) are now legacy-only and must not appear in new code. Document the four supported host patterns: UiListActivity, UiTabListActivity, UiAppHost, and OptionPopup.
2026-08-10 15:16:36 -04:00
Justin Mitchell fc6d11fdd8 Fix input handling race conditions and edge cases
Add assertions for tab navigation bounds checking. Fix confirm button handling to only swallow release when button is actually pressed, preventing touch input from being incorrectly consumed. Add fromButton parameter to distinguish physical button presses from touch taps. Hide action hints when recent books list is empty. Add atomic synchronization for end-of-book options menu to prevent race conditions. Handle case where section is dropped during pending page turn.
2026-08-10 14:29:09 -04:00
Justin Mitchell daf7937b68 Refactor UiListActivity to inherit from UiAppHost
Extract common UI app hosting logic into UiAppHost base class. UiListActivity now inherits from UiAppHost instead of duplicating the render target, FreeInkApp, and uiReady handshake logic. Simplifies touch routing by delegating to parent class and renames routeTouch to routeListTouch to avoid name hiding.
2026-08-10 13:54:09 -04:00
Justin Mitchell 502335693d Replace custom touch handling with ConfirmPopup
Refactor OtaUpdateActivity to use the standard ConfirmPopup component instead of custom touch rectangle handling and button rendering. Also configure WifiSelectionActivity to use vertical options layout with multi-line text wrapping to prevent label truncation.
2026-08-10 13:19:37 -04:00
Justin Mitchell 9e6578f61c Replace custom prompt rendering with dialog component
Refactor WiFi save and forget prompts to use the FreeInkApp dialog system instead of custom touch handling and rendering. Moves prompt logic into event handlers that interact with the dialog action system, simplifying the code and improving consistency with the UI framework.
2026-08-10 00:48:06 -04:00
Justin Mitchell 36085d80db Convert all lists and tabs to FUI 2026-08-09 23:31:47 -04:00
76 changed files with 3227 additions and 457 deletions

No files matched your search

+45 -62
View File
@@ -18,7 +18,7 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: '3.14'
python-version: '3.13'
- name: Install clang-format-21
run: |
@@ -42,7 +42,7 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: '3.14'
python-version: '3.13'
- name: Install uv
uses: astral-sh/setup-uv@v7
@@ -51,7 +51,15 @@ jobs:
enable-cache: false
- name: Install PlatformIO Core
run: uv pip install --system -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.19.zip
run: |
uv pip install --system -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.19.zip
# platform-espressif32's builder/main.py imports these unconditionally; its own
# penv bootstrap (builder/penv_setup.py) is supposed to install them automatically
# but isn't picking them up reliably in this runner image, so pin them explicitly.
uv pip install --system -U "littlefs-python>=0.16.0" "fatfs-ng>=0.1.14" "pyyaml>=6.0.2" \
"rich-click>=1.8.6" "zopfli>=0.2.2" "intelhex>=2.3.0" "rich>=14.0.0" "urllib3<2" \
"cryptography>=45.0.3" "certifi>=2025.8.3" "ecdsa>=0.19.1" "bitstring>=4.3.1" \
"reedsolo>=1.5.3,<1.8" "esp-idf-size>=2.0.0" "esp-coredump>=1.14.0"
- name: Cache PlatformIO packages
uses: actions/cache@v4
@@ -63,9 +71,24 @@ jobs:
- name: Run cppcheck
run: pio check --fail-on-defect low --fail-on-defect medium --fail-on-defect high
build-default:
name: Build default
build:
name: Build ${{ matrix.env }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Artifact names match the release asset names OtaUpdater requests:
# plain firmware.bin for the C3 X4/X3 binary, firmware-<board>.bin for
# the S3 boards.
include:
- env: default
asset: firmware.bin
- env: sticky
asset: firmware-sticky.bin
- env: x4pro
asset: firmware-x4pro.bin
- env: papermono
asset: firmware-papermono.bin
steps:
- uses: actions/checkout@v6
with:
@@ -73,7 +96,7 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: '3.14'
python-version: '3.13'
- name: Install uv
uses: astral-sh/setup-uv@v7
@@ -82,7 +105,15 @@ jobs:
enable-cache: false
- name: Install PlatformIO Core
run: uv pip install --system -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.19.zip
run: |
uv pip install --system -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.19.zip
# platform-espressif32's builder/main.py imports these unconditionally; its own
# penv bootstrap (builder/penv_setup.py) is supposed to install them automatically
# but isn't picking them up reliably in this runner image, so pin them explicitly.
uv pip install --system -U "littlefs-python>=0.16.0" "fatfs-ng>=0.1.14" "pyyaml>=6.0.2" \
"rich-click>=1.8.6" "zopfli>=0.2.2" "intelhex>=2.3.0" "rich>=14.0.0" "urllib3<2" \
"cryptography>=45.0.3" "certifi>=2025.8.3" "ecdsa>=0.19.1" "bitstring>=4.3.1" \
"reedsolo>=1.5.3,<1.8" "esp-idf-size>=2.0.0" "esp-coredump>=1.14.0"
- name: Cache PlatformIO packages
uses: actions/cache@v4
@@ -91,13 +122,12 @@ jobs:
key: pio-${{ runner.os }}-${{ hashFiles('platformio.ini') }}
restore-keys: pio-${{ runner.os }}-
- name: Build default firmware
- name: Build ${{ matrix.env }} firmware
run: |
set -euo pipefail
pio run -e default | tee pio.log
pio run -e ${{ matrix.env }} | tee pio.log
- name: Extract firmware stats
run: |
set -euo pipefail
ram_line="$(grep -E "RAM:\\s" -m1 pio.log || true)"
@@ -105,64 +135,18 @@ jobs:
echo "ram_line=${ram_line}" >> "$GITHUB_OUTPUT"
echo "flash_line=${flash_line}" >> "$GITHUB_OUTPUT"
{
echo "## Firmware build stats"
echo "## ${{ matrix.env }} firmware build stats"
if [ -n "$ram_line" ]; then echo "- ${ram_line}"; else echo "- RAM: not found"; fi
if [ -n "$flash_line" ]; then echo "- ${flash_line}"; else echo "- Flash: not found"; fi
} >> "$GITHUB_STEP_SUMMARY"
- name: Upload firmware.bin artifact
- name: Upload firmware artifact
uses: actions/upload-artifact@v6
with:
name: firmware.bin
path: .pio/build/default/firmware.bin
name: ${{ matrix.asset }}
path: .pio/build/${{ matrix.env }}/firmware.bin
if-no-files-found: error
build-sticky:
name: Build sticky
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- uses: actions/setup-python@v6
with:
python-version: '3.14'
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
version: "latest"
enable-cache: false
- name: Install PlatformIO Core
run: uv pip install --system -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.19.zip
- name: Cache PlatformIO packages
uses: actions/cache@v4
with:
path: ~/.platformio
key: pio-${{ runner.os }}-${{ hashFiles('platformio.ini') }}
restore-keys: pio-${{ runner.os }}-
- name: Build sticky firmware
run: |
set -euo pipefail
pio run -e sticky | tee pio.log
- name: Extract firmware stats
run: |
set -euo pipefail
ram_line="$(grep -E "RAM:\\s" -m1 pio.log || true)"
flash_line="$(grep -E "Flash:\\s" -m1 pio.log || true)"
echo "ram_line=${ram_line}" >> "$GITHUB_OUTPUT"
echo "flash_line=${flash_line}" >> "$GITHUB_OUTPUT"
{
echo "## Sticky firmware build stats"
if [ -n "$ram_line" ]; then echo "- ${ram_line}"; else echo "- RAM: not found"; fi
if [ -n "$flash_line" ]; then echo "- ${flash_line}"; else echo "- Flash: not found"; fi
} >> "$GITHUB_STEP_SUMMARY"
unit-tests:
runs-on: ubuntu-latest
steps:
@@ -195,8 +179,7 @@ jobs:
test-status:
name: Test Status
needs:
- build-default
- build-sticky
- build
- clang-format
- cppcheck
- unit-tests
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: '3.14'
python-version: '3.13'
- name: Install font tools
run: pip install freetype-py fonttools pyyaml
+83
View File
@@ -0,0 +1,83 @@
name: Compile Release
# Builds every board's release firmware on tag push, with the .bin named
# exactly as OtaUpdater requests it from the GitHub release: plain
# firmware.bin for the C3 X4/X3 binary, firmware-<board>.bin for every other
# board. Attach the artifacts' .bin files to the release as-is.
on:
push:
tags:
- '*'
permissions:
contents: read
jobs:
build-release:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- pio_env: gh_release
asset: firmware.bin
- pio_env: sticky-gh_release
asset: firmware-sticky.bin
- pio_env: x4pro-gh_release
asset: firmware-x4pro.bin
- pio_env: papermono-gh_release
asset: firmware-papermono.bin
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
version: "latest"
enable-cache: false
- name: Install PlatformIO Core
run: |
uv pip install --system -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.19.zip
# platform-espressif32's builder/main.py imports these unconditionally; its own
# penv bootstrap (builder/penv_setup.py) is supposed to install them automatically
# but isn't picking them up reliably in this runner image, so pin them explicitly.
uv pip install --system -U "littlefs-python>=0.16.0" "fatfs-ng>=0.1.14" "pyyaml>=6.0.2" \
"rich-click>=1.8.6" "zopfli>=0.2.2" "intelhex>=2.3.0" "rich>=14.0.0" "urllib3<2" \
"cryptography>=45.0.3" "certifi>=2025.8.3" "ecdsa>=0.19.1" "bitstring>=4.3.1" \
"reedsolo>=1.5.3,<1.8" "esp-idf-size>=2.0.0" "esp-coredump>=1.14.0"
- name: Cache PlatformIO packages
uses: actions/cache@v4
with:
path: ~/.platformio
key: pio-${{ runner.os }}-${{ hashFiles('platformio.ini') }}
restore-keys: pio-${{ runner.os }}-
- name: Build CrossPoint
run: pio run -e ${{ matrix.pio_env }} -j1
- name: Name release asset
run: |
if [ "${{ matrix.asset }}" != "firmware.bin" ]; then
cp ".pio/build/${{ matrix.pio_env }}/firmware.bin" \
".pio/build/${{ matrix.pio_env }}/${{ matrix.asset }}"
fi
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.asset }}
path: |
.pio/build/${{ matrix.pio_env }}/bootloader.bin
.pio/build/${{ matrix.pio_env }}/${{ matrix.asset }}
.pio/build/${{ matrix.pio_env }}/firmware.elf
.pio/build/${{ matrix.pio_env }}/firmware.map
.pio/build/${{ matrix.pio_env }}/partitions.bin
+10 -2
View File
@@ -14,7 +14,7 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: '3.14'
python-version: '3.13'
- name: Install uv
uses: astral-sh/setup-uv@v7
@@ -23,7 +23,15 @@ jobs:
enable-cache: false
- name: Install PlatformIO Core
run: uv pip install --system -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.19.zip
run: |
uv pip install --system -U https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.19.zip
# platform-espressif32's builder/main.py imports these unconditionally; its own
# penv bootstrap (builder/penv_setup.py) is supposed to install them automatically
# but isn't picking them up reliably in this runner image, so pin them explicitly.
uv pip install --system -U "littlefs-python>=0.16.0" "fatfs-ng>=0.1.14" "pyyaml>=6.0.2" \
"rich-click>=1.8.6" "zopfli>=0.2.2" "intelhex>=2.3.0" "rich>=14.0.0" "urllib3<2" \
"cryptography>=45.0.3" "certifi>=2025.8.3" "ecdsa>=0.19.1" "bitstring>=4.3.1" \
"reedsolo>=1.5.3,<1.8" "esp-idf-size>=2.0.0" "esp-coredump>=1.14.0"
- name: Cache PlatformIO packages
uses: actions/cache@v4
+1 -1
View File
@@ -36,7 +36,7 @@ CrossPoint is open-source e-reader firmware - community-built, fully hackable, f
- OPDS browser with saved servers (up to 8), search, pagination, and direct download
- OTA update checks and installs from GitHub releases
- **Customization**: multiple themes (Classic, Lyra, Lyra Extended, RoundedRaff), sleep screen modes, front/side button remapping, status bar controls, power-button behavior, refresh cadence, and more.
- **Customization**: multiple themes (Classic, Lyra, Lyra Extended, RoundedRaff), sleep screen modes including transparent overlays, front/side button remapping, status bar controls, power-button behavior, refresh cadence, and more.
- **Localization**: 24 UI languages and counting. RTL support.
+14 -4
View File
@@ -186,7 +186,7 @@ The Settings screen allows you to configure the device's behavior. There are a f
- "None" - A blank screen
- "Cover + Custom" - The book cover image while actively reading, falls back to "Custom" behavior otherwise
- "Quick resume" - The text of the last page read will be displayed on the sleep screen and a moon icon is shown on the edge of the screen. Waking up the device will return to the same page of the opened book. This is useful for quickly resuming reading without waiting for the device to fully wake up and load the book.
- "Transparent" - A transparent overlay image drawn over the current screen; see [Sleep Screen](#37-sleep-screen) below for more information
- **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
@@ -501,6 +501,7 @@ The **Sleep Screen** setting controls what is displayed when the device goes to
| **Custom** | A custom image from the SD card (see below). Falls back to **Dark** if no custom image is found. |
| **Cover** | The cover of the currently open book. Falls back to **Dark** if no book is open. |
| **Cover + Custom** | The cover of the currently open book, shown only while actively reading. Falls back to **Custom** behavior when not reading. |
| **Transparent** | A BMP overlay drawn over the current screen. Supports alpha transparency in 32-bit BGRA images and treats white as transparent in regular BMPs. Falls back to **Dark** if no valid overlay image is found. |
| **None** | A blank screen. |
#### Cover settings
@@ -515,12 +516,21 @@ When using **Cover** or **Cover + Custom**, two additional settings apply:
To use custom sleep images, set the sleep screen mode to **Custom** or **Cover + Custom**, then place images on the SD card:
- **Multiple Images (recommended):** Create a `.sleep` directory in the root of the SD card and place any number of `.bmp` images inside. One will be randomly selected each time the device sleeps. (A directory named `sleep` is also accepted as a fallback.)
- **Single Image:** Place a file named `sleep.bmp` in the root directory. This is used as a fallback if no valid images are found in the `.sleep`/`sleep` directory.
- **Single Image:** Place a file named `sleep.bmp` in the root directory. This takes priority over the `.sleep`/`sleep` directories.
#### Transparent overlay images
To use transparent sleep overlays, set the sleep screen mode to **Transparent**, then place BMP files on the SD card:
- **Multiple Images (recommended):** Create a `.sleep-overlay` directory in the root of the SD card and place any number of valid overlay `.bmp` images inside. One will be randomly selected each time the device sleeps. A directory named `sleep-overlay` is also accepted as a fallback.
- **Single Image:** Place a file named `sleep-overlay.bmp` in the root directory. This takes priority over the `.sleep-overlay`/`sleep-overlay` directories.
Transparent overlay files are intentionally separate from normal sleep images. Regular BMP formats supported by CrossPoint are accepted; white pixels leave the existing screen unchanged. For per-pixel alpha transparency, use a 32-bit BGRA BMP with both visible and non-opaque pixels. Opaque white pixels in these alpha images erase the content behind them.
> [!TIP]
> For best results:
>
> - Use uncompressed BMP files with 24-bit color depth
> - For non-transparent **Custom** mode, use uncompressed BMP files with 24-bit color depth.
> - For **Transparent** mode, use a regular BMP for white-as-transparent artwork or an uncompressed 32-bit BGRA BMP for per-pixel alpha.
> - X4: Use a resolution of 480x800 pixels to match the device's screen resolution.
> - X3: Use a resolution of 528x792 pixels to match the device's screen resolution.
+2 -2
View File
@@ -1,6 +1,6 @@
# Touch and UI Development
CrossPoint runs on touch devices (Seeed Sticky, M5Paper, LilyGo T5) alongside the button-only Xteink X3/X4. Every screen must work with both input styles.
CrossPoint runs on touch devices (Seeed Sticky, M5Paper, M5Stack PaperMono, LilyGo T5, Xteink X4 Pro) alongside the button-only Xteink X3/X4. Every screen must work with both input styles.
**There is one supported way to build a new screen: FreeInkUI, hosted through the firmware base classes below.** Touch hit-testing, tap highlighting, long-press, swipe scrolling, and button focus navigation all come from the shared stack; you never hand-roll coordinate math.
@@ -18,7 +18,7 @@ The old bridge helpers (`rowTouch`, `colTouch`, `wasTapInRect`, manual rect `con
| A modal picker or confirm inside a legacy activity | `OptionPopup` (or push `ConfirmationActivity`) | [`OtaUpdateActivity`](../../src/activities/settings/OtaUpdateActivity.cpp) |
| A Yes/No prompt inside a FUI screen | build `fui::optionDialog` into the screen | `WifiSelectionActivity::buildPromptDialog` |
All four paths route input through the same SDK interaction table, so touch and physical buttons fire the same actions with no per-screen coordinate code.
All of these paths route input through the same SDK interaction table, so touch and physical buttons fire the same actions with no per-screen coordinate code.
## The hosting stack
+3 -1
View File
@@ -13,7 +13,7 @@ A dictionary folder must contain:
- `.syn` — synonym index (optional; maps alternate spellings and irregular forms to their headword)
- `.ifo` — metadata (optional)
Not supported: dictionaries with 64-bit index offsets (`idxoffsetbits=64` in the `.ifo` — rare, and rejected with an error), and HTML-formatted definitions render as raw markup rather than styled text.
Not supported: dictionaries with 64-bit index offsets (`idxoffsetbits=64` in the `.ifo` — rare, and rejected with an error).
## Setting Up a Dictionary
@@ -49,6 +49,8 @@ On the very first lookup with a dictionary (and again whenever the `.idx` or `.s
When a word is found, the definition screen shows the matched headword at the top and the definition text below, with a page counter for long definitions.
HTML dictionaries that declare `sametypesequence=h` use the EPUB text-layout engine for semantic formatting such as headings, bold, italics, lists, and line breaks. Images and CSS styling are ignored. Definitions that are too large or cannot be laid out within the available memory fall back to plain text.
- **Left/Right** or side **Up/Down** — previous / next page
- **Back** — return to word selection
+2
View File
@@ -2138,6 +2138,8 @@ void GfxRenderer::writeGrayscalePlaneStrip(bool lsbPlane, const uint8_t* scratch
bool GfxRenderer::supportsStripGrayscale() const { return display.supportsStripGrayscale(); }
bool GfxRenderer::combinesGrayscaleBase() const { return display.combinesGrayscaleBase(); }
void GfxRenderer::freeBwBufferChunks() {
for (auto& bwBufferChunk : bwBufferChunks) {
if (bwBufferChunk) {
+3
View File
@@ -293,6 +293,9 @@ class GfxRenderer {
// numRows)), bypassing the framebuffer. supportsStripGrayscale() gates use.
void writeGrayscalePlaneStrip(bool lsbPlane, const uint8_t* scratch, int yStart, int numRows) const;
bool supportsStripGrayscale() const;
// Paper Mono: the base activation is deferred so base + gray planes go out
// as one waveform. Route the base through displayGrayscaleBase() when true.
bool combinesGrayscaleBase() const;
bool storeBwBuffer(); // Returns true if buffer was stored successfully
void restoreBwBuffer(); // Restore and free the stored buffer
void cleanupGrayscaleWithFrameBuffer() const;
+1
View File
@@ -278,6 +278,7 @@ STR_BOOKMARK_REMOVED: "S'ha eliminat el punt de llibre."
STR_OPDS_BROWSER: "Navegador OPDS"
STR_COVER_CUSTOM: "Portada + Personalitzat"
STR_QUICK_RESUME: "Represa rĂ pida"
STR_TRANSPARENT: "Transparent"
STR_MENU_RECENT_BOOKS: "Llibres recents"
STR_REMOVE_FROM_RECENTS: "Vols suprimir-lo de Llibres recents?"
STR_NO_RECENT_BOOKS: "No hi ha llibres recents"
+10
View File
@@ -95,6 +95,7 @@ STR_SHORT_PWR_BTN: "Short Power Button Click"
STR_ORIENTATION: "Reading Orientation"
STR_SIDE_BTN_LAYOUT: "Side Button Layout (reader)"
STR_TOUCH_READER_CONTROLS: "Touch Reader Controls"
STR_TAP_FOR_READER_MENU: "Tap For Reader Menu"
STR_FRONT_BTN_FOLLOW_ORIENTATION: "Orient front buttons"
STR_LONG_PRESS_BEHAVIOR: "Long-press button behavior"
STR_LONG_PRESS_BEHAVIOR_OFF: "OFF"
@@ -184,6 +185,7 @@ STR_NEXT_PREV: "Next/Prev"
STR_KOSYNC: "KOSync"
STR_BOOKMARK_OPTION: "Bookmark"
STR_DICTIONARY: "Dictionary"
STR_READER_MENU: "Reader Menu"
STR_DISABLED: "Disabled"
STR_NOTO_SERIF: "Noto Serif"
STR_NOTO_SANS: "Noto Sans"
@@ -247,6 +249,13 @@ STR_SHOW: "Show"
STR_HIDE: "Hide"
STR_STATE_ON: "ON"
STR_STATE_OFF: "OFF"
STR_STATE_TAP: "Tap"
STR_STATE_SWIPE: "Swipe"
STR_STATE_INVERTED_TAP: "Inverted Tap"
STR_FRONTLIGHT: "Frontlight"
STR_BRIGHTNESS: "Brightness"
STR_WARMTH: "Warmth"
STR_RESTORE_LIGHT_ON_WAKE: "Restore Light on Wake"
STR_NOT_SET: "Not Set"
STR_DIR_LEFT: "Left"
STR_DIR_RIGHT: "Right"
@@ -306,6 +315,7 @@ STR_OPDS_BROWSER: "OPDS Browser"
STR_SEARCH: "Search"
STR_COVER_CUSTOM: "Cover + Custom"
STR_QUICK_RESUME: "Quick Resume"
STR_TRANSPARENT: "Transparent"
STR_MENU_RECENT_BOOKS: "Recent Books"
STR_REMOVE_FROM_RECENTS: "Remove from Recent Books?"
STR_NO_RECENT_BOOKS: "No recent books"
+328
View File
@@ -0,0 +1,328 @@
_language_name: "Orangutan"
_language_code: "OOK"
_order: "34"
STR_CROSSPOINT: "CrossPoint"
STR_BOOTING: "OOK"
STR_SLEEPING: "Oooook"
STR_ENTERING_SLEEP: "Ook..."
STR_BROWSE_FILES: "Ook? OOK"
STR_FILE_TRANSFER: "Oook!"
STR_SETTINGS_TITLE: "OOK!"
STR_CONTINUE_READING: "Oooook ook"
STR_RESUME: "OOk!"
STR_NO_OPEN_BOOK: "OOK?"
STR_START_READING: "Ook ook"
STR_NO_FILES_FOUND: "Oook?"
STR_SELECT_CHAPTER: "Ook? Oook OOK!"
STR_NO_CHAPTERS: "Ook..."
STR_END_OF_BOOK: "Oooook."
STR_EMPTY_CHAPTER: "OOk?"
STR_INDEXING: "Oook..."
STR_LOADING: "Ooook..."
STR_LOADING_POPUP: "Oook"
STR_LOOKUP: "Ook? Oook! OOK"
STR_WIFI_NETWORKS: "Wi-Fi OOK"
STR_NO_NETWORKS: "Oook?"
STR_NETWORKS_FOUND: "%zu OOK"
STR_SCANNING: "Oook..."
STR_FINDING_SAVED_WIFI: "Oook Wi-Fi..."
STR_CONNECTING: "Ooook..."
STR_CONNECTING_SAVED_WIFI: "OOk Wi-Fi..."
STR_SHOW_NETWORKS: "OOK"
STR_CONNECTED: "Oook!"
STR_CONNECTION_FAILED: "OOk?"
STR_FORGET_NETWORK: "Oook?"
STR_SAVE_PASSWORD: "OOK?"
STR_PRESS_OK_SCAN: "OOk OK"
STR_JOIN_NETWORK: "Oook!"
STR_CREATE_HOTSPOT: "Ooook"
STR_JOIN_DESC: "Oook Wi-Fi"
STR_HOTSPOT_DESC: "Oooook Wi-Fi"
STR_STARTING_HOTSPOT: "Ooook..."
STR_HOTSPOT_MODE: "OOk!"
STR_CONNECT_WIFI_HINT: "Oook Wi-Fi"
STR_OPEN_URL_HINT: "Oook URL"
STR_SCAN_QR_HINT: "Oook QR:"
STR_CALIBRE_WIRELESS: "Calibre OOK"
STR_NETWORK_LEGEND: "* = OOK | + = OOk"
STR_MAC_ADDRESS: "MAC!"
STR_CHECKING_WIFI: "OOk Wi-Fi..."
STR_ENTER_WIFI_PASSWORD: "Oook Wi-Fi"
STR_ADD_HIDDEN_NETWORK: "Oook..."
STR_ENTER_WIFI_SSID: "OOk (SSID)"
STR_TO_PREFIX: "Oo "
STR_CALIBRE_RECEIVING: "Oook: "
STR_CALIBRE_RECEIVED: "OOK!: "
STR_CAT_DISPLAY: "OOK"
STR_CAT_READER: "OOk"
STR_CAT_CONTROLS: "Ook!"
STR_CAT_SYSTEM: "Oook"
STR_SLEEP_SCREEN: "Oooook"
STR_NIGHT_MODE: "Ook!"
STR_QUICK_RESUME_TIMEOUT: "Oook ook"
STR_SLEEP_COVER_MODE: "Ook ook"
STR_HIDE_BATTERY: "OOk %"
STR_EXTRA_SPACING: "Oook ook"
STR_TEXT_AA: "Ook-ook"
STR_IMAGES: "OOk!"
STR_IMAGES_DISPLAY: "Oook"
STR_IMAGES_PLACEHOLDER: "Ooook"
STR_IMAGES_SUPPRESS: "OOK"
STR_EOB_HOME: "Oook"
STR_EOB_CONTINUE_WITH: "Oook ook"
STR_SHORT_PWR_BTN: "Oooook OOK"
STR_ORIENTATION: "Ook? Oooook OOK"
STR_SIDE_BTN_LAYOUT: "Oook ook"
STR_TOUCH_READER_CONTROLS: "OOk! OOK"
STR_FRONT_BTN_FOLLOW_ORIENTATION: "Oook OOK"
STR_LONG_PRESS_BEHAVIOR: "Oooook OOK"
STR_LONG_PRESS_BEHAVIOR_OFF: "OFF"
STR_LONG_PRESS_BEHAVIOR_SKIP: "Oook!"
STR_LONG_PRESS_BEHAVIOR_ORIENTATION: "Ook? OOK"
STR_LONG_PRESS_MENU: "Oooook!"
STR_FONT_PREVIEW_TEXT: "Ook ook ook."
STR_FONT_FAMILY: "Oook OOK"
STR_FONT_SIZE: "OOk OOK"
STR_TEXT_SETTINGS: "Oooook OOK: Ook!"
STR_FONT: "OOk!"
STR_SIZE: "OOK"
STR_LAYOUT: "Oook"
STR_ALIGNMENT: "Oooook"
STR_STYLE: "OOk!"
STR_NOT_IN_PREVIEW: "Oook?"
STR_LINE_SPACING: "Oook ook"
STR_SCREEN_MARGIN: "OOk ook"
STR_PARA_ALIGNMENT: "Ook OOK"
STR_HYPHENATION: "Ooook"
STR_TIME_TO_SLEEP: "Oook..."
STR_SHOW_HIDDEN_FILES: "OOk?"
STR_REMOVE_READ_FROM_RECENTS: "Oook OOK"
STR_MOVE_FINISHED_TO_READ: "Ook! OOK"
STR_REFRESH_FREQ: "Oook!"
STR_KOREADER_SYNC: "KOReader OOK"
STR_CHECK_UPDATES: "Oook!"
STR_LANGUAGE: "OOk?"
STR_CLEAR_READING_CACHE: "Oook OOK"
STR_USERNAME: "Oook"
STR_PASSWORD: "OOk!"
STR_SYNC_SERVER_URL: "Oook URL"
STR_DOCUMENT_MATCHING: "Oook OOK"
STR_SEND_METADATA: "Ook! OOK"
STR_SYNC_BEHAVIOR: "OOk ook"
STR_ASK_EVERY_TIME: "Oook?"
STR_SMART_SYNC: "Oook!"
STR_AUTHENTICATE: "Oooook"
STR_SIGN_UP: "OOk!"
STR_KOREADER_USERNAME: "KOReader OOK"
STR_KOREADER_PASSWORD: "KOReader OOk"
STR_FILENAME: "Oook"
STR_KOREADER_AUTH: "KOReader OOK"
STR_DONE: "Oook"
STR_DARK: "OOk!"
STR_LIGHT: "Oook"
STR_CUSTOM: "Ooook"
STR_COVER: "OOk?"
STR_NONE_OPT: "OOk!"
STR_FIT: "OOk"
STR_CROP: "OOK!"
STR_NEVER: "Oook!"
STR_IN_READER: "Ook? OOK"
STR_ALWAYS: "Oooook"
STR_IGNORE: "OOk?"
STR_SLEEP: "Oook!"
STR_PAGE_TURN: "Oook OOK"
STR_FORCE_REFRESH: "Ook! OOK"
STR_PORTRAIT: "Oook"
STR_LANDSCAPE_CW: "Oook OOK"
STR_INVERTED: "OOk!"
STR_ORIENTATION_INVERTED: "Ook 180°"
STR_LANDSCAPE_CCW: "OOk OOK"
STR_PREV_NEXT: "OOk/OOK"
STR_NEXT_PREV: "OOK/OOk"
STR_KOSYNC: "KOSync"
STR_BOOKMARK_OPTION: "Oook!"
STR_DICTIONARY: "Oooook"
STR_DISABLED: "OOk!"
STR_NOTO_SERIF: "Noto OOK"
STR_NOTO_SANS: "Noto OOk"
STR_TIGHT: "OOk!"
STR_NORMAL: "Oook"
STR_WIDE: "OOk!"
STR_JUSTIFY: "Ooook!"
STR_ALIGN_LEFT: "OOk"
STR_CENTER: "Oook"
STR_ALIGN_RIGHT: "OOK!"
STR_PAGES_1: "1 OOK"
STR_PAGES_5: "5 OOk"
STR_PAGES_10: "10 OOK"
STR_PAGES_15: "15 OOk"
STR_PAGES_30: "30 OooK"
STR_UPDATE: "Oook!"
STR_CURRENT_VERSION: "OOK: "
STR_NEW_VERSION: "OOk: "
STR_DOWNLOADING: "Oooook..."
STR_UNNAMED: "OOk?"
STR_HOLD_OPEN_TO_DELETE: "Oook OOK"
STR_NEXT_PAGE: "OOk »"
STR_PREV_PAGE: "« OOK"
STR_NETWORK_PREFIX: "OOk: "
STR_IP_ADDRESS_PREFIX: "IP: "
STR_SD_CARD: "SD OOK"
STR_BACK: "« OOK"
STR_EXIT: "« OOk"
STR_HOME: "« Oook"
STR_SELECT: "OOk!"
STR_SELECTED: "Oooook"
STR_TOGGLE: "Oook!"
STR_TOGGLE_BOOKMARK: "Ook? OOK! Oooook"
STR_CONFIRM: "Oooook"
STR_CANCEL: "OOk?"
STR_CONNECT: "Oooook"
STR_OPEN: "Oook"
STR_DOWNLOAD: "Oooook"
STR_RETRY: "Oook!"
STR_YES: "OOk"
STR_NO: "Oo"
STR_SHOW: "Oook"
STR_HIDE: "OOk!"
STR_STATE_ON: "OK"
STR_STATE_OFF: "OOk"
STR_NOT_SET: "Oook"
STR_DIR_LEFT: "OOk!"
STR_DIR_RIGHT: "OOK!"
STR_DIR_UP: "OK"
STR_DIR_DOWN: "OOk!"
STR_OK_BUTTON: "OK"
STR_KEY_SHIFT: "OOk!"
STR_KEY_MODE_SYMBOLS: "?123"
STR_KEY_MODE_ABC: "abc"
STR_SLEEP_COVER_FILTER: "Oook OOK"
STR_FILTER_CONTRAST: "Oooook"
STR_CUSTOMISE_STATUS_BAR: "Oook OOK"
STR_CHAPTER_PAGE_COUNT: "OOk OOK"
STR_BOOK_PROGRESS_PERCENTAGE: "Oook OOK"
STR_PROGRESS_BAR: "Oook OOK"
STR_PROGRESS_BAR_THICKNESS: "Oook OOK"
STR_PROGRESS_BAR_THIN: "OOk!"
STR_PROGRESS_BAR_MEDIUM: "Oook"
STR_PROGRESS_BAR_THICK: "Oook!"
STR_BOOK: "Oook"
STR_CHAPTER: "OOk!"
STR_EXAMPLE_CHAPTER: "OOk 21"
STR_EXAMPLE_BOOK: "Oook OOK"
STR_PREVIEW: "Oook!"
STR_TITLE: "OOk?"
STR_BATTERY: "Oook"
STR_XTC_STATUS_BAR: "XTC OOK"
STR_BOTTOM: "Oooook"
STR_TOP: "OOk"
STR_CLOCK: "Oook!"
STR_CLOCK_UTC_OFFSET: "Oook OOK"
STR_CLOCK_FORMAT: "OOk OOK"
STR_CLOCK_FORMAT_24H: "24-OOK"
STR_CLOCK_FORMAT_12H: "12-OOk"
STR_CURRENT_TIME: "OOk:"
STR_NEXT_FIELD: "Oook"
STR_CLOCK_SYNC: "OOk OOK"
STR_CLOCK_SYNC_NOW: "Oook OOK"
STR_CLOCK_SYNCING: "Oooook..."
STR_CLOCK_SYNC_OK: "Oook!"
STR_CLOCK_SYNC_FAIL: "OOk?"
STR_CLOCK_SYNC_NO_WIFI: "Wi-Fi OOK"
STR_CLOCK_SYNCED: "Oooook"
STR_UI_THEME: "OOk OOK"
STR_THEME_CLASSIC: "Oook!"
STR_THEME_LYRA: "OOk!"
STR_THEME_ROUNDEDRAFF: "Oook"
STR_THEME_LYRA_EXTENDED: "Oook OOK"
STR_SUNLIGHT_FADING_FIX: "Oook OOK"
STR_REMAP_FRONT_BUTTONS: "Oook OOK"
STR_BOOKMARKS: "Ook! OOK Oooook"
STR_NO_BOOKMARKS: "OOk?"
STR_BOOKMARK_ADDED: "Ook!"
STR_BOOKMARK_REMOVED: "Oook!"
STR_OPDS_BROWSER: "OPDS OOK"
STR_SEARCH: "Oook!"
STR_COVER_CUSTOM: "OOk + OOK"
STR_QUICK_RESUME: "Oook OOK"
STR_MENU_RECENT_BOOKS: "Oook OOK"
STR_REMOVE_FROM_RECENTS: "OOk?"
STR_NO_RECENT_BOOKS: "Oook?"
STR_CALIBRE_DESC: "Calibre OOK"
STR_FORGET_AND_REMOVE: "Oook?"
STR_FORGET_BUTTON: "Oook!"
STR_CALIBRE_STARTING: "Calibre OOK"
STR_CALIBRE_SETUP: "OOk!"
STR_CALIBRE_STATUS: "Oook"
STR_CLEAR_BUTTON: "Oook!"
STR_DEFAULT_VALUE: "OOk OOK"
STR_UNASSIGNED: "OOk?"
STR_ALREADY_ASSIGNED: "Oook OOK"
STR_GO_TO_PERCENT: "Oook! Ook? %"
STR_GO_HOME_BUTTON: "Oook OOK! Oooook"
STR_SYNC_PROGRESS: "Oooook OOK! Ook!"
STR_DELETE_CACHE: "Oook OOK? Oooook!"
STR_DELETE: "Oooook"
STR_CONFIRM_DELETE_BOOKMARK: "Oook?"
STR_DISPLAY_QR: "Oooook OOK QR!"
STR_CHAPTER_PREFIX: "OOk: "
STR_BOOK_PREFIX: "Oook: "
STR_SYNCING_TIME: "Oook..."
STR_FETCH_PROGRESS: "OOk..."
STR_UPLOAD_PROGRESS: "Oooook..."
STR_KOREADER_SETUP_HINT: "KOReader OOK"
STR_PROGRESS_FOUND: "Oook!"
STR_REMOTE_LABEL: "OOk:"
STR_LOCAL_LABEL: "Oook:"
STR_PAGE_OVERALL_FORMAT: "OOk %d, %.2f%%"
STR_PAGE_TOTAL_OVERALL_FORMAT: "Oook %d/%d, %.2f%%"
STR_DEVICE_FROM_FORMAT: "OOk: %s"
STR_APPLY_REMOTE: "Oook OOK"
STR_UPLOAD_LOCAL: "OOk OOK"
STR_UPLOAD_PROMPT: "Oook?"
STR_UPLOAD_SUCCESS: "Oooook!"
STR_ALREADY_SYNCED: "Oook!"
STR_SECTION_PREFIX: "OOk "
STR_UPLOAD: "Oooook"
STR_BOOK_S_STYLE: "Oook OOK"
STR_EMBEDDED_STYLE: "OOk OOK"
STR_FOCUS_READING: "Oook OOK"
STR_OPDS_SERVER_URL: "OPDS OOK"
STR_PWR_BTN_FOOTNOTE_BACK: "Oook OOK"
STR_BACK_SHORT_TO_FILE_BROWSER: "OOk OOK"
STR_SET_SLEEP_COVER: "Oook OOK"
STR_FOOTNOTES: "Ook! Oook OOK"
STR_NO_FOOTNOTES: "Oook?"
STR_LINK: "[Ook]"
STR_SCREENSHOT_BUTTON: "Oook! OOK? Ook!"
STR_SLEEP_TIMER_VALUE_FORMAT: "%u OOK"
STR_SLEEP_NEVER: "Oook!"
STR_ADD_SERVER: "Oook!"
STR_SERVER_NAME: "OOk OOK"
STR_DELETE_SERVER: "Oook OOK"
STR_OPDS_SERVERS: "OPDS OOK"
STR_OPDS_DOWNLOAD_FOLDER: "Oook OOK"
STR_OPDS_FILENAME_FORMAT: "OOk OOK"
STR_FMT_AUTHOR_TITLE: "OOk - OOK"
STR_FMT_TITLE_AUTHOR: "OOK - OOk"
STR_FMT_TITLE: "Oook"
STR_OPDS_SD_ROOT: "SD OOK"
STR_AUTO_TURN_ENABLED: "OOk: "
STR_AUTO_TURN_PAGES_PER_MIN: "Oooook OOK (Ook!)"
STR_MANAGE_FONTS: "Oook OOK"
STR_FONT_BROWSER: "OOk OOK"
STR_LOADING_FONT_LIST: "Oooook..."
STR_NO_FONTS_AVAILABLE: "Oook?"
STR_FONT_INSTALLED: "Oook!"
STR_INSTALLED: "OOk!"
STR_DOWNLOAD_ALL: "Oook OOK"
STR_UPDATE_ALL: "OOk OOK"
STR_UPDATE_AVAILABLE: "Oook!"
STR_TILT_PAGE_TURN: "Oook OOK"
STR_SD_FIRMWARE_UPDATE: "SD Oooook Ooook Ooooook"
STR_STEP_HINT_FRONT: "Ooook Ooooook:"
STR_STEP_HINT_SIDE: "OOK Oook:"
+1
View File
@@ -303,6 +303,7 @@ STR_OPDS_BROWSER: "Navegador OPDS"
STR_SEARCH: "Buscar"
STR_COVER_CUSTOM: "Portada + Pers."
STR_QUICK_RESUME: "Reanudación rápida"
STR_TRANSPARENT: "Transparente"
STR_MENU_RECENT_BOOKS: "Libros recientes"
STR_REMOVE_FROM_RECENTS: "ÂżEliminar de Libros recientes?"
STR_NO_RECENT_BOOKS: "No hay libros recientes"
+1
View File
@@ -283,6 +283,7 @@ STR_BOOKMARK_REMOVED: "S'ha eliminat el punt de llibre."
STR_OPDS_BROWSER: "Navegador OPDS"
STR_COVER_CUSTOM: "Portada + Personalitzat"
STR_QUICK_RESUME: "Represa rĂ pida"
STR_TRANSPARENT: "Transparent"
STR_MENU_RECENT_BOOKS: "Llibres recents"
STR_REMOVE_FROM_RECENTS: "Vols eliminar-lo de Llibres recents?"
STR_NO_RECENT_BOOKS: "No hi ha llibres recents"
+6 -1
View File
@@ -16,9 +16,14 @@ void safeCopy(char* dst, size_t dstSize, const char* src, size_t srcLen) {
ReleaseJsonParser::ReleaseJsonParser()
: parser(JsonCallbacks{this, sOnKey, sOnString, sOnNumber, sOnBool, sOnNull, sOnObjectStart, sOnObjectEnd,
sOnArrayStart, sOnArrayEnd}) {
safeCopy(firmwareAssetName, sizeof(firmwareAssetName), "firmware.bin", sizeof("firmware.bin") - 1);
reset();
}
void ReleaseJsonParser::setFirmwareAssetName(const char* name) {
safeCopy(firmwareAssetName, sizeof(firmwareAssetName), name, strlen(name));
}
void ReleaseJsonParser::reset() {
parser.reset();
position = Position::TOP_LEVEL;
@@ -44,7 +49,7 @@ const char* ReleaseJsonParser::getFirmwareUrl() const { return firmwareUrl; }
size_t ReleaseJsonParser::getFirmwareSize() const { return firmwareSize; }
void ReleaseJsonParser::commitAsset() {
if (strcmp(currentAssetName, "firmware.bin") == 0) {
if (strcmp(currentAssetName, firmwareAssetName) == 0) {
memcpy(firmwareUrl, currentAssetUrl, sizeof(firmwareUrl));
firmwareSize = currentAssetSize;
firmwareFound = true;
+7
View File
@@ -15,6 +15,11 @@ class ReleaseJsonParser {
void reset();
void feed(const char* data, size_t len);
// Release-asset filename to match (default "firmware.bin"). Boards with
// their own release binaries pass e.g. "firmware-papermono.bin". Survives
// reset(); truncated silently if longer than the internal buffer.
void setFirmwareAssetName(const char* name);
bool foundTag() const;
bool foundFirmware() const;
const char* getTagName() const;
@@ -65,4 +70,6 @@ class ReleaseJsonParser {
char currentAssetName[32];
char currentAssetUrl[512];
size_t currentAssetSize;
char firmwareAssetName[32];
};
+6
View File
@@ -93,6 +93,10 @@ bool HalDisplay::isInverted() const { return einkDisplay.isInverted(); }
void HalDisplay::deepSleep() { einkDisplay.deepSleep(); }
void HalDisplay::setBusyWaitSliceHook(bool (*sliceHook)(int8_t busyPin, uint8_t busyLevel)) {
einkDisplay.setBusyWaitSliceHook(sliceHook);
}
uint8_t* HalDisplay::getFrameBuffer() const { return einkDisplay.getFrameBuffer(); }
uint8_t* HalDisplay::lendFrameBufferStorage(uint32_t* sizeOut) { return einkDisplay.lendBuildStorage(sizeOut); }
@@ -139,6 +143,8 @@ void HalDisplay::writeGrayscalePlaneStrip(bool lsbPlane, const uint8_t* rows, ui
bool HalDisplay::supportsStripGrayscale() const { return einkDisplay.supportsStripGrayscale(); }
bool HalDisplay::combinesGrayscaleBase() const { return einkDisplay.combinesGrayscaleBase(); }
uint16_t HalDisplay::getDisplayWidth() const { return einkDisplay.getDisplayWidth(); }
uint16_t HalDisplay::getDisplayHeight() const { return einkDisplay.getDisplayHeight(); }
+11
View File
@@ -61,6 +61,10 @@ class HalDisplay {
// Power management
void deepSleep();
// Install the slice hook that replaces the BUSY poll delay on proven-long
// waits (see EpdBus::setBusyWaitSliceHook for the contract)
void setBusyWaitSliceHook(bool (*sliceHook)(int8_t busyPin, uint8_t busyLevel));
// Access to frame buffer
uint8_t* getFrameBuffer() const;
@@ -98,6 +102,13 @@ class HalDisplay {
void writeGrayscalePlaneStrip(bool lsbPlane, const uint8_t* rows, uint16_t yStart, uint16_t numRows);
bool supportsStripGrayscale() const;
// True when displayGrayscaleBase() defers the base activation so the gray
// planes join it in a single waveform (Paper Mono). Callers should then route
// the base of a grayscale page through displayGrayscaleBase() instead of
// displayBuffer(): a separate B/W refresh first makes the gray pass re-drive
// the whole text body (a visible flash).
bool combinesGrayscaleBase() const;
// Runtime geometry passthrough
uint16_t getDisplayWidth() const;
uint16_t getDisplayHeight() const;
Loaded 20 of 76 files, more files were not shown because too many files have changed in this diff. Show more