chore: release v0.27.12
This commit is contained in:
@@ -594,6 +594,15 @@ func (b *IcomSerial) SetMode(mode string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.setModeBytes(mode, code, data)
|
||||
}
|
||||
|
||||
// setModeBytes is SetMode once the mode is already a CI-V byte and a data flag.
|
||||
// Split out for the band-stacking recall, which gets both FROM the radio and
|
||||
// must not go back through an ADIF name to reach them: a register holding CW-R
|
||||
// or LSB would come back as plain CW or as whatever the band convention says,
|
||||
// i.e. not the mode the operator left there.
|
||||
func (b *IcomSerial) setModeBytes(mode string, code byte, data bool) error {
|
||||
// Set the base mode (keeping the rig's current filter by sending only the
|
||||
// mode byte), then set the data-mode flag for digital modes.
|
||||
if err := b.execIdempotent("set mode "+mode, civ.CmdSetMode, code); err != nil {
|
||||
@@ -2188,3 +2197,59 @@ func (b *IcomSerial) TXAudioSender() (func([]byte) error, error) {
|
||||
}
|
||||
return nil, fmt.Errorf("this rig takes transmit audio through its USB sound card, not the CAT link")
|
||||
}
|
||||
|
||||
// ── Band stacking registers ───────────────────────────────────────────────
|
||||
|
||||
// RecallBandStack puts the VFO where the operator last was on a band, by asking
|
||||
// the radio rather than by holding an opinion about it.
|
||||
//
|
||||
// The console's band buttons used to send a frequency chosen in software — a
|
||||
// reasonable middle-of-the-band number, and never where anybody actually
|
||||
// operates. The radio already knows better: every band key press it has ever
|
||||
// had is remembered in that band's stacking registers, so register 1 is the
|
||||
// last place used on that band, and cycling through 2 and 3 walks back through
|
||||
// the ones before it — CW where CW was worked, and the FT8 frequency where FT8
|
||||
// was worked, without either being written down anywhere.
|
||||
//
|
||||
// Reads the register, then sets frequency and mode from it. Returns the
|
||||
// frequency it landed on, so the caller can say where it went; a register the
|
||||
// rig will not read leaves the radio untouched and returns an error, which is
|
||||
// what makes the caller's fallback to a plain frequency safe.
|
||||
func (b *IcomSerial) RecallBandStack(band, reg int) (int64, error) {
|
||||
if b.port == nil {
|
||||
return 0, fmt.Errorf("not connected")
|
||||
}
|
||||
if band <= 0 || reg < 1 || reg > 3 {
|
||||
return 0, fmt.Errorf("icom: band stack %d/%d is not a register", band, reg)
|
||||
}
|
||||
bb, rb := civ.ByteToBCD(band), civ.ByteToBCD(reg)
|
||||
if err := b.write(civ.CmdExtra, civ.SubBandStack, bb, rb); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
f, err := b.recv(icomReadTimeout, func(d civ.Decoded) bool {
|
||||
return d.Cmd == civ.CmdExtra && len(d.Data) >= 2 && d.Data[0] == civ.SubBandStack
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
bs, ok := civ.DecodeBandStack(f.Data, bb, rb)
|
||||
if !ok {
|
||||
// Logged with the raw frame: the register layout has a tail that differs
|
||||
// between models, and a rig that answers something we cannot read is the
|
||||
// one thing worth seeing here.
|
||||
applog.Printf("icom: band stack %d/%d — cannot read the register from % X", band, reg, f.Data)
|
||||
return 0, fmt.Errorf("icom: band stacking register %d/%d not understood", band, reg)
|
||||
}
|
||||
if err := b.SetFrequency(bs.FreqHz); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// The mode is best-effort. Landing on the right frequency in the wrong mode
|
||||
// is a nuisance; refusing the whole recall over it would send the operator
|
||||
// back to a button that does less.
|
||||
if bs.Mode != 0 {
|
||||
if err := b.setModeBytes(civ.ModeToADIF(bs.Mode, bs.Data), bs.Mode, bs.Data); err != nil {
|
||||
applog.Printf("icom: band stack %d/%d — frequency set, mode 0x%02X refused: %v", band, reg, bs.Mode, err)
|
||||
}
|
||||
}
|
||||
return bs.FreqHz, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user