Skip to content

feat(d211-linux): audio and backlight host modules - #417

Draft
boa-z wants to merge 7 commits into
pocket-stack:mainfrom
boa-z:feat/d211-host-modules
Draft

feat(d211-linux): audio and backlight host modules#417
boa-z wants to merge 7 commits into
pocket-stack:mainfrom
boa-z:feat/d211-host-modules

Conversation

@boa-z

@boa-z boa-z commented Sep 12, 2026

Copy link
Copy Markdown

Stacked / draft: do not review before #407 (d211 host) and #416 (quickjs-c host-module hook) merge. This branch carries both until then; after they land it rebases to the single audio/backlight commit.

What

  • hosts/d211-linux/audio.c|h: PocketAudioOps on one aplay -t raw child per stream plus a feeder thread over a 16384-frame ring — credits follow consumption, starvation is edge-reported as underrun, endStream drains then reports ended, volume is a soft gain.
  • hosts/d211-linux/backlight.c|h: PocketBacklightOps over /sys/class/backlight/<name>/brightness, percent 0-100.
  • main.c installs both tables before boot; build-runtime.sh compiles the new sources and links -lpthread.

Validation (device)

  • Boot: host modules: audio + backlight, audio createStream handle=0 rate=22050 ch=2 (framework player loaded audio:wav.btn from the pak).
  • Button press: writePcmplay (aplay child) → poll {"t":"credit",...}endStream when the 4984-frame clip drains.
  • Brightness: UI slider writes sysfs (6 → 1 for a ~20% drag); panel dims.

ui_render, ui_render_scaled, and ui_render_incremental_scaled are exported C ABI functions the raster implementation already provides; the public header only declared the unscaled incremental form.
The D211DBV runs Luban Linux 5.10 on RISC-V with an 800x480 32bpp panel and
a GT911 touchscreen. The host presents the software raster surface through
/dev/fb0, probes the framebuffer geometry and channel bitfields with
FBIOGET_VSCREENINFO/FBIOGET_FSCREENINFO, fixes the visible page with
FBIOPAN_DISPLAY, and finds the touch device by capability instead of eventN.

The build runs on a canonical Ubuntu builder with the Luban Xuantie GCC
wrapper and sysroot; D211_LUBAN_SDK selects the SDK root. The final link
uses LLVM LLD from the pinned Rust nightly because binutils 2.35 rejects
modern RISC-V ELF attributes. The private d211-linux-dev target (host ABI
11) renders the full 800x480 panel at raster density 1, and
tools/d211-linux/remote-build.sh wraps sync, build, and artifact fetch with
the builder taken from D211_REMOTE.
The touch backend now runs the protocol-B slot state machine (ABS_MT_SLOT,
ABS_MT_TRACKING_ID, per-slot positions) and delivers every live contact
through pocket_runtime_tick_contacts(), with the bounds hit resolved once at
each contact's own down edge. Single-touch devices still map to one id-0
contact, and the host tracks up to D211_MAX_CONTACTS (8).

Validated against the panel with a local probe: five simultaneous contacts,
each id keeping its own coordinates and down-edge hit. stop-ui now sends
SIGKILL because test_lvgl ignores SIGTERM and keeps the panel.
The C runtime could install only the ui surface; native hosts had no way to
expose device services to the guest. Add two optional host op tables:

- PocketAudioOps installs globalThis.audio with the method set the audio spec
  already pins (contracts/spec/audio.ts); hosts fill the table before boot and
  leave it absent otherwise (the framework player stays a no-op).
- PocketBacklightOps installs globalThis.backlight { get, set(percent) } —
  pinned here until a display spec lands.

Both follow the existing ui-module installation shape; no wire changes, no
behavior change for hosts that pass no tables.
@boa-z
boa-z force-pushed the feat/d211-host-modules branch from 0aea628 to f61457f Compare September 12, 2026 06:49
@boa-z

boa-z commented Sep 12, 2026

Copy link
Copy Markdown
Author

Validation update (d211, ALSA): the credit queue originally reported one event per fed chunk, which flooded the 32-slot queue and dropped the ended event — the guest then stalled after one ring. Fixed with sequence-based coalescing (occupancy changes counted, not compared), a feeder paced by the stream rate (device clock) and a 150 ms aplay buffer so ended aligns with actual playback end. With that, the product's alarm voices loop exactly at clip length (overspeed 3.2 s vs 3.19 s clip, reverse 1.8 s vs 1.82 s) and the startup/button sounds play. Also switched the host's asset loading to mmap (file-backed pages are reclaimable; the 8.25 MB pak now leaves ~15 MB available on the 54 MB board instead of OOM-killing at ~8 MB).

Wire two host modules into the d211 runtime:

- audio: PocketAudioOps on top of one `aplay -t raw` child per stream and a
  feeder thread over a frame ring; credits follow consumption, starvation is
  edge-reported as underrun, endStream drains then reports ended; volume is a
  soft gain. Matches contracts/spec/audio.ts; the framework player now works
  unchanged (load("btn") -> createStream -> writePcm -> play -> credit).
- backlight: PocketBacklightOps over /sys/class/backlight (percent 0-100).

main.c sets both tables before boot; build-runtime.sh compiles the two new
sources and links -lpthread. The runtime-side hook is the quickjs-c commit
below (stacked PR).
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.

1 participant