Files
galahad2lcd/internal/protocol/protocol.go
T
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

65 lines
1.7 KiB
Go

// Package protocol builds the USB packets that the Lian Li Galahad II LCD
// expects. It is a pure, dependency-free implementation of the framing used
// by the reference Rust/Python drivers.
//
// Each H.264 frame is split into one or more 512-byte USB packets. Every
// packet carries an 11-byte header:
//
// [0] report_id (0x02)
// [1] command (0x0D = send H.264)
// [2:6] total payload size (big-endian)
// [6:9] packet index, 3 bytes (big-endian, wraps)
// [9:11] chunk length in this packet (big-endian)
//
// followed by up to 501 bytes of frame data and zero padding.
package protocol
import (
"encoding/binary"
"fmt"
)
// Wire-level constants shared with the reference implementation.
const (
ReportIDVideo = 0x02
CmdSendH264 = 0x0D
HeaderSize = 11
PacketSize = 512
MaxPayloadSize = 501
)
// EncodePackets splits frame data into USB packets. It returns an error only
// when frame is empty, which would otherwise produce a malformed stream.
func EncodePackets(frame []byte) ([][]byte, error) {
if len(frame) == 0 {
return nil, fmt.Errorf("cannot encode empty frame")
}
var packets [][]byte
for offset, idx := 0, uint32(0); offset < len(frame); offset += MaxPayloadSize {
end := min(offset+MaxPayloadSize, len(frame))
chunk := frame[offset:end]
pkt := make([]byte, PacketSize)
pkt[0] = ReportIDVideo
pkt[1] = CmdSendH264
binary.BigEndian.PutUint32(pkt[2:6], uint32(len(frame)))
pkt[6] = byte(idx >> 16)
pkt[7] = byte(idx >> 8)
pkt[8] = byte(idx)
binary.BigEndian.PutUint16(pkt[9:11], uint16(len(chunk)))
copy(pkt[HeaderSize:HeaderSize+len(chunk)], chunk)
packets = append(packets, pkt)
idx++
}
return packets, nil
}
func min(a, b int) int {
if a < b {
return a
}
return b
}