Skip to content

reMarkable 2 support (ARM32 + AppLoad/qtfb)#19

Open
mariomosca wants to merge 1 commit into
MaximeRivest:mainfrom
mariomosca:remarkable2-support
Open

reMarkable 2 support (ARM32 + AppLoad/qtfb)#19
mariomosca wants to merge 1 commit into
MaximeRivest:mainfrom
mariomosca:remarkable2-support

Conversation

@mariomosca

Copy link
Copy Markdown

What

Makes riddle run on the reMarkable 2 (rM2, ARM32) under xovi + AppLoad in qtfb mode, alongside the existing Paper Pro takeover path. Everything is gated on the takeover flag / runtime backend, so Paper Pro behaviour is unchanged.

I ran it end-to-end on an rM2 (firmware 3.27.3.0): the page opens, pen strokes render, the ink fades, and the oracle (Claude via an OpenAI-compatible endpoint) replies in a flowing hand. 🖋️

Why these changes

Debugging the qtfb backend on-device surfaced a few rM2/AppLoad specifics:

  • pen.rsfind_marker_device() only matched "marker" (Paper Pro). The rM2 pen enumerates as "Wacom I2C Digitizer", so I also match "wacom"/"digitizer".

  • qtfb.rs — the AppLoad shim's ServerMessage puts the InitResponse union at offset 4 (shm_key @4, shm_size @8), not @8/@16, and publishes the framebuffer as a POSIX object opened with shm_open("/qtfb_<key>"). The old offsets read the size as the key and produced a nonexistent /qtfb_<size> name → ENOENT. user_input events are likewise @4/@8/@12/@16/@20. Verified on-device against the shim wire format (matches the canonical zqtfb client).

  • main.rs — in qtfb mode, don't open the raw evdev pen: the shim intercepts the digitizer and delivers pen events over the QTFB socket, so the raw device yields nothing and the event loop was skipping the qtfb pen path whenever pen_dev.is_some(). Now raw evdev is opened only in takeover mode.

  • main.rs — a corner-tap quit for qtfb/AppLoad (there's no touch device there for the 5-finger tap): a finger tap in the top-right corner exits cleanly.

  • main.rs — coalesce qtfb flushes at 20 ms (~50 Hz) for a more continuous stroke over the IPC round-trip.

  • oracle.rs — strengthen the persona so it always replies in the writer's language (it was defaulting to English for non-English input). Happy to split this into its own PR if you'd prefer to keep this one hardware-only.

Notes

  • No changes to the takeover/quill path; the takeover feature builds as before.
  • Cross-built for armv7-unknown-linux-gnueabihf (rM2 has GLIBC 2.39, binary needs ≤ 2.34).
  • Glad to adjust naming, gate flags, or split commits however fits the project.

Makes riddle build and run on the reMarkable 2 (rM2, ARM32) under
xovi + AppLoad in qtfb mode, in addition to the Paper Pro takeover path.
All changes are gated so Paper Pro / takeover behaviour is unchanged.

Fixes needed for the rM2 / AppLoad qtfb backend:

- pen.rs: find_marker_device() also matches "wacom"/"digitizer" — the
  rM2 pen reports as "Wacom I2C Digitizer" (Paper Pro reports "...marker").

- qtfb.rs: the AppLoad shim's ServerMessage places the InitResponse union
  at offset 4 (shm_key @4, shm_size @8), not @8/@16, and publishes the
  buffer as a POSIX object opened with shm_open("/qtfb_<key>"). The old
  offsets picked up the size as the key and produced a nonexistent
  /qtfb_<size> name -> ENOENT. Input (user_input) events are likewise at
  @4/@8/@12/@16/@20. Verified on-device against the shim protocol.

- main.rs: in qtfb mode do NOT open the raw evdev pen — the shim intercepts
  the digitizer and delivers pen events over the QTFB socket, so the raw
  device yields nothing and the event loop was skipping the qtfb pen path
  whenever pen_dev.is_some(). Only open raw evdev in takeover mode.

- main.rs: add a corner-tap quit gesture for qtfb/AppLoad (no touch device
  there for the 5-finger tap) — a finger tap in the top-right corner exits.

- main.rs: coalesce qtfb flushes at 20ms (~50Hz) for a more continuous
  stroke over the IPC round-trip to the shim.

- oracle.rs: strengthen the persona instruction to always reply in the
  writer's language (it was defaulting to English for non-English input).
@serenasensini

Copy link
Copy Markdown

Hi @mariomosca! It seemed we had the same idea :)

Great work on this PR - I’ve been testing and extending the rm2 port on my side, and I’d be happy to contribute the additional changes if useful.

Compared to #19, my branch currently adds a few follow-up pieces that seem complementary:
• rm2 feature gating + rm2 screen geometry (fb.rs)
• 32-bit-safe evdev parsing (EV_SIZE/EV_OFF) in pen/touch paths
• rm2 pen mapping calibration (axis swap + Y inversion) and configurable pressure threshold (RIDDLE_PEN_MIN_PRESSURE)
• rm2 touch device support (pt_mt)
• quill 32-bit QImage constructor hook (needed to capture framebuffer pointers on rm2)
• build/bundle script parametrization for DEVICE=rm2 / SDK=...
• onboarding/docs for rm2 bring-up

I don’t want to step on ongoing work here, so I wanted to ask what you’d prefer:
• I can coordinate with this PR and split/cherry-pick only the missing parts, or
• I can open a separate follow-up PR scoped only to the additions above (referencing #19).

Happy to proceed in whichever way is easiest for review/merge.

You can find my fork and updated changes in here.

icetingyu added a commit to icetingyu/riddle that referenced this pull request Jul 13, 2026
…ample

The forced-Traditional-Chinese persona was a personal preference; match
the writer's language instead (same wording as upstream PR MaximeRivest#19 so the
strings merge cleanly). The reply font stays configurable via
RIDDLE_FONT, now documented.
yeedle added a commit to yeedle/riddle-rm2 that referenced this pull request Jul 17, 2026
Apply PR MaximeRivest#19 (32-bit AppLoad shim ServerMessage offsets,
shm_open, no raw evdev pen under qtfb) and build on it:

- fb.rs: rm2 panel dims only for takeover builds; windowed qtfb always
  presents a 1620x2160 canvas scaled to the device (fixes dead right/bottom
  margin where ink was neither committed nor faded)
- visible close button top-right (pen or finger); the corner-tap
  gesture's break never actually exited the main loop
- written farewells: close/exit/quit/goodbye as the only word closes the app
- Display::deghost — one GC16-quality pass after the drink-fade and after a
  reply finishes; kills UFAST dither blotches and pale handwriting remnants
- RIDDLE_PERSONA_EXTRA env hook: extend the persona from oracle.env without
  rebuilding
- font: Patrick Hand (print-style, child-readable) instead of Dancing Script
- qtfb flush 20ms -> 10ms; scripts/riddle-start.sh launcher that sources
  oracle.env (the binary does not read it itself)
- README: rM2 prerequisites (Qt6/OS>=3.9), armv7 Docker build recipe,
  deploy layout, close/reset/personalize docs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants