Skip to content
 
 

Repository files navigation

CrossPoint Simulator

A desktop simulator for CrossPoint-based firmware. Compiles the firmware natively and renders the e-ink display in an SDL2 window. No device required. Can be used with forks of Crosspoint but any new methods added to the firmware will need to be stubbed.

Note

Platform support: macOS and Linux/WSL use different native compiler and library flags. Start from sample-platformio-macos.ini on macOS, or sample-platformio-linux-wsl.ini on Linux/WSL. Native Windows is not supported; use WSL and follow the Linux instructions.

Warning

This has been tested on ARM64 macOS (Apple Silicon, M4) and Ubuntu under WSL on Windows. Other platforms may need additional libraries or platform-specific stubs.

Prerequisites

SDL2 and curl must be installed on the host machine. Linux/WSL users also need OpenSSL development headers for MD5 support.

# macOS
brew install sdl2

# Linux — Debian/Ubuntu (including WSL)
sudo apt install libsdl2-dev libssl-dev

# Linux — Fedora/RHEL
sudo dnf install SDL2-devel openssl-devel

# Linux — Arch
sudo pacman -S sdl2 openssl

Integration

Add the simulator to your firmware's platformio.ini as a lib_dep and configure the [env:simulator] environment. Use the sample file for your host OS:

  • sample-platformio-macos.ini
  • sample-platformio-linux-wsl.ini

No scripts need to be copied into the firmware repo for the simulator to build. The simulator library automatically patches consumer-side compatibility issues from its own build script when PlatformIO fetches it as a dependency.

If you only want a self-contained simulator dependency, stop there.

If you also want the Run Simulator task to appear in the consuming repo's PlatformIO IDE task list (under the "Custom" folder), let the consuming project own the IDE task registration. Add custom_run_simulator_target_owner = project to [env:simulator], then add one project-level hook:

For a normal fetched dependency:

custom_run_simulator_target_owner = project

extra_scripts =
  pre:scripts/gen_i18n.py
  pre:scripts/git_branch.py
  pre:scripts/build_html.py
  post:.pio/libdeps/$PIOENV/simulator/run_simulator_project.py

For a local symlinked dependency:

custom_run_simulator_target_owner = project

extra_scripts =
  pre:scripts/gen_i18n.py
  pre:scripts/git_branch.py
  pre:scripts/build_html.py
  post:../crosspoint-simulator/run_simulator_project.py

Use the symlink form only when the Crosspoint repo and this crosspoint-simulator repo are checked out side by side and your lib_deps entry is:

simulator=symlink://../crosspoint-simulator

The custom_run_simulator_target_owner = project line tells the library-side hook not to register the same launcher a second time. Without that, closing one simulator window can immediately relaunch another because both the library hook and the project hook try to own run_simulator.

Do not point post: at run_simulator.py directly. That file is already auto-loaded via library.json and is the backward-compatible library hook.

The post: line above only exposes the task in the consuming project UI. The actual launcher logic still lives in this simulator repo.

Setup

Place EPUB books at ./fs_/books/ in the Crosspoint repo's root. This maps to the /books/ path on the physical SD card.

Build and run

Run this command from the Crosspoint project after you have added the [env:simulator] config to Crosspoint's platformio.ini file. Alternatively, if you added the project hook above, you can click "Build" from PlatformIO's IDE task list and then "Run Simulator" (nested under the "Custom" folder).

pio run -e simulator -t run_simulator

Controls

Key Action
↑ / ↓ Page back / forward (side buttons)
← / → Left / right front buttons
Return Confirm / Select
Escape Back
P Power
S Simulate sleep

When the simulator is on the sleep screen, pressing any mapped simulator key wakes it. Under the hood the simulator relaunches itself and reports a synthetic power-button wake, because the native build has no real ESP deep-sleep resume path.

Notes

Host-backed network flows: OPDS/catalog downloads and KOReader sync use the host's curl binary through simulator implementations of HTTPClient and esp_http_client. This keeps the firmware code path intact while allowing the desktop build to reach real HTTP/HTTPS services.

Mocked downloads: Set CROSSPOINT_SIM_HTTP_MOCK_ROOT to a folder of local fixtures to make host-backed HTTP requests return local files by basename before falling back to the real network. This is useful for SD-font testing because the firmware can request its normal release URLs while the simulator serves a local fonts.json and .cpfont files:

cd /path/to/firmware
python3 -m pip install -r lib/EpdFont/scripts/requirements.txt
python3 lib/EpdFont/scripts/build-sd-fonts.py \
  --only NotoSansExtended \
  --manifest \
  --base-url "https://github.com/crosspoint-reader/crosspoint-fonts/releases/download/local/"
CROSSPOINT_SIM_HTTP_MOCK_ROOT="$PWD/lib/EpdFont/scripts/output" \
  pio run -e simulator -t run

The mock still uses the firmware's normal manifest parsing, file download, write-to-SD, .cpfont validation, registry refresh, and font-selection flow.

File transfer: The simulator provides a native host implementation of CrossPointWebServer on http://127.0.0.1:8080/. It supports the browser file manager plus common WebDAV-style OPTIONS, PROPFIND, PUT, DELETE, MKCOL, MOVE, and COPY requests. WebDAV LOCK and UNLOCK return an explicit unsupported response because the native server does not enforce locks.

Firmware updates: OTA and SD-card firmware flashing are non-destructive in the simulator. The simulator stubs those update paths so the UI can be opened without flashing firmware or changing boot partitions.

Image previews: The simulator decodes JPEG and PNG files on the host and renders a rough grayscale preview through the firmware's normal image callbacks. This is meant to make image pages and PNG sleep overlays visible while testing desktop flows. It does not simulate device-specific e-ink image quality, refresh behaviour, or memory pressure.

Cache: On first open of an ebook, an "Indexing..." popup will appear while the section cache is built. If you see rendering issues after a code change that affects layout, delete ./fs_/.crosspoint/ to clear stale caches.

Warning

Upstream compatibility: The simulator mirrors interfaces used by Crosspoint. If Crosspoint adds or changes methods in a shared library and the simulator build reaches that code path, the simulator can fail to compile or link until a matching implementation or stub is added here. In many cases this is just a small no-op shim. Open a PR if the change is broadly applicable to CrossPoint-based forks.

About

Simulate Crosspoint firmware without flashing onto your device

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages