62 lines
2.1 KiB
Go
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)
|
|
}
|