From dad71e9e4f493b9575c748fd6a1a8c61fdcceb0a Mon Sep 17 00:00:00 2001 From: rouggy Date: Wed, 26 Aug 2026 20:59:31 +0200 Subject: [PATCH] fix(tci): a filter button does what it says, and mute is put under a log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 250 now means 0-250. It meant 575-825: the width was right and it was centred on the CW note, on the reasoning that a CW filter should contain the note. That reasoning may be right for a radio and it is still wrong here, because it is not what the button says — and a button that does not do what it says is worse than one that does something simple. The two edges are editable underneath for anything else, which is what TCI takes anyway. And MUTE still lights the squelch on a real radio. Nothing in this code can do that — the button sends mute and only mute, and the two are separate state — so the radio's own announcements are logged as they arrive. What it says after the command will settle whether this is our reading or its doing; no more reasoning from here will. --- frontend/src/components/TCIPanel.tsx | 29 +++++++++++++++++++--------- internal/cat/tci_panel.go | 8 ++++++++ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/TCIPanel.tsx b/frontend/src/components/TCIPanel.tsx index 103b191..03c8d4d 100644 --- a/frontend/src/components/TCIPanel.tsx +++ b/frontend/src/components/TCIPanel.tsx @@ -47,15 +47,16 @@ function widthLabel(w: number): string { return w >= 1000 ? `${(w / 1000).toFixed(1)}k` : String(w); } -// edgesFor turns a width into the pair TCI wants. Narrow filters are centred on -// the CW note: a 250 Hz filter from 100 to 350 would put the note outside its -// own passband. -function edgesFor(w: number, mode: string): { lo: number; hi: number } { - const cw = /CW/i.test(mode); - if (cw || w <= 1000) { - return { lo: Math.max(0, CW_PITCH - Math.round(w / 2)), hi: CW_PITCH + Math.round(w / 2) }; - } - return { lo: 100, hi: 100 + w }; +// edgesFor turns a width into the pair TCI wants: 0 to the width, and nothing +// clever. +// +// It centred narrow filters on the CW note first — 250 became 575-825 — on the +// reasoning that a CW filter should contain the note. That reasoning may even be +// right for a radio, but it is not what the button says, and a button that does +// not do what it says is worse than one that does something simple. 250 means +// 0-250. The two edges are editable underneath for anything else. +function edgesFor(w: number, _mode: string): { lo: number; hi: number } { + return { lo: 0, hi: w }; } // dBm → S units. TCI reports a real signal level rather than a meter position, @@ -311,6 +312,16 @@ export function TCIPanel({ onReportRST }: { onReportRST?: (rst: string) => void {t('tcip.filter')} {st.filter_lo}–{st.filter_hi} Hz +
+ call(() => SetTCIFilter(v, st.filter_hi))} /> +
+
+ call(() => SetTCIFilter(st.filter_lo, v))} /> +
{WIDTHS.map((w) => { const e = edgesFor(w, mode); diff --git a/internal/cat/tci_panel.go b/internal/cat/tci_panel.go index bbe8fca..e8fd39d 100644 --- a/internal/cat/tci_panel.go +++ b/internal/cat/tci_panel.go @@ -95,6 +95,14 @@ func (t *TCI) handlePanel(name string, get func(int) string, args string) bool { yes := func(s string) bool { return strings.EqualFold(strings.TrimSpace(s), "true") } p := &t.panel.st + // Mute and squelch are LOGGED as they change, because a report from a real + // radio says pressing MUTE lights the squelch and nothing here can explain + // it. What the radio actually announces after the command settles whether + // this is our reading or its doing, and no amount of reasoning will. + switch name { + case "mute", "sql_enable", "sql_level": + debugLog.Printf("TCI: %s:%s", name, args) + } switch name { case "protocol": p.Protocol = strings.TrimSpace(args)