Files
fds-os/docs/developer/dasung.md
T
2026-09-24 13:03:52 +08:00

10 KiB
Raw Blame History

Dasung Paperlike 13K base-system integration

Development reference and historical context. For current operating instructions, use the user manual. Acceptance applies only to the source and artifacts identified in each record.

Documentation index · First build · Services

FDS includes the Rust dasungd controller from the project's earlier Fix Dasung monitor black screen task. It targets the user's Paperlike 13K grayscale, serial L56051794302, with the confirmed 3200 × 2400 timing at about 37 Hz. This is core display support: its package is required for the base SYSTEM image, and its service belongs to the base boot bundle, including console-only use. It does not require an ENVIRONMENT cartridge, WindowMaker, or a graphical session.

Implementation boundary: the daemon, ARM package, and s6 service definitions are included by the rootfs assembler. M2 native init starts the controller in the base boot graph, including in the ARM VM with no monitor. The M4 boot path starts an early copy before SYSTEM exists, then stops and reaps it before base s6 starts the normal daemon. Software handoff is tested in a VM; physical Pi display and monitor recovery remain unverified. The final s6 database is compiled at image build time.

Build it on the workstation

Complete make bootstrap as described in Your first build, then run from the repository root, as your regular user:

make dasung
make dasung-test

The first command prepares the additional C cross compiler inside the existing Void build container, fetches the crates pinned in Cargo.lock, and cross-builds static-musl dasungd. It verifies the ELF, builds the fds-dasungd XBPS overlay, indexes the output, and compiles the actual s6 source into a validation database. The second runs unit tests and a simulated serial monitor, then inspects the package and compiles the service definitions extracted from that package. It also runs that s6 graph with a native test binary, a read-only container root, and no physical device access to check startup, logging, permissions, restart, and stop.

Python 3 is needed only on the host for the simulator. If absent on Arch, install python with pacman. No Python interpreter is shipped for the daemon. The first additional toolchain download is approximately 243 MB and needs roughly 1 GB of extra container space. Builds still depend on rolling Void binary inputs. Run these commands sequentially with other FDS builds; they share the container.

Output Purpose
out/dasungd Static AArch64 executable; no target glibc, musl, libusb, or libudev shared library dependency
out/packages/fds-dasungd-0.1.0_1.aarch64.xbps Target package with executable, config, exact EDID, s6 source, udev rule, and licenses
out/manifests/dasung-s6-database.txt Path to the service database compiled on the host for validation
out/manifests/dasung-artifacts.sha256 Executable and package hashes
out/manifests/dasung-build-packages.txt Installed build-container input versions
out/logs/dasung-build.log, dasung-checks.log Build and test evidence

The standalone validation database contains only the Dasung subset. The M2 image assembler merges it with the init package and compiles the full current graph while building the rootfs. No daemon is started on the workstation by these targets; the integration test uses its own temporary socket and pseudo-terminal.

What goes into the base system

image/base-packages.list makes fds-dasungd a mandatory hardware package. packages/fds-dasungd/template is the active FDS-owned XBPS overlay. The upstream Void tree remains pinned and unchanged. Source is maintained at rust/dasungd/; the original task directory is not required for future builds.

The package installs:

  • /usr/bin/dasungd and /etc/dasungd.toml.
  • /usr/lib/firmware/edid/dasung-paperlike13k-37hz.bin.
  • /etc/s6-rc/source/dasungd, its runtime-directory and log services, and the boot/contents.d/dasungd membership entry.
  • /usr/lib/udev/rules.d/99-dasung-spi.rules, adapted to eudev syntax.
  • Documentation and the controller/libusb licenses.

s6 supervises the foreground daemon. A short oneshot creates private writable runtime/log directories; it does not wait for the display. The daemon starts with no monitor attached and retries discovery. Its initial service transition does not wait for a monitor reply, a desktop, the network, or all cartridge bays. The log service rotates a small log under /run/log/dasungd.

The init package adds a dependency on runtime-fs so the controller starts with its kernel interfaces mounted. The service runs as root because it claims USB interfaces. Its socket is under a root-owned mode-0750 directory; runtime control is restricted to root. A future FDS CLI can expose selected operations through an explicit policy. No world-writable USB rule, systemd unit, or runit service is installed.

Confirmed profile and Pi-specific choices

Property Recorded value
Monitor Paperlike 13K grayscale; L56051794302
Resolution 3200 × 2400
Pixel clock 304210 kHz (304.21 MHz)
Horizontal active / sync start / sync end / total 3200 / 3248 / 3280 / 3360
Vertical active / sync start / sync end / total 2400 / 2423 / 2427 / 2447
Sync polarities Positive horizontal and vertical
EDID SHA-256 b6c1e0a8d315d9cf5c2fb83784a177530bcc085c2d0724dc7478a9c12449e4f4
Control transport USB UART 1a86:7523, with companion SPI bridge 1a86:5512
Startup parameters Raw mode 1 and contrast 4, previously read back on this unit
Keepalive 20 01 every two seconds; minimum 150 ms between command writes

The video timing was confirmed on the original AMD workstation, not on a Pi. The original USB-C video connection is not a Pi cabling prescription. Pi connector, cable/adapter, mode acceptance, and picture stability require hardware validation. For the current HDMI video plus USB control procedure, including separate monitor power and a reversible native-EDID experiment, use the display guide. Desktop 2× scaling is separate from EDID timing; a console uses its own font size.

FDS configures display.enabled=false and hotplug="none": the daemon handles USB control without applying the source project's AMD debugfs disconnect/reconnect procedure. The Pi boot/display integration must supply the appropriate KMS/firmware EDID configuration for its real connector. The Pi boot-volume builder now supplies an unqualified firmware EDID override for this dedicated monitor; it does not assume DP-2 or a numbered HDMI connector. See the boot guide for the exact command line and the remaining physical mode test.

The daemon requires the configured monitor's DRM EDID and the matching USB companion topology before claiming a device. Multiple matching UARTs are rejected; usb_path can disambiguate a verified Pi topology. Do not substitute a blanket match for all CH340 adapters or copy this unit's identity to a different monitor.

The original monitor's SPI driver interaction caused a dark picture after a power cycle. image/kernel/dasung.config requires CONFIG_SPI_CH341=n; the Pi kernel builder enforces this before boot, including the initramfs environment. The scoped udev rule is secondary protection: it cannot prevent a built-in or already-loaded SPI driver from probing. The daemon also reserves the companion interface without sending SPI data and refuses to take it from an already-bound kernel driver.

Runtime usage once installed in an FDS image

These are target commands, not commands to run against the workstation's live monitor during the build:

dasungd status
dasungd query
dasungd refresh
dasungd set contrast 4
dasungd set mode 1 --save
dasungd forget mode

status returns JSON including connected, responsive, reply age, and cached parameters. A successful set means a packet was sent; use query/status to check observed values. It is not proof of physical image quality. Color-model mode names are not assigned to this grayscale monitor's raw numeric modes.

The default socket is /run/dasungd/control.sock. External programs can use its newline-delimited JSON protocol; the daemon remains the only USB owner:

{"op":"status"}
{"op":"set","parameter":"contrast","value":4,"save":true}

In FDS's current payload, saved overrides live in /run/dasungd/settings.json. They survive a daemon restart within the same boot, but not power loss. Mode 1/contrast 4 are persistent image configuration defaults. Once persistent machine-state mounts are implemented, point state_file at that internal writable storage to retain user overrides across boots. Do not put it on read-only SYSTEM or make the base display daemon depend on a removable DATA cartridge.

Dependencies and source provenance

The imported Rust dependencies are retained and pinned by the workspace lockfile: rusb wraps USB access; libc supports Linux serial/locking calls; ctrlc handles termination; clap provides CLI parsing; serde, serde_json, and toml support configuration and the local socket; anyhow supplies contextual errors. Transitive versions are recorded in Cargo.lock.

The vendored feature builds libusb from the pinned libusb1-sys crate. The Void cross-aarch64-linux-musl toolchain supplies C headers/compiler for that library; Rust's bundled musl target alone was enough for the old pure-Rust smoke-test, but is insufficient for this C dependency. LIBUSB_NO_PKG_CONFIG and LIBUDEV_NO_PKG_CONFIG prevent accidental host/shared-library linkage. libusb uses its Linux netlink backend. No libusb/libudev shared runtime package is needed.

The target package depends on GNU coreutils for directory preparation, execline for service launch, s6/s6-rc for supervision, and eudev for device rules. These match the planned base userspace. The container's s6-rc is a build-time compiler, not a target PID 1 running on Arch.

Import provenance records the original source hashes. Original validation records the live handoff and remaining physical test. Protocol and reconnect tests use simulated hardware; Pi boot, image quality, physical disconnect/reconnect, and corrected cold-power recovery must still be verified on the actual target. No boot benchmark is claimed.