This commit is contained in:
2026-01-11 17:41:40 +01:00
parent cd93f0ea67
commit 414d802d37
2 changed files with 66 additions and 11 deletions

View File

@@ -67,7 +67,7 @@ func NewDeviceManager(cfg *config.Config, hub *Hub) *DeviceManager {
return &DeviceManager{ return &DeviceManager{
config: cfg, config: cfg,
hub: hub, hub: hub,
updateInterval: 200 * time.Millisecond, // Update status every second updateInterval: 1 * time.Second, // Update status every second
stopChan: make(chan struct{}), stopChan: make(chan struct{}),
freqThreshold: 25000, // 25 kHz default freqThreshold: 25000, // 25 kHz default
autoTrackEnabled: true, // Enabled by default autoTrackEnabled: true, // Enabled by default
@@ -130,7 +130,9 @@ func (dm *DeviceManager) Initialize() error {
motorsMoving := dm.ultrabeamMotorsMoving motorsMoving := dm.ultrabeamMotorsMoving
dm.ultrabeamStateMu.RUnlock() dm.ultrabeamStateMu.RUnlock()
// Block transmit if motors are moving // Block transmit if motors are moving
return motorsMoving == 0 allowed := motorsMoving == 0
log.Printf("FlexRadio PTT check: motorsMoving=%d, transmit=%v", motorsMoving, allowed)
return allowed
}) })
// Set callback for immediate frequency changes (no waiting for update cycle) // Set callback for immediate frequency changes (no waiting for update cycle)
@@ -363,12 +365,26 @@ func (dm *DeviceManager) updateStatus() {
dm.ultrabeamMotorsMoving = ubStatus.MotorsMoving dm.ultrabeamMotorsMoving = ubStatus.MotorsMoving
dm.ultrabeamStateMu.Unlock() dm.ultrabeamStateMu.Unlock()
// Log motor state changes // Proactively update FlexRadio interlock when motor state changes
if previousMotors != ubStatus.MotorsMoving { if previousMotors != ubStatus.MotorsMoving {
if ubStatus.MotorsMoving > 0 { if ubStatus.MotorsMoving > 0 {
log.Printf("Ultrabeam: Motors STARTED (bitmask=%d)", ubStatus.MotorsMoving) log.Printf("Ultrabeam: Motors STARTED (bitmask=%d)", ubStatus.MotorsMoving)
// PROACTIVELY block transmit - don't wait for PTT_REQUESTED
log.Printf("DEBUG: About to call ForceInterlockState(false), flexRadio=%v", dm.flexRadio != nil)
if dm.flexRadio != nil {
dm.flexRadio.ForceInterlockState(false)
} else {
log.Printf("DEBUG: FlexRadio is nil, cannot force interlock")
}
} else { } else {
log.Printf("Ultrabeam: Motors STOPPED") log.Printf("Ultrabeam: Motors STOPPED")
// PROACTIVELY allow transmit again
log.Printf("DEBUG: About to call ForceInterlockState(true), flexRadio=%v", dm.flexRadio != nil)
if dm.flexRadio != nil {
dm.flexRadio.ForceInterlockState(true)
} else {
log.Printf("DEBUG: FlexRadio is nil, cannot force interlock")
}
} }
} }
} else { } else {
@@ -467,6 +483,7 @@ func (dm *DeviceManager) updateStatus() {
if dm.hub != nil { if dm.hub != nil {
dm.hub.BroadcastStatusUpdate(status) dm.hub.BroadcastStatusUpdate(status)
} }
} }
func (dm *DeviceManager) GetStatus() *SystemStatus { func (dm *DeviceManager) GetStatus() *SystemStatus {

View File

@@ -15,9 +15,10 @@ type Client struct {
host string host string
port int port int
conn net.Conn conn net.Conn
reader *bufio.Reader reader *bufio.Reader
connMu sync.Mutex connMu sync.Mutex // For connection management
writeMu sync.Mutex // For writing to connection (separate from reads)
interlockID string interlockID string
interlockName string interlockName string
@@ -144,10 +145,15 @@ func (c *Client) getNextSeq() int {
} }
func (c *Client) sendCommand(cmd string) (string, error) { func (c *Client) sendCommand(cmd string) (string, error) {
c.connMu.Lock() // Use writeMu instead of connMu to avoid blocking on messageLoop reads
defer c.connMu.Unlock() c.writeMu.Lock()
defer c.writeMu.Unlock()
if c.conn == nil { c.connMu.Lock()
conn := c.conn
c.connMu.Unlock()
if conn == nil {
return "", fmt.Errorf("not connected") return "", fmt.Errorf("not connected")
} }
@@ -156,10 +162,12 @@ func (c *Client) sendCommand(cmd string) (string, error) {
log.Printf("FlexRadio TX: %s", strings.TrimSpace(fullCmd)) log.Printf("FlexRadio TX: %s", strings.TrimSpace(fullCmd))
_, err := c.conn.Write([]byte(fullCmd)) _, err := conn.Write([]byte(fullCmd))
if err != nil { if err != nil {
c.connMu.Lock()
c.conn = nil c.conn = nil
c.reader = nil c.reader = nil
c.connMu.Unlock()
return "", fmt.Errorf("failed to send command: %w", err) return "", fmt.Errorf("failed to send command: %w", err)
} }
@@ -215,6 +223,7 @@ func (c *Client) messageLoop() {
continue continue
} }
log.Printf("FlexRadio RX: %s", line)
c.handleMessage(line) c.handleMessage(line)
} }
@@ -325,7 +334,7 @@ func (c *Client) handleStatus(msg string) {
} }
} }
func (c *Client) handleInterlockState(state string, _ map[string]string) { func (c *Client) handleInterlockState(state string, statusMap map[string]string) {
log.Printf("FlexRadio: Interlock state changed to: %s", state) log.Printf("FlexRadio: Interlock state changed to: %s", state)
c.statusMu.Lock() c.statusMu.Lock()
@@ -410,3 +419,32 @@ func (c *Client) GetStatus() (*Status, error) {
return &status, nil return &status, nil
} }
// ForceInterlockState proactively sends ready/not_ready to the radio
// This is used when external conditions change (e.g., antenna motors start/stop)
func (c *Client) ForceInterlockState(allowed bool) {
c.interlockMu.RLock()
interlockID := c.interlockID
c.interlockMu.RUnlock()
if interlockID == "" {
log.Println("FlexRadio: No interlock ID, cannot force state")
return
}
if allowed {
log.Println("FlexRadio: PROACTIVE - Sending ready (motors stopped)")
c.sendCommand(fmt.Sprintf("interlock ready %s", interlockID))
// Update state immediately for UI
c.statusMu.Lock()
c.lastStatus.InterlockState = InterlockStateReady
c.statusMu.Unlock()
} else {
log.Println("FlexRadio: PROACTIVE - Sending not_ready (motors moving)")
c.sendCommand(fmt.Sprintf("interlock not_ready %s", interlockID))
// Update state immediately for UI
c.statusMu.Lock()
c.lastStatus.InterlockState = InterlockStateNotReady
c.statusMu.Unlock()
}
}