# Dasung Paperlike 13K base-system integration [Documentation index](README.md) · [First build](getting-started.md) · [Services](services.md) 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](rootfs.md). [M2 native init](init.md) starts the controller in the base boot graph, including in the ARM VM with no monitor. The [M4 boot path](boot.md) 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](getting-started.md), then run from the repository root, as your regular user: ```sh 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. 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](boot.md) 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**: ```text 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: ```json {"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](../rust/dasungd/IMPORT.md) records the original source hashes. [Original validation](../rust/dasungd/VALIDATION.md) 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.