fix: Save and close taking time when Flex or Icom is not connected
This commit is contained in:
+35
-4
@@ -4,6 +4,7 @@ package cat
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
@@ -25,9 +26,10 @@ type Flex struct {
|
||||
host string
|
||||
port int
|
||||
|
||||
mu sync.Mutex
|
||||
conn net.Conn
|
||||
wmu sync.Mutex // serialises writes to conn
|
||||
mu sync.Mutex
|
||||
conn net.Conn
|
||||
dialCancel context.CancelFunc // cancels an in-flight Connect dial (Interrupt/Stop); nil when not dialing
|
||||
wmu sync.Mutex // serialises writes to conn
|
||||
seq int
|
||||
handle string
|
||||
model string
|
||||
@@ -171,7 +173,19 @@ func (f *Flex) Connect() error {
|
||||
if host == "" {
|
||||
return fmt.Errorf("flex: no radio IP configured")
|
||||
}
|
||||
conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, strconv.Itoa(port)), 5*time.Second)
|
||||
// Cancellable dial: Interrupt() (called by Stop/Start) aborts it at once so a
|
||||
// dead radio's 5 s dial timeout doesn't make Stop / Settings "Save & Close"
|
||||
// wait several seconds for the poll goroutine to give up.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
f.mu.Lock()
|
||||
f.dialCancel = cancel
|
||||
f.mu.Unlock()
|
||||
var d net.Dialer
|
||||
conn, err := d.DialContext(ctx, "tcp", net.JoinHostPort(host, strconv.Itoa(port)))
|
||||
cancel()
|
||||
f.mu.Lock()
|
||||
f.dialCancel = nil
|
||||
f.mu.Unlock()
|
||||
if err != nil {
|
||||
return fmt.Errorf("flex: connect %s:%d: %w", host, port, err)
|
||||
}
|
||||
@@ -224,6 +238,23 @@ func (f *Flex) Disconnect() {
|
||||
}
|
||||
}
|
||||
|
||||
// Interrupt aborts an in-flight Connect dial so Stop()/Start() (Settings
|
||||
// "Save & Close", CAT backend switch) don't block on a dead radio's 5 s dial
|
||||
// timeout. Satisfies the Manager's optional interruptible interface. Safe to call
|
||||
// anytime and from another goroutine; a no-op when not dialing.
|
||||
func (f *Flex) Interrupt() {
|
||||
f.mu.Lock()
|
||||
cancel := f.dialCancel
|
||||
c := f.conn
|
||||
f.mu.Unlock()
|
||||
if cancel != nil {
|
||||
cancel()
|
||||
}
|
||||
if c != nil {
|
||||
_ = c.Close() // unblock the reader if we're already past the dial
|
||||
}
|
||||
}
|
||||
|
||||
// send writes a sequenced command (C<seq>|<cmd>) to the radio and returns the
|
||||
// sequence number (so the caller can match the R<seq> response, e.g. to learn a
|
||||
// new spot's index). Returns 0 when not connected. Best effort.
|
||||
|
||||
Reference in New Issue
Block a user