Files
OpsLog/amps_linked_test.go
T
rouggy d0c6e420d2 feat(amp): command linked amplifiers together for a combiner
The SPE CO1-2 combiner is an RF device: it sums two amplifiers and commands
nothing. So "combined" operation is really two amplifiers that must be held in
the same state, and one left in STANDBY while the other keys means the combiner
sees power on a single input.

A switch in Settings → Amplifier makes ON, OFF and OPERATE act on every
configured amplifier. Offered only with two or more: coupling one amplifier to
itself is a switch that cannot do anything.

The METERS stay per amplifier, deliberately. Two amps combined are still two
amps, and an operator watching for one of them to run away needs to see them
apart — a summed bar would hide exactly the fault worth catching.

Fanned out in AmpOperate/AmpPower rather than in the UI: the card and the docked
widget both call these, and a coupling built into one would be missing from the
other, which on a combiner means one amplifier keyed and one not. The clicked
amplifier goes first, so a partial failure still did what the operator asked
before it stopped.

While linked, an amplifier with no power command — a PGXL on its direct link —
is skipped silently rather than reported: it would make a successful pair look
broken.
2026-08-13 14:02:34 +02:00

37 lines
1.1 KiB
Go

package main
import (
"sort"
"testing"
)
// A combiner sums two amplifiers and commands nothing, so "combined" operation
// is really two amplifiers that must be kept in the same state. Leaving one in
// OPERATE while the other sits in STANDBY is exactly what must not happen —
// the combiner would then see power on one input only.
func TestAmpTargets(t *testing.T) {
a := &App{}
a.ampInsts = map[string]*ampInst{"left": {}, "right": {}, "third": {}}
// Unlinked: only the amplifier that was clicked.
if got := a.ampTargets("left", false); len(got) != 1 || got[0] != "left" {
t.Errorf("unlinked = %v, want just [left]", got)
}
// Linked: every running amplifier, and the one clicked FIRST — a partial
// failure should still have done what the operator asked before it stopped.
got := a.ampTargets("right", true)
if len(got) != 3 {
t.Fatalf("linked = %v, want all three", got)
}
if got[0] != "right" {
t.Errorf("clicked amplifier is %q, want it first", got[0])
}
rest := append([]string{}, got[1:]...)
sort.Strings(rest)
if rest[0] != "left" || rest[1] != "third" {
t.Errorf("rest = %v, want the other two", rest)
}
}