working tx inhibit
This commit is contained in:
@@ -126,6 +126,26 @@ func (dm *DeviceManager) Initialize() error {
|
||||
dm.flexRadio.SetFrequencyChangeCallback(func(freqMHz float64) {
|
||||
dm.handleFrequencyChange(freqMHz)
|
||||
})
|
||||
|
||||
// Set callback to check if transmit is allowed (based on Ultrabeam motors)
|
||||
dm.flexRadio.SetTransmitCheckCallback(func() bool {
|
||||
// Get current Ultrabeam status
|
||||
ubStatus, err := dm.ultrabeam.GetStatus()
|
||||
if err != nil || ubStatus == nil {
|
||||
// If we cannot get status, allow transmit (fail-safe)
|
||||
return true
|
||||
}
|
||||
|
||||
// Block transmit if motors are moving
|
||||
motorsMoving := ubStatus.MotorsMoving != 0
|
||||
if motorsMoving {
|
||||
log.Printf("FlexRadio PTT check: Motors moving (bitmask=%d) - BLOCKING", ubStatus.MotorsMoving)
|
||||
} else {
|
||||
log.Printf("FlexRadio PTT check: Motors stopped - ALLOWING")
|
||||
}
|
||||
|
||||
return !motorsMoving
|
||||
})
|
||||
}
|
||||
|
||||
// Initialize Solar data client
|
||||
|
||||
@@ -29,14 +29,21 @@ type Client struct {
|
||||
running bool
|
||||
stopChan chan struct{}
|
||||
|
||||
// Interlock
|
||||
interlockID string // ID retourné par la radio (ex: "000000F4")
|
||||
interlockName string // Nom de notre interlock
|
||||
interlockMu sync.RWMutex // Protection pour l'ID
|
||||
|
||||
// Callbacks
|
||||
onFrequencyChange func(freqMHz float64)
|
||||
checkTransmitAllowed func() bool // Returns true if transmit allowed (motors not moving)
|
||||
}
|
||||
|
||||
func New(host string, port int, interlockName string) *Client {
|
||||
return &Client{
|
||||
host: host,
|
||||
port: port,
|
||||
interlockName: interlockName,
|
||||
stopChan: make(chan struct{}),
|
||||
lastStatus: &Status{
|
||||
Connected: false,
|
||||
@@ -49,6 +56,11 @@ func (c *Client) SetFrequencyChangeCallback(callback func(freqMHz float64)) {
|
||||
c.onFrequencyChange = callback
|
||||
}
|
||||
|
||||
// SetTransmitCheckCallback sets the callback to check if transmit is allowed
|
||||
func (c *Client) SetTransmitCheckCallback(callback func() bool) {
|
||||
c.checkTransmitAllowed = callback
|
||||
}
|
||||
|
||||
func (c *Client) Connect() error {
|
||||
c.connMu.Lock()
|
||||
defer c.connMu.Unlock()
|
||||
@@ -93,6 +105,12 @@ func (c *Client) Start() error {
|
||||
// Start message listener
|
||||
go c.messageLoop()
|
||||
|
||||
// Create interlock
|
||||
log.Printf("FlexRadio: Creating interlock '%s'...", c.interlockName)
|
||||
if err := c.createInterlock(); err != nil {
|
||||
log.Printf("FlexRadio: Warning - failed to create interlock: %v", err)
|
||||
}
|
||||
|
||||
// Subscribe to slice updates for frequency tracking
|
||||
log.Println("FlexRadio: Subscribing to slice updates...")
|
||||
_, err := c.sendCommand("sub slice all")
|
||||
@@ -213,6 +231,7 @@ func (c *Client) messageLoop() {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("FlexRadio RX: %s", line)
|
||||
c.handleMessage(line)
|
||||
}
|
||||
|
||||
@@ -222,6 +241,7 @@ func (c *Client) messageLoop() {
|
||||
func (c *Client) handleMessage(msg string) {
|
||||
// Response format: R<seq>|<status>|<data>
|
||||
if strings.HasPrefix(msg, "R") {
|
||||
c.handleResponse(msg)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -244,6 +264,32 @@ func (c *Client) handleMessage(msg string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) handleResponse(msg string) {
|
||||
// Format: R<seq>|<status>|<data>
|
||||
// Example: R21|0|000000F4
|
||||
parts := strings.SplitN(msg, "|", 3)
|
||||
if len(parts) < 2 {
|
||||
return
|
||||
}
|
||||
|
||||
status := parts[1]
|
||||
if status != "0" {
|
||||
log.Printf("FlexRadio: Command error: status=%s, message=%s", status, msg)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if this is interlock create response (has data in 3rd part)
|
||||
if len(parts) >= 3 && parts[2] != "" {
|
||||
interlockID := parts[2]
|
||||
|
||||
c.interlockMu.Lock()
|
||||
c.interlockID = interlockID
|
||||
c.interlockMu.Unlock()
|
||||
|
||||
log.Printf("FlexRadio: ✅ Interlock created successfully with ID: %s", interlockID)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) handleStatus(msg string) {
|
||||
// Format: S<handle>|<key>=<value> ...
|
||||
parts := strings.SplitN(msg, "|", 2)
|
||||
@@ -286,6 +332,18 @@ func (c *Client) handleStatus(msg string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check for interlock PTT_REQUESTED
|
||||
// Format: S0|interlock ... state=PTT_REQUESTED ...
|
||||
if strings.Contains(msg, "interlock") {
|
||||
if state, ok := statusMap["state"]; ok {
|
||||
log.Printf("FlexRadio: Interlock state changed to: %s", state)
|
||||
|
||||
if state == "PTT_REQUESTED" {
|
||||
// PTT requested - we MUST respond within 500ms!
|
||||
c.handlePTTRequest()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) GetStatus() (*Status, error) {
|
||||
@@ -304,3 +362,53 @@ func (c *Client) GetStatus() (*Status, error) {
|
||||
|
||||
return &status, nil
|
||||
}
|
||||
|
||||
// createInterlock creates an interlock on the radio
|
||||
func (c *Client) createInterlock() error {
|
||||
// Format: interlock create type=ANT name=<name> serial=ShackMaster
|
||||
// Type ANT = External antenna controller (state always controlled by us)
|
||||
cmd := fmt.Sprintf("interlock create type=ANT name=%s serial=ShackMaster", c.interlockName)
|
||||
|
||||
log.Printf("FlexRadio: Sending interlock create command: %s", cmd)
|
||||
|
||||
_, err := c.sendCommand(cmd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send interlock create: %w", err)
|
||||
}
|
||||
|
||||
// The response will be parsed in handleResponse()
|
||||
// Format: R<seq>|0|<interlock_id> (ex: R21|0|000000F4)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// handlePTTRequest is called when FlexRadio sends PTT_REQUESTED
|
||||
// We MUST respond within 500ms with ready or not_ready
|
||||
func (c *Client) handlePTTRequest() {
|
||||
log.Println("FlexRadio: 🔴 PTT REQUESTED - checking if transmit allowed...")
|
||||
|
||||
c.interlockMu.RLock()
|
||||
interlockID := c.interlockID
|
||||
c.interlockMu.RUnlock()
|
||||
|
||||
if interlockID == "" {
|
||||
log.Println("FlexRadio: ⚠️ No interlock ID, cannot respond to PTT request!")
|
||||
return
|
||||
}
|
||||
|
||||
// Check if transmit is allowed via callback
|
||||
allowed := true
|
||||
if c.checkTransmitAllowed != nil {
|
||||
allowed = c.checkTransmitAllowed()
|
||||
}
|
||||
|
||||
if allowed {
|
||||
log.Println("FlexRadio: ✅ Transmit ALLOWED - sending 'ready'")
|
||||
cmd := fmt.Sprintf("interlock ready %s", interlockID)
|
||||
c.sendCommand(cmd)
|
||||
} else {
|
||||
log.Println("FlexRadio: ❌ Transmit BLOCKED - sending 'not_ready'")
|
||||
cmd := fmt.Sprintf("interlock not_ready %s", interlockID)
|
||||
c.sendCommand(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user