Files
Maksim Totmin 4c34f0bedc Initial commit: Go driver for the Lian Li Galahad II LCD
Streams H.264 to the Galahad II LCD via USB (gousb) with:
- ffmpeg CLI transcoding (no fragile FFmpeg C-ABI bindings)
- pure-Go Annex-B access-unit splitting
- framerate pacing with graceful shutdown and USB reconnect
- TOML config, cobra CLI, structured slog logging, unit tests
2026-08-19 12:03:54 +07:00

123 lines
3.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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