# galahad2lcd A modern Go driver for the **Lian Li Galahad II LCD** cooler display. It transcodes a video or GIF to H.264 and streams it over USB to the 480×480 LCD, running as a systemd service. This is a clean-room rewrite of the archived [GalahadII_LCD_Linux](https://github.com/H4rk3nz0/GalahadII_LCD_Linux) project. It keeps the exact wire protocol but drops the fragile FFmpeg C-ABI dependency in favour of the system `ffmpeg` binary, adds structured logging, automatic USB reconnection and a testable, layered architecture. ## Features - `daemon` — transcodes media to H.264 and streams it in a loop - `set` — change the input/rotation/speed and restart the service - `list` — enumerate USB devices to diagnose connectivity - `version` — print the build version - Automatic reconnect if the USB link is lost (e.g. after suspend) - Graceful shutdown on SIGINT/SIGTERM (`systemctl stop` works cleanly) - Structured logs (`log/slog`) captured by journald - Rotation, playback speed and framerate overrides via config or flags ## Requirements - Go 1.22+ (to build) - FFmpeg + FFprobe (any recent version, e.g. `sudo pacman -S ffmpeg`) - libusb (transitive build dependency of `github.com/google/gousb`) - systemd ## Install ```sh sudo ./packaging/install.sh /path/to/media.gif ``` The script builds the binary, installs the systemd unit and udev rule, writes an initial config and starts the service. If no media file is given, configure it afterwards: ```sh sudo galahad2lcd set --input /path/to/media.gif --rotate 0 ``` ## Configuration Settings live in `/etc/galahad2lcd.toml`: ```toml [display] input = "/home/user/media.gif" rotate = 0 # 0, 90, 180, 270 (clockwise) speed = 1.0 # >1 slower, <1 faster [usb] vendor_id = 0x0416 product_id = 0x7395 [stream] fps = 0 # 0 = auto-detect from the source cache_path = "/tmp/galahad_cache.h264" ``` The `set` command updates this file and restarts the service: ```sh sudo galahad2lcd set --input /home/user/media.gif --rotate 90 --speed 1.2 sudo galahad2lcd set --fps 15 --no-restart # apply later ``` CLI flags also override the config for one-off runs: ```sh sudo galahad2lcd daemon --input /home/user/media.gif --rotate 180 ``` ## Diagnostics ```sh galahad2lcd list # find the LCD on the USB bus (needs udev rule or root) journalctl -u galahad2lcd -f # live daemon logs ``` The bundled udev rule (`packaging/99-galahad2lcd.rules`) grants the logged-in session user access to the device so `list` works without root. ## Architecture ``` cmd/galahad2lcd entry point (composition root) internal/cli cobra commands: daemon, set, list, version internal/config TOML configuration model, load/save/validate internal/transcoder ffmpeg/ffprobe wrapper, filter graph, FPS detection internal/h264 Annex-B stream → access-unit splitting (pure Go) internal/stream frame-rate pacing loop (testable, device-agnostic) internal/device Device interface + gousb (libusb) implementation internal/protocol USB framing (pure functions, golden-tested) internal/service systemd unit management ``` Layers depend only downward. `stream` talks to a `device.Device` interface, so the transport can be swapped or faked in tests without touching the rest of the pipeline. ## Development ```sh make build # build ./bin/galahad2lcd make test # unit + integration tests (integration needs ffmpeg) make vet # go vet make fmt # gofmt make install # copy binary to /usr/local/bin ``` ## Uninstall ```sh sudo ./packaging/uninstall.sh ``` ## License MIT