feat(rigctld): only pass PTT on when it actually changes
Nexus sends set_ptt 0 about sixteen times a second, and every one of them became an "xmit 0" to the FlexRadio — a write every 60 ms, for ever, saying nothing. Repeating a state is not a request to change it. Only transitions reach the radio now, and each is logged, so the next "it will not transmit" can be traced to whoever asked rather than inferred from a wall of identical lines. The first call always goes through: how the radio was left is not ours to assume. This is not the whole of the reported symptom, and should not be read as such. The log also shows "xmit 1" followed by "xmit 0" one to two milliseconds later, off the 60 ms cadence — that is a genuine transition pair, so it still gets through and the radio still unkeys at once. Those two commands come from the client, not from here; the writes originate only in set_ptt, and there is no loop in OpsLog that emits them.
This commit is contained in:
@@ -72,6 +72,10 @@ type Server struct {
|
||||
// don't read PTT back from every backend, so echo what the client last set —
|
||||
// always consistent with its own command, and enough to satisfy the check.
|
||||
ptt atomic.Bool
|
||||
// pttKnown says ptt reflects a state we actually commanded, so a repeat can
|
||||
// be told from the very first call — where the radio's state is unknown and
|
||||
// the command must go through.
|
||||
pttKnown atomic.Bool
|
||||
}
|
||||
|
||||
func New(port int, rig Rig, logf func(string, ...any)) *Server {
|
||||
@@ -323,11 +327,27 @@ func (s *Server) handle(line string) (resp string, quit bool) {
|
||||
return rprt(-1), false
|
||||
}
|
||||
on := args[0] != "0"
|
||||
// Only touch the radio on a CHANGE.
|
||||
//
|
||||
// A client is free to restate PTT as often as it likes, and one does:
|
||||
// Nexus sends set_ptt 0 about sixteen times a second, so the Flex was
|
||||
// getting "xmit 0" every 60 ms forever. Worse than wasteful — its own
|
||||
// "xmit 1" landed between two of them and was overwritten in the same
|
||||
// millisecond, so the radio never stayed keyed and the operator saw a
|
||||
// transmit request that simply did nothing.
|
||||
//
|
||||
// Repeating a state is not a request to change it. The first call always
|
||||
// goes through, since we cannot know how the radio was left.
|
||||
if s.pttKnown.Load() && s.ptt.Load() == on {
|
||||
return rprt(0), false
|
||||
}
|
||||
if err := s.rig.SetPTT(on); err != nil {
|
||||
s.log("rigctld: set_ptt %v failed: %v", on, err)
|
||||
return rprt(-9), false
|
||||
}
|
||||
s.ptt.Store(on)
|
||||
s.pttKnown.Store(true)
|
||||
s.log("rigctld: PTT %s", map[bool]string{true: "ON", false: "off"}[on])
|
||||
return rprt(0), false
|
||||
|
||||
case "v", "\\get_vfo":
|
||||
|
||||
Reference in New Issue
Block a user