chore: release v0.27.12

This commit is contained in:
2026-09-05 19:07:21 +02:00
parent f93e1c5898
commit be889681a9
40 changed files with 4971 additions and 453 deletions
+46
View File
@@ -425,3 +425,49 @@ func indexPreamble(buf []byte, from int) int {
}
return -1
}
// ── Band stacking registers (CI-V 0x1A sub 0x01) ──────────────────────────
//
// Every modern Icom remembers the last few frequency/mode pairs used on each
// band, and its front-panel band key walks through them. That is why pressing
// [14] on the radio lands on the FT8 watering hole rather than on a number
// somebody chose in software: the register is the operator's OWN last visit.
//
// The frame is a READ — it asks the rig what a register holds and changes
// nothing — so a rig that does not know the command answers NG and the caller
// is exactly where it started.
//
// → 1A 01 <band> <reg>
// ← 1A 01 <band> <reg> <freq 5 BCD, LE> <mode> <filter> <data mode> …
//
// Anything past the data-mode byte (duplex, tone, DV squelch on the VHF rigs)
// is not read here: the question is where the operator last was, and the answer
// to that is the frequency and the mode.
const SubBandStack = 0x01
// BandStack is one register's contents.
type BandStack struct {
FreqHz int64
Mode byte
Data bool // the data-mode flag that goes with Mode
}
// DecodeBandStack reads the payload of a 0x1A 0x01 reply, i.e. everything after
// the command byte. ok is false for a frame that is not the register asked for,
// which is what a desynchronised read looks like.
func DecodeBandStack(data []byte, band, reg byte) (BandStack, bool) {
if len(data) < 9 || data[0] != SubBandStack || data[1] != band || data[2] != reg {
return BandStack{}, false
}
hz, ok := BCDToFreq(data[3:8])
if !ok || hz <= 0 {
return BandStack{}, false
}
bs := BandStack{FreqHz: hz, Mode: data[8]}
// Filter then data mode. A rig that stops at the filter byte is not an
// error — it is a register without a data flag, so the flag stays false.
if len(data) >= 11 {
bs.Data = data[10] != 0
}
return bs, true
}