fix(tci): a filter button does what it says, and mute is put under a log
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.
This commit is contained in:
@@ -47,15 +47,16 @@ function widthLabel(w: number): string {
|
|||||||
return w >= 1000 ? `${(w / 1000).toFixed(1)}k` : String(w);
|
return w >= 1000 ? `${(w / 1000).toFixed(1)}k` : String(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
// edgesFor turns a width into the pair TCI wants. Narrow filters are centred on
|
// edgesFor turns a width into the pair TCI wants: 0 to the width, and nothing
|
||||||
// the CW note: a 250 Hz filter from 100 to 350 would put the note outside its
|
// clever.
|
||||||
// own passband.
|
//
|
||||||
function edgesFor(w: number, mode: string): { lo: number; hi: number } {
|
// It centred narrow filters on the CW note first — 250 became 575-825 — on the
|
||||||
const cw = /CW/i.test(mode);
|
// reasoning that a CW filter should contain the note. That reasoning may even be
|
||||||
if (cw || w <= 1000) {
|
// right for a radio, but it is not what the button says, and a button that does
|
||||||
return { lo: Math.max(0, CW_PITCH - Math.round(w / 2)), hi: CW_PITCH + Math.round(w / 2) };
|
// 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.
|
||||||
return { lo: 100, hi: 100 + w };
|
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,
|
// 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
|
|||||||
<span className="text-[10px] font-bold uppercase tracking-wider text-muted-foreground">{t('tcip.filter')}</span>
|
<span className="text-[10px] font-bold uppercase tracking-wider text-muted-foreground">{t('tcip.filter')}</span>
|
||||||
<span className="text-xs font-mono tabular-nums">{st.filter_lo}–{st.filter_hi} Hz</span>
|
<span className="text-xs font-mono tabular-nums">{st.filter_lo}–{st.filter_hi} Hz</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex items-center gap-2 pb-1">
|
||||||
|
<LevelRow label="LO" unit=" Hz" min={-5000} max={5000} step={10}
|
||||||
|
value={st.filter_lo} disabled={off}
|
||||||
|
onSet={(v) => call(() => SetTCIFilter(v, st.filter_hi))} />
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2 pb-1">
|
||||||
|
<LevelRow label="HI" unit=" Hz" min={-5000} max={5000} step={10}
|
||||||
|
value={st.filter_hi} disabled={off}
|
||||||
|
onSet={(v) => call(() => SetTCIFilter(st.filter_lo, v))} />
|
||||||
|
</div>
|
||||||
<div className="grid grid-cols-4 sm:grid-cols-7 gap-2">
|
<div className="grid grid-cols-4 sm:grid-cols-7 gap-2">
|
||||||
{WIDTHS.map((w) => {
|
{WIDTHS.map((w) => {
|
||||||
const e = edgesFor(w, mode);
|
const e = edgesFor(w, mode);
|
||||||
|
|||||||
@@ -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") }
|
yes := func(s string) bool { return strings.EqualFold(strings.TrimSpace(s), "true") }
|
||||||
|
|
||||||
p := &t.panel.st
|
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 {
|
switch name {
|
||||||
case "protocol":
|
case "protocol":
|
||||||
p.Protocol = strings.TrimSpace(args)
|
p.Protocol = strings.TrimSpace(args)
|
||||||
|
|||||||
Reference in New Issue
Block a user