TernOS - A rust based firmware with reading and PalmOS functionality for XTEink X4 pocket reader
See the codeEasy flashing + file conversion: Use the web app at https://ternreader.org to flash the latest firmware and convert images/EPUBs for XTEink X4.
All of the existing firmwares for these devices are single application firmwares e.g. Crosspoint, i.e. one app delivered as a firmware which means that you can't do anything else on the device.
TernOS aims to be a more general purpose OS, taking it's inspiration from the defunct PalmOS, it provides system / hardware services, a rich UI library, database services and apps and databases as loadable resources. It also emulates the original Palm 68k hardware so you can run most of the original Palm apps.
see docs/ui-layer.md
Complete
ternos::services::db.prc_app to palm, clarifying the architecture boundary.DmNumRecordsDmRecordInfoDmQueryRecordDmNewRecordDmResizeRecordDmReleaseRecordDmSetDmWrite/db.Outstanding
ternos::services::* APIs.Complete
Outstanding
Complete
palm/ rather than prc_app/.Outstanding
Complete
Outstanding
tern-native PRCs with manifest-driven entrypoint selection.docs/ternos.md is only partially realized.rust-srccargocargo-espflash / espflashriscv32imc-unknown-none-elf)espupsource /Users/Me/export-esp.shespflashm5paper uses a vendored arduino-esp32 component under third_party/arduino-esp32, and the build runs with the ESP-IDF component manager disabled for repeatable builds.
cargo run --package tern-desktop
Build, flash, and monitor:
./run-x4.sh
Manual build only:
cargo espflash save-image --release --chip=esp32c3 --target=riscv32imc-unknown-none-elf --package=tern-x4 firmware.bin
In each new shell, load the ESP environment first:
source /Users/andrew/export-esp.sh
Build, flash, and monitor:
./run-m5.sh
Manual build only:
cd m5paper
cargo +esp build --release
The script cleans the ESP-IDF build products, rebuilds m5paper, locates the generated m5paper/espidf/build/tern_m5paper_rust_host.elf, and flashes it with espflash.
This firmware focuses on two usecases and aims to do each well:-
Wallet for loyalty cards, tickets, boarding passes etc. eInk has the great advantage in that the display is persistent and therefore can function even when the device has no power. We convert images into a 4 color greyscale format (trimg) that is compact and renders well on the device.
eBook Reader, of course we all love reading on an eInk screen. TernReader converts epub books into a compact binary format (trbk) so that rendering and reading will be fast and small on device.
There is a home screen which shows recents (images & books) by title and thumbnail and also provides access to the file browser to load additional content from the sdcard.
In addition to the firmware image for the device, there are 2 desktop command line tools: tern-image and tern-book
All of these can be found in the releases section in github.
Additional features:
.tri/.trimg/.trbk entries.The image viewer views full screen images in 4 color greyscale by selecting the image file in the file browser. Pressing right or left will display the previous or next image in that directory on the sdcard. This is handy, if you put all of your passes in the same directory on the sdcard. Pressing the power button will cause the device to sleep, leaving the image on the screen. The device will sleep in any case after 5 minutes of inactivity.
Opening a trbk file in the file browser will open the book for reading. Books retain original epub content including embedded images and ToC which can be used for navigation. Pressing down will advance to the next page, pressing up will go back to previous page. Fonts are rendered antialiased using the font specified at conversion time with tern-book.
| Button | Home | File Browser | Book Reader | Image Viewer | Sleep |
|---|---|---|---|---|---|
| Up | Move selection | Move selection | Previous page | Previous image | - |
| Down | Move selection | Move selection | Next page | Next image | - |
| Left | Switch to Actions | — | Previous page | Previous image | - |
| Right | Switch to Actions | — | Next page | Next image | - |
| Confirm | Open recent/action | Open | TOC / confirm | — | - |
| Back | — | Up one folder / Home | Back to Home | Back to Home | - |
| Power | Sleep | Sleep | Sleep | Sleep | Wake |
The tools are distributed in GitHub Releases for macOS, Linux, and Windows.
Convert images (tern-image):
# Defaults are already 480x800, fit=width, dither=bayer.
tern-image convert input.png output.tri
Convert images with YOLO barcode/QR detection (recommended for QR/barcodes):
tern-image convert input.png output.tri \
--yolo-model tools/tern-image/model/YOLOV8s_Barcode_Detection.onnx
Convert books (tern-book):
tern-book input.epub sdcard/MyBook.trbk \
--font /System/Library/Fonts/Supplemental/Arial.ttf --sizes 24
--font) in TTF/OTF format.FontName Bold.ttfFontName Italic.ttfFontName Bold Italic.ttfGoto https://ternos.org/
Make sure you have some suitable content on the sdcard.
This repo was originally cloned from: https://github.com/HookedBehemoth/TrustyReader be sure to check back there. Since then book and image viewing have been added here.
There are two firmware images you can flash:
firmware.bin / tern-fw-<tag>.bin): contains only the app, meant to be written at 0x10000.ternfull-<tag>.bin): includes bootloader, partitions, boot_app0, and the app.Use the application image if you already have a working bootloader/partition table. Use the full merged image for a clean flash or if your device is blank.
cargo espflash flash --chip esp32c3 --target riscv32imc-unknown-none-elf \
--partition-table partition-table.bin \
--bootloader bootloader.bin \
--boot-app0 boot_app0.bin \
--baud 921600 \
firmware.bin
./make_full_flash.sh
# then flash ternfull-<tag>.bin with your preferred tool, for example:
cargo espflash flash --chip esp32c3 --target riscv32imc-unknown-none-elf \
--baud 921600 \
ternfull-<tag>.bin
Try to put everything in Core, so you can run it on the desktop simulator.
The tern-image tool converts PNG/JPG into a mono1 .tri/.trimg format
optimized for the X4 portrait display (480x800). It also detects barcodes/QRs
and re-renders them without dithering for scan reliability.
Basic conversion (defaults: 480x800, fit=width, dither=bayer):
cargo run -p tern-image -- convert images/Waitrose.PNG images/Waitrose.tri
Explicit size/fit/dither:
cargo run -p tern-image -- convert input.png output.tri --size 480x800 --fit width --dither bayer
Enable debug output:
cargo run -p tern-image -- convert input.png output.tri --debug
Use YOLOv8 ONNX detector to refine barcode/QR bounding boxes:
cargo run -p tern-image -- convert input.png output.tri --debug \
--yolo-model tools/tern-image/model/YOLOV8s_Barcode_Detection.onnx
.onnx (not .pt/.safetensors).The tern-book tool converts EPUB into the pre-rendered .trbk format.
It runs as a library-first crate with a simple CLI.
Basic conversion with a single font and size:
cargo run -p tern-book -- input.epub sdcard/MyBook.trbk \
--font /System/Library/Fonts/Supplemental/Arial.ttf \
--sizes 18
Multiple output sizes in one pass:
cargo run -p tern-book -- input.epub sdcard/MyBook.trbk \
--font /System/Library/Fonts/Supplemental/Times\ New\ Roman.ttf \
--sizes 12,16,20
--font) in TTF/OTF format.FontName Bold.ttfFontName Italic.ttfFontName Bold Italic.ttftern-image outputs .tri/.trimg files. These are identical formats:
Offset Size Field
0x00 4 Magic "TRIM"
0x04 1 Version (u8) = 1
0x05 1 Format (u8) = 1 (mono1)
0x06 2 Width (u16 LE)
0x08 2 Height (u16 LE)
0x0A 6 Reserved (zeros)
0x10 ... Bitpacked pixels (row-major, MSB-first)
Payload length is ceil(width * height / 8). Total file size is 16 + payload.
TRIM v2 (gray2):
Offset Size Field
0x00 4 Magic "TRIM"
0x04 1 Version (u8) = 2
0x05 1 Format (u8) = 2 (gray2)
0x06 2 Width (u16 LE)
0x08 2 Height (u16 LE)
0x0A 6 Reserved (zeros)
0x10 ... Base (BW) bitplane
... ... LSB bitplane
... ... MSB bitplane
Each plane is ceil(width * height / 8) bytes. Total payload is 3 * plane.
TRBK is a pre-rendered book format generated on desktop. It keeps the firmware fast and low-memory by moving EPUB parsing/layout off-device.
Header (v2):
Tables/blocks:
u32 offsets into page data0x01 TextRun: x, y, style, utf-8 text0x02 Image: x, y, w, h, image indexThe device streams pages from the LUT and renders ops directly.
/sdcard in desktop..trbk opens the book reader, .tri/.trimg open the image viewer..epub entries are shown but prompt for conversion..tri/.trimg in portrait orientation.12 commits
Rust
54.1%
C
45.4%
TernOS - A rust based firmware with reading and PalmOS functionality for XTEink X4 pocket reader
See the codeEasy flashing + file conversion: Use the web app at https://ternreader.org to flash the latest firmware and convert images/EPUBs for XTEink X4.
All of the existing firmwares for these devices are single application firmwares e.g. Crosspoint, i.e. one app delivered as a firmware which means that you can't do anything else on the device.
TernOS aims to be a more general purpose OS, taking it's inspiration from the defunct PalmOS, it provides system / hardware services, a rich UI library, database services and apps and databases as loadable resources. It also emulates the original Palm 68k hardware so you can run most of the original Palm apps.
see docs/ui-layer.md
Complete
ternos::services::db.prc_app to palm, clarifying the architecture boundary.DmNumRecordsDmRecordInfoDmQueryRecordDmNewRecordDmResizeRecordDmReleaseRecordDmSetDmWrite/db.Outstanding
ternos::services::* APIs.Complete
Outstanding
Complete
palm/ rather than prc_app/.Outstanding
Complete
Outstanding
tern-native PRCs with manifest-driven entrypoint selection.docs/ternos.md is only partially realized.rust-srccargocargo-espflash / espflashriscv32imc-unknown-none-elf)espupsource /Users/Me/export-esp.shespflashm5paper uses a vendored arduino-esp32 component under third_party/arduino-esp32, and the build runs with the ESP-IDF component manager disabled for repeatable builds.
cargo run --package tern-desktop
Build, flash, and monitor:
./run-x4.sh
Manual build only:
cargo espflash save-image --release --chip=esp32c3 --target=riscv32imc-unknown-none-elf --package=tern-x4 firmware.bin
In each new shell, load the ESP environment first:
source /Users/andrew/export-esp.sh
Build, flash, and monitor:
./run-m5.sh
Manual build only:
cd m5paper
cargo +esp build --release
The script cleans the ESP-IDF build products, rebuilds m5paper, locates the generated m5paper/espidf/build/tern_m5paper_rust_host.elf, and flashes it with espflash.
This firmware focuses on two usecases and aims to do each well:-
Wallet for loyalty cards, tickets, boarding passes etc. eInk has the great advantage in that the display is persistent and therefore can function even when the device has no power. We convert images into a 4 color greyscale format (trimg) that is compact and renders well on the device.
eBook Reader, of course we all love reading on an eInk screen. TernReader converts epub books into a compact binary format (trbk) so that rendering and reading will be fast and small on device.
There is a home screen which shows recents (images & books) by title and thumbnail and also provides access to the file browser to load additional content from the sdcard.
In addition to the firmware image for the device, there are 2 desktop command line tools: tern-image and tern-book
All of these can be found in the releases section in github.
Additional features:
.tri/.trimg/.trbk entries.The image viewer views full screen images in 4 color greyscale by selecting the image file in the file browser. Pressing right or left will display the previous or next image in that directory on the sdcard. This is handy, if you put all of your passes in the same directory on the sdcard. Pressing the power button will cause the device to sleep, leaving the image on the screen. The device will sleep in any case after 5 minutes of inactivity.
Opening a trbk file in the file browser will open the book for reading. Books retain original epub content including embedded images and ToC which can be used for navigation. Pressing down will advance to the next page, pressing up will go back to previous page. Fonts are rendered antialiased using the font specified at conversion time with tern-book.
| Button | Home | File Browser | Book Reader | Image Viewer | Sleep |
|---|---|---|---|---|---|
| Up | Move selection | Move selection | Previous page | Previous image | - |
| Down | Move selection | Move selection | Next page | Next image | - |
| Left | Switch to Actions | — | Previous page | Previous image | - |
| Right | Switch to Actions | — | Next page | Next image | - |
| Confirm | Open recent/action | Open | TOC / confirm | — | - |
| Back | — | Up one folder / Home | Back to Home | Back to Home | - |
| Power | Sleep | Sleep | Sleep | Sleep | Wake |
The tools are distributed in GitHub Releases for macOS, Linux, and Windows.
Convert images (tern-image):
# Defaults are already 480x800, fit=width, dither=bayer.
tern-image convert input.png output.tri
Convert images with YOLO barcode/QR detection (recommended for QR/barcodes):
tern-image convert input.png output.tri \
--yolo-model tools/tern-image/model/YOLOV8s_Barcode_Detection.onnx
Convert books (tern-book):
tern-book input.epub sdcard/MyBook.trbk \
--font /System/Library/Fonts/Supplemental/Arial.ttf --sizes 24
--font) in TTF/OTF format.FontName Bold.ttfFontName Italic.ttfFontName Bold Italic.ttfGoto https://ternos.org/
Make sure you have some suitable content on the sdcard.
This repo was originally cloned from: https://github.com/HookedBehemoth/TrustyReader be sure to check back there. Since then book and image viewing have been added here.
There are two firmware images you can flash:
firmware.bin / tern-fw-<tag>.bin): contains only the app, meant to be written at 0x10000.ternfull-<tag>.bin): includes bootloader, partitions, boot_app0, and the app.Use the application image if you already have a working bootloader/partition table. Use the full merged image for a clean flash or if your device is blank.
cargo espflash flash --chip esp32c3 --target riscv32imc-unknown-none-elf \
--partition-table partition-table.bin \
--bootloader bootloader.bin \
--boot-app0 boot_app0.bin \
--baud 921600 \
firmware.bin
./make_full_flash.sh
# then flash ternfull-<tag>.bin with your preferred tool, for example:
cargo espflash flash --chip esp32c3 --target riscv32imc-unknown-none-elf \
--baud 921600 \
ternfull-<tag>.bin
Try to put everything in Core, so you can run it on the desktop simulator.
The tern-image tool converts PNG/JPG into a mono1 .tri/.trimg format
optimized for the X4 portrait display (480x800). It also detects barcodes/QRs
and re-renders them without dithering for scan reliability.
Basic conversion (defaults: 480x800, fit=width, dither=bayer):
cargo run -p tern-image -- convert images/Waitrose.PNG images/Waitrose.tri
Explicit size/fit/dither:
cargo run -p tern-image -- convert input.png output.tri --size 480x800 --fit width --dither bayer
Enable debug output:
cargo run -p tern-image -- convert input.png output.tri --debug
Use YOLOv8 ONNX detector to refine barcode/QR bounding boxes:
cargo run -p tern-image -- convert input.png output.tri --debug \
--yolo-model tools/tern-image/model/YOLOV8s_Barcode_Detection.onnx
.onnx (not .pt/.safetensors).The tern-book tool converts EPUB into the pre-rendered .trbk format.
It runs as a library-first crate with a simple CLI.
Basic conversion with a single font and size:
cargo run -p tern-book -- input.epub sdcard/MyBook.trbk \
--font /System/Library/Fonts/Supplemental/Arial.ttf \
--sizes 18
Multiple output sizes in one pass:
cargo run -p tern-book -- input.epub sdcard/MyBook.trbk \
--font /System/Library/Fonts/Supplemental/Times\ New\ Roman.ttf \
--sizes 12,16,20
--font) in TTF/OTF format.FontName Bold.ttfFontName Italic.ttfFontName Bold Italic.ttftern-image outputs .tri/.trimg files. These are identical formats:
Offset Size Field
0x00 4 Magic "TRIM"
0x04 1 Version (u8) = 1
0x05 1 Format (u8) = 1 (mono1)
0x06 2 Width (u16 LE)
0x08 2 Height (u16 LE)
0x0A 6 Reserved (zeros)
0x10 ... Bitpacked pixels (row-major, MSB-first)
Payload length is ceil(width * height / 8). Total file size is 16 + payload.
TRIM v2 (gray2):
Offset Size Field
0x00 4 Magic "TRIM"
0x04 1 Version (u8) = 2
0x05 1 Format (u8) = 2 (gray2)
0x06 2 Width (u16 LE)
0x08 2 Height (u16 LE)
0x0A 6 Reserved (zeros)
0x10 ... Base (BW) bitplane
... ... LSB bitplane
... ... MSB bitplane
Each plane is ceil(width * height / 8) bytes. Total payload is 3 * plane.
TRBK is a pre-rendered book format generated on desktop. It keeps the firmware fast and low-memory by moving EPUB parsing/layout off-device.
Header (v2):
Tables/blocks:
u32 offsets into page data0x01 TextRun: x, y, style, utf-8 text0x02 Image: x, y, w, h, image indexThe device streams pages from the LUT and renders ops directly.
/sdcard in desktop..trbk opens the book reader, .tri/.trimg open the image viewer..epub entries are shown but prompt for conversion..tri/.trimg in portrait orientation.12 commits
Rust
54.1%
C
45.4%