fix: zoom taking too long after clicking a spot
This commit is contained in:
+85
-9
@@ -54,6 +54,7 @@ type Flex struct {
|
||||
spotsEnabled bool // push cluster spots + manage the panadapter overlay
|
||||
spotIdx map[int]bool // panadapter spot indices currently known to the radio
|
||||
pendingSpot map[int]string // seq → callsign, awaiting the spot index in the R response
|
||||
pendingSplit map[int]bool // seq → awaiting the new TX slice's index (split create)
|
||||
spotCall map[int]string // spot index → callsign (to fill the call on a panadapter click)
|
||||
sentCmds map[int]string // seq → command text, so an R<seq> error names the command
|
||||
|
||||
@@ -148,7 +149,7 @@ func NewFlex(host string, port int, spotsEnabled bool) *Flex {
|
||||
return &Flex{
|
||||
host: strings.TrimSpace(host), port: port,
|
||||
slices: map[int]*flexSlice{}, spotsEnabled: spotsEnabled,
|
||||
spotIdx: map[int]bool{}, pendingSpot: map[int]string{}, spotCall: map[int]string{},
|
||||
spotIdx: map[int]bool{}, pendingSpot: map[int]string{}, spotCall: map[int]string{}, pendingSplit: map[int]bool{},
|
||||
meterMeta: map[int]meterInfo{}, meterVal: map[int]float64{}, meterSub: map[int]bool{},
|
||||
sentCmds: map[int]string{}, txSetAt: map[string]time.Time{},
|
||||
}
|
||||
@@ -314,7 +315,18 @@ func (f *Flex) reader(conn net.Conn) {
|
||||
f.spotIdx[idx] = true
|
||||
}
|
||||
}
|
||||
// A successful "slice create" for split returns the new slice's index;
|
||||
// make that slice the transmitter so RX/TX are on separate slices.
|
||||
splitSeq := f.pendingSplit[seq]
|
||||
if splitSeq {
|
||||
delete(f.pendingSplit, seq)
|
||||
}
|
||||
f.mu.Unlock()
|
||||
if splitSeq && ok && len(parts) >= 3 {
|
||||
if idx, e := strconv.Atoi(strings.TrimSpace(parts[2])); e == nil {
|
||||
f.send(fmt.Sprintf("slice s %d tx=1", idx))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Connection ended.
|
||||
@@ -1050,6 +1062,11 @@ func (f *Flex) FlexState() FlexTXState {
|
||||
CWSidetone: f.tx.cwSidetone,
|
||||
CWMonLevel: f.tx.cwMonLevel,
|
||||
}
|
||||
if rx, tx := f.pickSlicesLocked(); rx != nil && tx != nil && rx != tx && rx.freqHz != tx.freqHz {
|
||||
st.Split = true
|
||||
st.RXFreqHz = rx.freqHz
|
||||
st.TXFreqHz = tx.freqHz
|
||||
}
|
||||
if _, rx := f.rxSliceLocked(); rx != nil {
|
||||
st.RXAvail = true
|
||||
st.Mode = strings.ToUpper(rx.mode)
|
||||
@@ -1170,14 +1187,73 @@ func (f *Flex) SetAudioLevel(l int) error { return f.sendSlice("audio_level",
|
||||
func (f *Flex) SetMute(on bool) error { return f.sendSlice("audio_mute", boolFlex(on)) }
|
||||
func (f *Flex) SetRXAntenna(a string) error { return f.sendSlice("rxant", a) }
|
||||
func (f *Flex) SetTXAntenna(a string) error { return f.sendSlice("txant", a) }
|
||||
func (f *Flex) SetNB(on bool) error { return f.sendSlice("nb", boolFlex(on)) }
|
||||
func (f *Flex) SetNBLevel(l int) error { return f.sendSlice("nb_level", clampLevel(l)) }
|
||||
func (f *Flex) SetNR(on bool) error { return f.sendSlice("nr", boolFlex(on)) }
|
||||
func (f *Flex) SetNRLevel(l int) error { return f.sendSlice("nr_level", clampLevel(l)) }
|
||||
func (f *Flex) SetANF(on bool) error { return f.sendSlice("anf", boolFlex(on)) }
|
||||
func (f *Flex) SetANFLevel(l int) error { return f.sendSlice("anf_level", clampLevel(l)) }
|
||||
func (f *Flex) SetAPF(on bool) error { return f.sendSlice("apf", boolFlex(on)) }
|
||||
func (f *Flex) SetAPFLevel(l int) error { return f.sendSlice("apf_level", clampLevel(l)) }
|
||||
|
||||
// SetSplit toggles 2-slice split like SmartSDR's SPLIT button. ON creates a TX
|
||||
// slice at RX freq + offset (+1 kHz on CW, +5 kHz otherwise) and makes it the
|
||||
// transmitter; OFF removes the extra TX slice and returns to simplex (RX slice
|
||||
// transmits again).
|
||||
func (f *Flex) SetSplit(on bool) error {
|
||||
f.mu.Lock()
|
||||
if f.conn == nil {
|
||||
f.mu.Unlock()
|
||||
return fmt.Errorf("flex: not connected")
|
||||
}
|
||||
rx, tx := f.pickSlicesLocked()
|
||||
rxIdx, txIdx := -1, -1
|
||||
for i, s := range f.slices {
|
||||
if s == rx {
|
||||
rxIdx = i
|
||||
}
|
||||
if s == tx {
|
||||
txIdx = i
|
||||
}
|
||||
}
|
||||
alreadySplit := rx != nil && tx != nil && rx != tx
|
||||
var rxFreq int64
|
||||
var rxMode, rxAnt string
|
||||
if rx != nil {
|
||||
rxFreq, rxMode, rxAnt = rx.freqHz, rx.mode, rx.rxAnt
|
||||
}
|
||||
f.mu.Unlock()
|
||||
|
||||
if on {
|
||||
if alreadySplit || rx == nil {
|
||||
return nil // already split (or no slice)
|
||||
}
|
||||
offset := int64(5000)
|
||||
if strings.HasPrefix(strings.ToUpper(rxMode), "CW") {
|
||||
offset = 1000
|
||||
}
|
||||
cmd := fmt.Sprintf("slice create freq=%.6f mode=%s", float64(rxFreq+offset)/1e6, rxMode)
|
||||
if rxAnt != "" {
|
||||
cmd += " ant=" + rxAnt
|
||||
}
|
||||
if seq := f.send(cmd); seq > 0 {
|
||||
f.mu.Lock()
|
||||
f.pendingSplit[seq] = true // mark the new slice TX once its index returns
|
||||
f.mu.Unlock()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if !alreadySplit {
|
||||
return nil
|
||||
}
|
||||
if txIdx >= 0 {
|
||||
f.send(fmt.Sprintf("slice remove %d", txIdx))
|
||||
}
|
||||
if rxIdx >= 0 {
|
||||
f.send(fmt.Sprintf("slice s %d tx=1", rxIdx))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (f *Flex) SetNB(on bool) error { return f.sendSlice("nb", boolFlex(on)) }
|
||||
func (f *Flex) SetNBLevel(l int) error { return f.sendSlice("nb_level", clampLevel(l)) }
|
||||
func (f *Flex) SetNR(on bool) error { return f.sendSlice("nr", boolFlex(on)) }
|
||||
func (f *Flex) SetNRLevel(l int) error { return f.sendSlice("nr_level", clampLevel(l)) }
|
||||
func (f *Flex) SetANF(on bool) error { return f.sendSlice("anf", boolFlex(on)) }
|
||||
func (f *Flex) SetANFLevel(l int) error { return f.sendSlice("anf_level", clampLevel(l)) }
|
||||
func (f *Flex) SetAPF(on bool) error { return f.sendSlice("apf", boolFlex(on)) }
|
||||
func (f *Flex) SetAPFLevel(l int) error { return f.sendSlice("apf_level", clampLevel(l)) }
|
||||
|
||||
// ── CW keyer controls (top-level "cw" commands) ──
|
||||
|
||||
|
||||
Reference in New Issue
Block a user