package kpa import "testing" // The reference's own examples, kept as the test. Every one of these strings is // quoted from the KPA1500 Programming Reference rather than invented here, so a // change that breaks the decoding fails against the document. func TestParseTheDocumentedExamples(t *testing.T) { t.Run("^WS — forward power and SWR", func(t *testing.T) { w, swr, err := parseWS("^WS1204 014;") if err != nil { t.Fatalf("unexpected error: %v", err) } if w != 1204 || swr != 1.4 { t.Errorf("got %d W, SWR %.1f; want 1204 W, SWR 1.4", w, swr) } }) // A KPA500 sends three digits for the watts. The split is on the space, so // the same code reads both amplifiers. t.Run("^WS from a KPA500 — three digits", func(t *testing.T) { w, swr, err := parseWS("^WS480 021;") if err != nil { t.Fatalf("unexpected error: %v", err) } if w != 480 || swr != 2.1 { t.Errorf("got %d W, SWR %.1f; want 480 W, SWR 2.1", w, swr) } }) t.Run("^VI — volts in tenths, amps whole", func(t *testing.T) { v, a, err := parseVI("^VI513 061;") if err != nil { t.Fatalf("unexpected error: %v", err) } if v != 51.3 || a != 61 { t.Errorf("got %.1f V, %d A; want 51.3 V, 61 A", v, a) } }) t.Run("^TM — heat sink temperature", func(t *testing.T) { c, err := parseInt("^TM045;", "^TM") if err != nil || c != 45 { t.Errorf("got %d, %v; want 45", c, err) } }) t.Run("^OS — operate or standby", func(t *testing.T) { for reply, want := range map[string]int{"^OS0;": 0, "^OS1;": 1} { got, err := parseInt(reply, "^OS") if err != nil || got != want { t.Errorf("%s → %d, %v; want %d", reply, got, err, want) } } }) t.Run("^BN — the K3 band numbering", func(t *testing.T) { n, err := parseInt("^BN05;", "^BN") if err != nil { t.Fatalf("unexpected error: %v", err) } if got := BandName(n); got != "20m" { t.Errorf("^BN05 → %q, want 20m", got) } if got := BandName(10); got != "6m" { t.Errorf("^BN10 → %q, want 6m", got) } }) } // ^FL is HEX. Read as decimal, 90 and 91 — reflected power and "antenna not // connected" — become 144 and 145 and match nothing at all, so the amplifier // would be shut down by a fault OpsLog could not name. func TestFaultCodesAreHex(t *testing.T) { code, err := parseFault("^FL91;") if err != nil { t.Fatalf("unexpected error: %v", err) } if code != 0x91 { t.Fatalf("^FL91 → %d, want %d (0x91)", code, 0x91) } if name := FaultName(code); name == "" || name == "fault 91" { t.Errorf("0x91 should be named, got %q", name) } if got := FaultName(0); got != "" { t.Errorf("no fault should be empty, got %q", got) } // A code from a firmware newer than this table still says something. if got := FaultName(0xAB); got != "fault AB" { t.Errorf("unknown code → %q, want \"fault AB\"", got) } } // Answers to somebody else's question are refused rather than misread. On a // serial line shared with the amplifier's own utility, or on the first read // after a reconnect, a stale reply is still in flight. func TestPayloadRefusesAnotherCommandsAnswer(t *testing.T) { if _, _, err := parseWS("^VI513 061;"); err == nil { t.Error("a ^VI answer was accepted as ^WS") } if _, err := parseInt("^TM045;", "^PC"); err == nil { t.Error("a ^TM answer was accepted as ^PC") } }