STATE.md was five days stale. It now carries what is on the phone (viewtop r76, souveraine r333) and the four defects fixed on the glass: per-window capture was unreachable because quickshell holds wlr handles and the ext capture source is named by an ext handle with nothing correlating them; titles were never republished on commit; the border was a filled slab that relied on the client covering its middle; capture came back flipped. Also the packaging hole, which was the important one — viewtop's PKGBUILD existed and appeared in none of packages.yml's build lists, so nothing ever built it. Half closed: it builds now, but a viewtop commit still does not trigger a rebuild. TASK-15 question 1 is answered and closed: dropping the accelerometer claim took iio-sensor-proxy from 15.3% to 1.1%, sensors overall 17.2% to 2.6% of a core. Consequence noted against 08(g) — confidence loses accel's +0.3. New: 54, 55, 56, and 57/58 (Pi dock head, SMB2 OTG boost) with the USB notes they point at.
99 lines
5.6 KiB
Markdown
99 lines
5.6 KiB
Markdown
# TASK 57 — the Pi dock head
|
||
|
||
**Status: open.** Created 2026-08-04, from Casey: *"I need a 'I plugged in
|
||
this dock and my pixel 3 screens lit up' system"* — the Pi 4 becomes the
|
||
phone's display and input head. The phone stays a gadget (device mode —
|
||
charging and tethering keep working), the Pi is the host that drives the
|
||
monitor and the dock's peripherals, and the phone's desktop streams to it
|
||
over the existing NCM link. Rejected paths, already argued: scrcpy (Android
|
||
only — no ADB on mainline), waypipe (forwards *apps*, not a shell; our shell
|
||
is a compositor, not forwardable), and DP alt-mode (unwired/unknown on
|
||
blueline — the Pi bridge works today).
|
||
|
||
**Repos:** the phone side is `souveraine-viewtop` (capture) + the phone
|
||
kernel/userspace; the Pi side is its own OS (bring-up state unknown — "major
|
||
malfunctions" TBD, find them first).
|
||
|
||
## The topology
|
||
|
||
```
|
||
[Dell dock: keyboard/mouse + monitor] [Pixel 3, device mode]
|
||
│ HDMI / USB-A │
|
||
▼ USB-C→A
|
||
[Pi 4] ◄──────────────────────────────────────────────┘
|
||
│ NCM link (usb0, 172.16.42.x) — phone compositor
|
||
│ capture → Venus H.264 → out over the cable
|
||
└── always-on: udev sees the phone's NIC → viewer fullscreen
|
||
```
|
||
|
||
The phone's port stays in the one mode that already works. The Pi's USB-A
|
||
port is a host: it sources VBUS (charges the phone, ~1.2 A shared), and the
|
||
phone's default developer gadget (NCM + ACM via usb-signaller) comes up the
|
||
moment the cable lands — no configuration on either side.
|
||
|
||
## What exists, measured
|
||
|
||
| Piece | Where | State |
|
||
|---|---|---|
|
||
| NCM gadget | usb-signaller default developer mode, `usb0` 172.16.42.1 | Live — WiFi SSH (`10.10.20.234` via wlan0) survives everything USB, so the management path is never at risk |
|
||
| Venus H.264 encoder | `/dev/video12`, decoder `/dev/video13` (v4l-utils 1.32.0-2) | Present; encoder idle and unproven at 1080p — load it first |
|
||
| Compositor capture | `souveraine-viewtop` — window capture landed (`86d0f93`) | Written and merged; **whether `zwlr_screencopy` exists on the wire is unverified** — if not, expose capture through our own IPC |
|
||
| Pi 4 | Casey's, bring-up TBD | Pi state unknown; needs OS + network check before anything |
|
||
| Link headroom | USB 2.0 HS, 480 Mbps vs H.264 1080p30 at ~5–10 Mbps | ~50× — bandwidth is not the constraint, latency is |
|
||
| Phone screen | 540×1080 portrait | The Pi must scale/rotate the stream to the monitor — free the Pi to do the transform (hardware scaler on the Pi 4) |
|
||
|
||
## Phases
|
||
|
||
1. **Pi bring-up** — what's on it, what's broken, network reach. Then plug
|
||
the phone into the Pi's USB-A: confirm the Pi sees a new NIC
|
||
(`172.16.42.1` pingable), the phone charges, tethering still works.
|
||
2. **Static chain** — phone: test pattern (or any source) → Venus H.264 →
|
||
NCM; Pi: decode (hardware) → fullscreen on HDMI. Proves the transport
|
||
before the capture exists. Latency budget: <100 ms is a usable desk;
|
||
measure, don't assume.
|
||
3. **Real capture** — phone: compositor capture → Venus encode → stream.
|
||
Trigger: the phone starts streaming when `usb0` has carrier (not the typec
|
||
udev event — blueline mainline has **no typec driver**, so usb-signaller's
|
||
cable monitor never fires; the NIC is the honest signal). Pi: udev rule on
|
||
the phone's gadget NIC → launch viewer.
|
||
4. **Input** — dock keyboard/mouse → Pi evdev → over the same cable → inject
|
||
into the phone's compositor via its IPC (both ends are ours). This is the
|
||
step that makes it a *dock* rather than a monitor.
|
||
5. **Parked — the car version.** A car head unit is the same problem with a
|
||
dashboard for a far end; the same bridge applies over NCM or WiFi.
|
||
"Android Auto" against *stock* head units is a separate universe — the AA
|
||
transport is closed Android proprietary userspace (the `f_accessory`/AOA
|
||
family lives in Android's kernel forks, not mainline), no open phone-side
|
||
implementation, zero kernel work involved. Not a task until Casey wants it
|
||
to be.
|
||
|
||
## Open questions
|
||
|
||
- Screencopy or custom capture IPC? (Determines the phone-side build.)
|
||
- Does the Venus encoder take the compositor's buffer format directly, or is
|
||
there a packing/stride hop (TASK-46 hit this with CAMSS)?
|
||
- Portrait 540×1080 vs monitor: stream native and let the Pi scale, or
|
||
rotate on the phone? (Native stream + Pi transform is simpler.)
|
||
- Latency target per use: desk cursor (<100 ms) vs video (<200 ms).
|
||
|
||
## Acceptance (measured)
|
||
|
||
- Plug the phone into the Pi's USB-A: the monitor lights up with the phone's
|
||
desktop within seconds, no interaction on either side, phone keeps
|
||
charging.
|
||
- The phone's own screen can be off/dimmed while the Pi shows the desktop.
|
||
- The laptop's shell and the phone's wifi networking are untouched by a dock
|
||
session.
|
||
- Dock keyboard/mouse drive the phone's desktop (Phase 4) with no visible
|
||
double-handling of input.
|
||
- A Pi that loses the phone exits cleanly and waits (no zombie viewer).
|
||
|
||
## Connects to
|
||
|
||
TASK-58 (host power — when the SMB2 boost lands, the phone can power the Pi
|
||
through the same cable, killing the Pi's wall wart), TASK-51 (the capture
|
||
punch list — the same capture feeds both UI verification and this stream),
|
||
TASK-54 (the frame-callback culling — the phone-side stream must not fight
|
||
the compositor's render budget), `USB/README.md` (the exploration record and
|
||
the rejected-paths argument), usb-signaller (the gadget side is already
|
||
built and default).
|