fix: CI-V frames read at the wrong offset decoded as plausible frequencies
From F4JND's log: a rig sitting on 145.550 MHz FM produced status lines reading 16445550000, 8364550000, 5817408364 and 12640 Hz between good readings — the last of those even resolved to a 6 cm band. BCDToFreq treated the nibbles 0x0A..0x0F as the digits 10..15, so a byte stream that had lost frame sync still decoded into a number. The same log shows why sync was lost: PTT round trips timing out and a scope stream the rig kept rejecting (0x27), both competing with the poll on one serial line. Non-decimal nibbles are now refused. Each caller keeps its last good value rather than publishing noise: the frequency reader returns an error, the sub-VFO reader returns not-ok, and the scope keeps its previous edges. Garbage that LOOKS like a frequency is worse than a refused frame — it reaches the display, the band slots and eventually the log, and it is the operator who then has to disprove it. The test builds its fixture with FreqToBCD rather than by hand, because my hand-written one was byte-reversed and the test caught it. This does NOT explain the white screen that was also reported, and I have not claimed it does: it removes one source of absurd values reaching the UI, which is worth doing on its own evidence.
This commit is contained in:
@@ -750,8 +750,13 @@ func (b *IcomSerial) scopeLoop(spec chan civ.Decoded, done chan struct{}) {
|
||||
// (e.g. 14.200 MHz + 100 kHz → centred 14.150-14.250; 21.000 +
|
||||
// 21.070 → fixed 21.000-21.070). Guessing wrong here gave the absurd
|
||||
// 21.000-42.070 span (low + a 21 MHz "span").
|
||||
v1 := civ.BCDToFreq(region[1:6])
|
||||
v2 := civ.BCDToFreq(region[6:11])
|
||||
v1, ok1 := civ.BCDToFreq(region[1:6])
|
||||
v2, ok2 := civ.BCDToFreq(region[6:11])
|
||||
if !ok1 || !ok2 {
|
||||
// Not decimal BCD — the frame was read at the wrong offset. Keep the
|
||||
// edges we had; a wrong span is drawn, noticed, and mistrusted.
|
||||
break
|
||||
}
|
||||
var low, high int64
|
||||
if v2 > v1 {
|
||||
low, high = v1, v2 // absolute low/high edges (fixed edge set)
|
||||
@@ -788,8 +793,13 @@ func (b *IcomSerial) scopeLoop(spec chan civ.Decoded, done chan struct{}) {
|
||||
// high = span (e.g. 100 kHz), so high < low and the panadapter had
|
||||
// no valid range to map the trace onto → blank scope. FIXED mode
|
||||
// parsed fine, which is why only center mode was broken.
|
||||
v1 := civ.BCDToFreq(region[1:6])
|
||||
v2 := civ.BCDToFreq(region[6:11])
|
||||
v1, ok1 := civ.BCDToFreq(region[1:6])
|
||||
v2, ok2 := civ.BCDToFreq(region[6:11])
|
||||
if !ok1 || !ok2 {
|
||||
// Not decimal BCD — the frame was read at the wrong offset. Keep the
|
||||
// edges we had; a wrong span is drawn, noticed, and mistrusted.
|
||||
break
|
||||
}
|
||||
var low, high int64
|
||||
if v2 > v1 {
|
||||
low, high = v1, v2 // absolute low/high edges (fixed)
|
||||
@@ -1142,7 +1152,14 @@ func (b *IcomSerial) readFreq() (int64, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return civ.BCDToFreq(f.Data), nil
|
||||
hz, ok := civ.BCDToFreq(f.Data)
|
||||
if !ok {
|
||||
// A frame that is not decimal BCD is a desynchronised read, not a
|
||||
// frequency. Reporting the error keeps the caller on its last good value
|
||||
// instead of publishing a number like 16445550000 Hz to the display.
|
||||
return 0, fmt.Errorf("icom: frequency frame is not BCD: % X", f.Data)
|
||||
}
|
||||
return hz, nil
|
||||
}
|
||||
|
||||
// readSplit reads the rig's split state (CI-V 0x0F). 0x01 = split on; 0x10/0x11
|
||||
@@ -1172,7 +1189,11 @@ func (b *IcomSerial) readTXFreq() (int64, bool) {
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
return civ.BCDToFreq(f.Data[1:]), true
|
||||
hz, ok := civ.BCDToFreq(f.Data[1:])
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
return hz, true
|
||||
}
|
||||
|
||||
// readTX reads the transmit state (CI-V 0x1C 0x00): non-zero data = keyed.
|
||||
|
||||
Reference in New Issue
Block a user