Files
groundstation/internal/display/osd.go
T

62 lines
2.1 KiB
Go

package display
import (
"git.piksar.eu/piotr/groundstation/internal/osd"
)
// SnapshotSource serves the latest supervisor-published OSD snapshot while
// it is fresh. The file-backed implementation lives in the osd package; the
// template only consumes the contract.
type SnapshotSource interface {
Latest() (osd.Snapshot, bool)
}
// OSDTemplate is the flight OSD layout of a display target: a transparent,
// input-transparent surface above pilot video. While decoded video is
// absent the fallback canvas owns the screen and the OSD presents nothing;
// while video is present the OSD draws deliberately minimal telemetry from
// the latest published snapshot — arm state and requested CH6 WFB power.
// The rendering gate is the video presence the display observes on the
// display server, never the snapshot's Video field: the supervisor's field
// is its launcher knowledge, while the display trusts only the presented
// video output itself. The OSD never draws the fallback: it is a telemetry
// surface, not a video substitute, and WFB or video decode never move into
// the UI process to feed it. The OSD refreshes on its own slower cadence
// than the video and the video window keeps rendering priority.
type OSDTemplate struct {
video *VideoPresence
source SnapshotSource
}
// NewOSDTemplate builds the OSD surface for a target from the shared video
// presence and the supervisor-published snapshot source.
func NewOSDTemplate(video *VideoPresence, source SnapshotSource) OSDTemplate {
return OSDTemplate{video: video, source: source}
}
func (t OSDTemplate) Draw(canvas Canvas) {
canvas.Clear()
if t.video.Active() {
if snapshot, ok := t.source.Latest(); ok {
drawOSD(canvas, snapshot)
}
}
canvas.Flush()
}
// drawOSD renders the deliberately minimal flight telemetry: two short
// lines in the top-left corner. The full final RC state stays in the
// snapshot; the pilot-facing overlay stays terse.
func drawOSD(canvas Canvas, snapshot osd.Snapshot) {
arm := "OFF"
if snapshot.Armed {
arm = "ARMED"
}
power := "OFF"
if snapshot.Power {
power = "ON"
}
canvas.Text(32, 32, "ARM "+arm)
canvas.Text(32, 64, "PWR "+power)
}