fix: Flex with multiple slices opened was always showing slice A s-meter.
This commit is contained in:
@@ -330,6 +330,7 @@ type FlexMeter struct {
|
||||
Src string `json:"src,omitempty"` // SLC / TX- / RAD / AMP…
|
||||
Name string `json:"name,omitempty"` // FWDPWR, SWR, LEVEL, PATEMP…
|
||||
Unit string `json:"unit,omitempty"`
|
||||
Slice int `json:"slice"` // for SLC meters, the slice index it belongs to; -1 otherwise
|
||||
Value float64 `json:"value"`
|
||||
Lo float64 `json:"lo"`
|
||||
Hi float64 `json:"hi"`
|
||||
|
||||
+24
-6
@@ -140,6 +140,7 @@ type meterInfo struct {
|
||||
src string // SLC (slice), TX-, COD, RAD, AMP…
|
||||
name string // FWDPWR, SWR, LEVEL, PATEMP, +13.8B…
|
||||
unit string // dbm, dbfs, swr, volts, degc, watts…
|
||||
slc int // for src=SLC meters, the slice index (the ".num" field); -1 otherwise
|
||||
lo float64
|
||||
hi float64
|
||||
}
|
||||
@@ -641,7 +642,7 @@ func (f *Flex) handleStatus(payload string) {
|
||||
// One meter per token; its fields are '#'-separated:
|
||||
// "<n>.src=…#<n>.num=…#<n>.nam=…#<n>.low=…#<n>.hi=…#<n>.unit=…".
|
||||
num := -1
|
||||
var mi meterInfo
|
||||
mi := meterInfo{slc: -1}
|
||||
for _, sub := range strings.Split(tok, "#") {
|
||||
key, val, ok := splitKV(sub)
|
||||
if !ok {
|
||||
@@ -661,6 +662,12 @@ func (f *Flex) handleStatus(payload string) {
|
||||
mi.src = val
|
||||
case "nam":
|
||||
mi.name = val
|
||||
case "num":
|
||||
// For a slice (SLC) meter this field is the slice index —
|
||||
// how we tell slice A's S-meter from slice B's.
|
||||
if v, e := strconv.Atoi(strings.TrimSpace(val)); e == nil {
|
||||
mi.slc = v
|
||||
}
|
||||
case "unit", "units":
|
||||
mi.unit = val
|
||||
case "low", "lo":
|
||||
@@ -675,6 +682,7 @@ func (f *Flex) handleStatus(payload string) {
|
||||
old, seen := f.meterMeta[num]
|
||||
if !seen {
|
||||
newIDs = append(newIDs, num)
|
||||
old.slc = -1
|
||||
}
|
||||
if mi.src != "" {
|
||||
old.src = mi.src
|
||||
@@ -685,6 +693,9 @@ func (f *Flex) handleStatus(payload string) {
|
||||
if mi.unit != "" {
|
||||
old.unit = mi.unit
|
||||
}
|
||||
if mi.slc >= 0 {
|
||||
old.slc = mi.slc
|
||||
}
|
||||
if mi.lo != 0 {
|
||||
old.lo = mi.lo
|
||||
}
|
||||
@@ -1079,15 +1090,22 @@ func (f *Flex) SendSpot(s SpotInfo) error {
|
||||
}
|
||||
// De-dupe by callsign: WSJT decodes re-fire every cycle, so a station already
|
||||
// spotted gets its previous spot removed first — one live spot per call,
|
||||
// refreshed, instead of a pile that all expire independently.
|
||||
// refreshed, instead of a pile that all expire independently. NB: capture the
|
||||
// old index under the lock but send OUTSIDE it — f.send() takes f.mu itself,
|
||||
// and Go mutexes aren't reentrant (calling send while locked deadlocks the
|
||||
// whole Flex goroutine → the radio drops OFFLINE).
|
||||
upperCall := strings.ToUpper(s.Callsign)
|
||||
f.mu.Lock()
|
||||
if old, ok := f.spotByCall[strings.ToUpper(s.Callsign)]; ok {
|
||||
delete(f.spotByCall, strings.ToUpper(s.Callsign))
|
||||
old, hadOld := f.spotByCall[upperCall]
|
||||
if hadOld {
|
||||
delete(f.spotByCall, upperCall)
|
||||
delete(f.spotCall, old)
|
||||
delete(f.spotIdx, old)
|
||||
f.send(fmt.Sprintf("spot remove %d", old))
|
||||
}
|
||||
f.mu.Unlock()
|
||||
if hadOld {
|
||||
f.send(fmt.Sprintf("spot remove %d", old))
|
||||
}
|
||||
cmd := fmt.Sprintf("spot add rx_freq=%.6f callsign=%s color=%s source=OpsLog lifetime_seconds=%d trigger_action=Tune timestamp=%d",
|
||||
float64(s.FreqHz)/1e6, call, color, life, time.Now().Unix())
|
||||
if m := flexEncode(s.Mode); m != "" {
|
||||
@@ -1321,7 +1339,7 @@ func (f *Flex) FlexState() FlexTXState {
|
||||
sort.Ints(ids) // stable order so the UI doesn't reshuffle each poll
|
||||
for _, id := range ids {
|
||||
mi := f.meterMeta[id]
|
||||
st.Meters = append(st.Meters, FlexMeter{ID: id, Src: mi.src, Name: mi.name, Unit: mi.unit, Value: f.meterVal[id], Lo: mi.lo, Hi: mi.hi})
|
||||
st.Meters = append(st.Meters, FlexMeter{ID: id, Src: mi.src, Name: mi.name, Unit: mi.unit, Slice: mi.slc, Value: f.meterVal[id], Lo: mi.lo, Hi: mi.hi})
|
||||
}
|
||||
}
|
||||
return st
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@@ -75,6 +76,20 @@ type Client struct {
|
||||
pendingDir int
|
||||
pendingDirAt time.Time
|
||||
pendingDirSet bool
|
||||
|
||||
// lastSetKHz is the frequency we last COMMANDED. Used as the follow-loop
|
||||
// deadband reference when the antenna's own status hasn't reported a frequency
|
||||
// yet (Frequency==0) — otherwise the deadband is bypassed and every small QSY
|
||||
// re-tunes the motors.
|
||||
lastSetKHz int
|
||||
}
|
||||
|
||||
// LastSetKHz returns the frequency (kHz) most recently commanded to the antenna,
|
||||
// or 0 if none yet.
|
||||
func (c *Client) LastSetKHz() int {
|
||||
c.statusMu.RLock()
|
||||
defer c.statusMu.RUnlock()
|
||||
return c.lastSetKHz
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
@@ -457,6 +472,15 @@ func (c *Client) queryProgress() ([]int, error) {
|
||||
|
||||
// SetFrequency changes frequency and optional direction (command 3)
|
||||
func (c *Client) SetFrequency(freqKhz int, direction int) error {
|
||||
// Trace WHO asked for the change — the caller's function + line — so an
|
||||
// unexpected antenna QSY (e.g. jumping to 14.074 while on 40m) can be traced
|
||||
// to the follow loop, an immediate re-tune, or a direction re-issue.
|
||||
caller := "?"
|
||||
if pc, _, line, ok := runtime.Caller(1); ok {
|
||||
caller = fmt.Sprintf("%s:%d", runtime.FuncForPC(pc).Name(), line)
|
||||
}
|
||||
log.Printf("Ultrabeam: SetFrequency(%d kHz, dir %d) ← %s", freqKhz, direction, caller)
|
||||
|
||||
data := []byte{
|
||||
byte(freqKhz & 0xFF),
|
||||
byte((freqKhz >> 8) & 0xFF),
|
||||
@@ -467,6 +491,7 @@ func (c *Client) SetFrequency(freqKhz int, direction int) error {
|
||||
if err == nil {
|
||||
c.statusMu.Lock()
|
||||
c.pendingDir, c.pendingDirAt, c.pendingDirSet = direction, time.Now(), true
|
||||
c.lastSetKHz = freqKhz
|
||||
if c.lastStatus != nil {
|
||||
c.lastStatus.Direction = direction // reflect immediately
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user