74 lines
2.5 KiB
Go
74 lines
2.5 KiB
Go
package udp
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"hamlog/internal/applog"
|
|
)
|
|
|
|
// WSJT-X Halt Tx (message type 8) — "stop transmitting".
|
|
//
|
|
// The same two things the Halt Tx button and the Enable Tx toggle do in the
|
|
// application's own window:
|
|
//
|
|
// Halt Tx type 8
|
|
// id utf8 the target application's own id
|
|
// auto_tx_only bool false = stop the transmission NOW
|
|
// true = let this over finish, then stop auto-Tx
|
|
//
|
|
// Both are useful and they are not the same operation. Stopping mid-over is what
|
|
// you want when you have called the wrong station or realised the frequency is
|
|
// occupied; finishing the over first is what you want when the QSO is complete
|
|
// and cutting the transmission would leave the other end waiting for a report
|
|
// that never lands.
|
|
const wsjtMsgHaltTx = 8
|
|
|
|
// EncodeHaltTx builds the datagram. autoTxOnly false halts immediately.
|
|
func EncodeHaltTx(programID string, autoTxOnly bool) []byte {
|
|
var b bytes.Buffer
|
|
_ = binary.Write(&b, binary.BigEndian, uint32(wsjtMagic))
|
|
_ = binary.Write(&b, binary.BigEndian, uint32(2)) // schema 2 — what every current sender speaks
|
|
_ = binary.Write(&b, binary.BigEndian, uint32(wsjtMsgHaltTx))
|
|
writeQString(&b, programID)
|
|
var auto uint8
|
|
if autoTxOnly {
|
|
auto = 1
|
|
}
|
|
_ = binary.Write(&b, binary.BigEndian, auto)
|
|
return b.Bytes()
|
|
}
|
|
|
|
// SendHaltTx tells one decoding application to stop transmitting.
|
|
//
|
|
// Routed by PROGRAM ID and answered back to the address that instance's packets
|
|
// arrive from, exactly like SendReply: two receivers can share one multicast
|
|
// group, and halting the 20 m instance because the 6 m one is transmitting would
|
|
// be worse than doing nothing.
|
|
func (m *Manager) SendHaltTx(programID string, autoTxOnly bool) error {
|
|
if strings.TrimSpace(programID) == "" {
|
|
return fmt.Errorf("no application id — cannot tell which receiver to halt")
|
|
}
|
|
m.mu.Lock()
|
|
servers := make([]*Server, 0, len(m.inbound))
|
|
for _, s := range m.inbound {
|
|
servers = append(servers, s)
|
|
}
|
|
m.mu.Unlock()
|
|
|
|
for _, s := range servers {
|
|
conn, addr := s.replyTarget(programID)
|
|
if conn == nil || addr == nil {
|
|
continue
|
|
}
|
|
if _, err := conn.WriteToUDP(EncodeHaltTx(programID, autoTxOnly), addr); err != nil {
|
|
return fmt.Errorf("send halt to %s at %s: %w", programID, addr, err)
|
|
}
|
|
applog.Printf("udp: halt tx sent to %s at %s (auto_tx_only=%v)", programID, addr, autoTxOnly)
|
|
return nil
|
|
}
|
|
return fmt.Errorf("no packet has arrived from %q yet — nothing to halt", programID)
|
|
}
|