Skip to content

pablohc/microreader_plus

 
 

Repository files navigation

microreader+

Minimal EPUB reader, compatible only with Xteink X4. Not recommended for locked devices — fork of CidVonHighwind/microreader

Fork Features

Navigation

  • 4 control modes (Default, Side Inverted, Front Inverted, Inverted) replacing the 3 separate booleans from upstream, applied independently to reader and menu for a more natural and consistent navigation experience
  • Long-press back/select → Contextual actions in MainMenu

MainMenu

  • Recently opened books section with the last 5 opened books
  • Delete book with long-press back
  • Remove from Recents with long-press back from Recents list
  • Rebuild Book Index with long-press select
  • Custom Logo
  • Reduced margins to show long titles

ReaderOptions

  • Book title as header instead of static "Options"
  • Font size default = 24px
  • Font size presets adjusted (17-36px in 5 steps)

Storage

  • Fonts: moved from flash to SD card (Alegreya)
  • Sleep images: only bird embedded; stone and bebop moved to SD

System

  • Auto-migration of settings (bool invert → ControlMode, Alegreya embedded → SD, sleep images embedded → SD)
  • Button state cleanup post-transition (prevents ghost presses)

Firmware Update via SD

based on crosspoint-reader/crosspoint-reader#1786

  • ESP32 image validation (magic 0xE9, segment walk, XOR, CRC32)
  • Chip/revision guard + SHA256 + battery check
  • OTA rollback via ESP_IMG_PENDING_VERIFY
  • Force switch via otadata direct write as fallback

Features merged upstream

CidVonHighwind#25

  • Horizontal rule: centered at 1/3 width, 2px thickness
  • CSS width: XX% parsing for <hr>

CidVonHighwind#26

  • Drop caps from <span style="float: left; font-size: ...">

CidVonHighwind#30

  • --upload-dir for batch EPUB upload via serial

CidVonHighwind#33

  • ControlMode (4 navigation modes)
  • ReaderOptions: book title as header
  • Toast feedback on actions

Original README

microreader2

Minimal EPUB reader for ESP32-C3 + SSD1677 e-ink display (480×800 portrait). Includes a desktop SDL2 emulator for development without hardware.

Hardware

MCU ESP32-C3 (RISC-V, 160 MHz)
Display 4.26" e-ink 800×480 (SSD1677), rotated → 480×800 portrait
Storage SD card (FAT32, SPI)
Flash 16 MB
Input ADC buttons

Project Structure

lib/microreader/       shared core (platform-agnostic C++17)
  content/             EPUB parsing, layout, MRB binary format
  display/             Canvas, DisplayQueue, Font interfaces
  screens/             UI screen implementations
platforms/desktop/     SDL2 emulator
platforms/esp32/       ESP-IDF + PlatformIO firmware
test/                  Google Test suite
tools/                 Python scripts
resources/             Fonts, sleep images

Building

Desktop (emulator)

cmake -S platforms/desktop -B build/desktop-debug -DCMAKE_BUILD_TYPE=Debug "-DCMAKE_POLICY_VERSION_MINIMUM:STRING=3.5"
cmake --build build/desktop-debug --config Debug
.\build\desktop-debug\Debug\microreader_desktop.exe

ESP32 (PlatformIO)

# Build + flash
$env:USERPROFILE\.platformio\penv\Scripts\pio.exe run -t upload

# Serial monitor
$env:USERPROFILE\.platformio\penv\Scripts\pio.exe device monitor --baud 115200

COM4, upload baud 921600.

Tests

cd test
cmake -B build2 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_POLICY_VERSION_MINIMUM:STRING=3.5
cmake --build build2 --config Debug

.\build2\Debug\unit_tests.exe          # fast (~375 tests, <1s)
.\build2\Debug\microreader_tests.exe   # includes real EPUB integration tests

Device Management

Books (.epub) can go anywhere on the SD card — the device scans recursively from the root. Fonts (.mfb) go in /fonts/. You can copy files directly or use tools/serial_cmd.py to transfer over serial:

# Upload an EPUB book
python tools/serial_cmd.py --port COM4 --upload path/to/book.epub

# Upload all EPUB books in a directory
python tools/serial_cmd.py --port COM4 --upload-dir path/to/books/

# Upload an SD card font (no firmware rebuild needed)
python tools/serial_cmd.py --port COM4 --upload-sd-font "resources/sd fonts/Cartisse.mfb"

# Upload all SD fonts
foreach ($f in (Get-ChildItem "resources/sd fonts/*.mfb")) {
    python tools/serial_cmd.py --port COM4 --upload-sd-font $f.FullName
}

# Interactive console (status, button injection, file management, benchmarks)
python tools/serial_cmd.py --port COM4

# Delete a specific file from the device
# (interactive: rm /sdcard/books/book.epub)

Font Generation

Reader fonts are FNTS bundles (.mfb), generated from TTF/OTF sources via tools/generate_font.py.

Two kinds:

  • Built-in (resources/fonts/) — embedded in the firmware asset blob. Require a firmware rebuild to update.
  • SD card (resources/sd fonts/) — loaded from /sdcard/fonts/ at runtime. No firmware rebuild needed; just copy or upload.

The generation command is the same for both:

python tools/generate_font.py "resources/sd fonts/ttf/Cartisse-Regular.ttf" `
  -o "resources/sd fonts/Cartisse.mfb" --with-styles `
  --bold "resources/sd fonts/ttf/Cartisse-Bold.ttf" `
  --italic "resources/sd fonts/ttf/Cartisse-Italic.ttf" `
  --bold-italic "resources/sd fonts/ttf/Cartisse-BoldItalic.ttf" `
  --bundle --bundle-sizes 20 22 24 26 28 30 32 --font-name Cartisse

# Regenerate all SD fonts
$ttf = "resources/sd fonts/ttf"; $out = "resources/sd fonts"
foreach ($f in @("Bitter","Cartisse","NV_Bitter","NV_Charis","NV_Cooper","NV_Garamond","NV_Jost","NV_Palatium","Readerly")) {
    python tools/generate_font.py "$ttf/$f-Regular.ttf" -o "$out/$f.mfb" --with-styles `
      --bold "$ttf/$f-Bold.ttf" --italic "$ttf/$f-Italic.ttf" --bold-italic "$ttf/$f-BoldItalic.ttf" `
      --bundle --bundle-sizes 20 22 24 26 28 30 32 --font-name $f
}

# Font preview (generates tools/font_overview.html)
python tools/font_overview.py

# UI fonts (bitmap, bw-only)
python tools/generate_font.py resources/fonts/terminus/Terminus-Bold.ttf 14 -o resources/fonts/ui-small.mbf --header lib/microreader/display/ui_font_small.h --bw-only --ranges ui
python tools/generate_font.py resources/fonts/terminus/Terminus-Bold.ttf 32 -o resources/fonts/ui-header.mbf --header lib/microreader/display/ui_font_header.h --bw-only --ranges ui

Font partition limit: SD card fonts must fit within 3.375 MB. The font data + 4 KB header must not exceed 0x360000 bytes.

Firmware Backup & Restore

Note: Built-in fonts and sleep images are embedded directly in the firmware image (EMBED_FILES), so firmware.bin is a standard IDF binary that any web flasher can validate and flash without issues. The tradeoff is that the assets (~2 MB) consume DROM MMU pages.

# Backup running firmware partition
python -m esptool --port COM4 read_flash 0x10000 0x650000 app0_backup.bin

# Restore
python -m esptool --port COM4 write_flash 0x10000 app0_backup.bin

# Switch OTA boot partition
python tools/switch_partition.py app0 --port COM4 --flash
python tools/switch_partition.py app1 --port COM4 --flash

Sleep Screen

Sleep screen images (.mgr) go in /sleep/ on the SD card. Convert a JPEG first, then copy manually or upload via serial:

python tools/image_to_mgr.py "resources/sleep/sleep_2.jpg" --out-prefix "resources/sleep/sleep_2" --bin
python tools/serial_cmd.py --port COM4 --upload-sleep "resources/sleep/sleep_2.mgr"

Hyphenation

The reader uses the Liang hyphenation algorithm — the same algorithm used by TeX. Language-specific TeX pattern files are compiled into compact binary tries by Typst hypher and embedded as constexpr byte arrays. The language is detected automatically from the EPUB's xml:lang attribute.

Supported languages:

Code Language Trie size
en English 26 KB
de German 206 KB
fr French 7 KB
es Spanish 14 KB
it Italian 2 KB
nl Dutch 64 KB
pt Portuguese 1 KB
pl Polish 16 KB
ru Russian 33 KB

Trie data lives in lib/microreader/content/hyphenation/Liang/hyph-<lang>.trie.h as constexpr byte arrays — no heap allocation, no flash reads at runtime (data is placed in DROM on ESP32).

To add a new language:

  1. Download the .bin from typst/hypher/tries into tools/hyphenation/
  2. Generate the header: python tools/generate_trie_header.py tools/hyphenation/<lang>.bin lib/microreader/content/hyphenation/Liang/hyph-<lang>.trie.h <lang>
  3. Add the new enum value to HyphenationLang in Hyphenation.h
  4. Add a #include + case in Hyphenation.cpp (hyphenate_word) and an ieq check in detect_language

QEMU Testing (no hardware needed)

# Terminal 1
python tools/run_qemu.py --with-books

# Terminal 2
python tools/test_books.py --port socket://localhost:4444 --pages 20 --delay 0.1

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

  • C++ 89.8%
  • HTML 6.8%
  • Python 2.8%
  • Other 0.6%