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:
+4
-2
@@ -7,14 +7,16 @@
|
|||||||
"Shared CAT no longer drops when the rig is busy. A Kenwood answers \"?;\" for a moment after coming out of transmit, which is exactly when polling resumes — and that single refused poll tore down the whole CAT link. WSJT-X, which keys through it, lost the radio mid-sequence and Hamlib then sent an uninitialised frequency, so the operator got an alarming frequency error whose real cause was three lines earlier. A busy rig is now ridden out for up to three polls; a genuine serial fault still drops immediately.",
|
"Shared CAT no longer drops when the rig is busy. A Kenwood answers \"?;\" for a moment after coming out of transmit, which is exactly when polling resumes — and that single refused poll tore down the whole CAT link. WSJT-X, which keys through it, lost the radio mid-sequence and Hamlib then sent an uninitialised frequency, so the operator got an alarming frequency error whose real cause was three lines earlier. A busy rig is now ridden out for up to three polls; a genuine serial fault still drops immediately.",
|
||||||
"CW over CAT now works on a Kenwood. The KY command was written against Elecraft's, which takes a string of any length; a Kenwood requires exactly 24 characters, so every message was refused and OpsLog reported that the radio would not do CW over CAT at all — sending operators to buy a serial keyer they did not need. A semicolon is also stripped from CW text now: it ends a CAT frame, so one in a macro cut the command short.",
|
"CW over CAT now works on a Kenwood. The KY command was written against Elecraft's, which takes a string of any length; a Kenwood requires exactly 24 characters, so every message was refused and OpsLog reported that the radio would not do CW over CAT at all — sending operators to buy a serial keyer they did not need. A semicolon is also stripped from CW text now: it ends a CAT frame, so one in a macro cut the command short.",
|
||||||
"Shared CAT now says so when a client is misconfigured. A program set to a Kenwood or Yaesu RIG MODEL instead of Hamlib NET rigctl sends raw rig commands to the CAT-sharing port; the reply it gets back has no terminator it recognises, so it reports a timeout with no data and the operator concludes CAT sharing is broken. The log now names the mistake and the setting that fixes it.",
|
"Shared CAT now says so when a client is misconfigured. A program set to a Kenwood or Yaesu RIG MODEL instead of Hamlib NET rigctl sends raw rig commands to the CAT-sharing port; the reply it gets back has no terminator it recognises, so it reports a timeout with no data and the operator concludes CAT sharing is broken. The log now names the mistake and the setting that fixes it.",
|
||||||
"Shared CAT now warns when another program has taken its port. Binding successfully is not the same as being reachable: OpsLog listens on every interface, and Windows lets a second program bind the SAME port on 127.0.0.1 alone — after which every local connection goes to that one, while OpsLog waits for clients that never arrive and reports nothing wrong. Seen with Nexus, which starts its own rigctld. The log now says so at startup and tells you what to do about it."
|
"Shared CAT now warns when another program has taken its port. Binding successfully is not the same as being reachable: OpsLog listens on every interface, and Windows lets a second program bind the SAME port on 127.0.0.1 alone — after which every local connection goes to that one, while OpsLog waits for clients that never arrive and reports nothing wrong. Seen with Nexus, which starts its own rigctld. The log now says so at startup and tells you what to do about it.",
|
||||||
|
"Shared CAT no longer relays a PTT state that has not changed. A client is free to restate PTT as often as it likes, and one does — sixteen times a second — which meant a write to the radio every 60 ms for no reason. Only a real change is passed on now, and each one is logged, so a transmit that does not happen can be traced to whoever asked for it."
|
||||||
],
|
],
|
||||||
"fr": [
|
"fr": [
|
||||||
"Décodes digitaux : le carré locator d une station pouvait être enregistré comme son indicatif. Un mot non reconnu après CQ faisait sauter un cran au parseur, et un grid de quatre caractères passe tous les tests de forme d un indicatif — « CQ FOO JN36 » était donc lu comme un contact avec JN36, spotté, coloré et compté comme n importe quelle autre station. Un grid à la place de l indicatif est maintenant refusé.",
|
"Décodes digitaux : le carré locator d une station pouvait être enregistré comme son indicatif. Un mot non reconnu après CQ faisait sauter un cran au parseur, et un grid de quatre caractères passe tous les tests de forme d un indicatif — « CQ FOO JN36 » était donc lu comme un contact avec JN36, spotté, coloré et compté comme n importe quelle autre station. Un grid à la place de l indicatif est maintenant refusé.",
|
||||||
"Le CAT partagé ne tombe plus quand le rig est occupé. Un Kenwood répond « ?; » un court instant en sortie d émission, c est-à-dire précisément au moment où le poll reprend — et ce seul refus faisait tomber tout le lien CAT. WSJT-X, qui émet à travers lui, perdait la radio en pleine séquence et Hamlib envoyait ensuite une fréquence non initialisée : l opérateur voyait une erreur de fréquence inquiétante dont la vraie cause était trois lignes plus haut. Un rig occupé est désormais encaissé sur trois polls au plus ; une vraie panne série tombe toujours immédiatement.",
|
"Le CAT partagé ne tombe plus quand le rig est occupé. Un Kenwood répond « ?; » un court instant en sortie d émission, c est-à-dire précisément au moment où le poll reprend — et ce seul refus faisait tomber tout le lien CAT. WSJT-X, qui émet à travers lui, perdait la radio en pleine séquence et Hamlib envoyait ensuite une fréquence non initialisée : l opérateur voyait une erreur de fréquence inquiétante dont la vraie cause était trois lignes plus haut. Un rig occupé est désormais encaissé sur trois polls au plus ; une vraie panne série tombe toujours immédiatement.",
|
||||||
"Le CW par CAT fonctionne enfin sur un Kenwood. La commande KY avait été écrite d après celle d Elecraft, qui accepte une chaîne de longueur libre ; un Kenwood en exige exactement 24 caractères, donc chaque message était refusé et OpsLog annonçait que la radio ne savait pas faire de CW par CAT — envoyant des opérateurs acheter un keyer série dont ils n avaient pas besoin. Le point-virgule est aussi retiré du texte CW : il termine une trame CAT, donc un seul dans une macro coupait la commande.",
|
"Le CW par CAT fonctionne enfin sur un Kenwood. La commande KY avait été écrite d après celle d Elecraft, qui accepte une chaîne de longueur libre ; un Kenwood en exige exactement 24 caractères, donc chaque message était refusé et OpsLog annonçait que la radio ne savait pas faire de CW par CAT — envoyant des opérateurs acheter un keyer série dont ils n avaient pas besoin. Le point-virgule est aussi retiré du texte CW : il termine une trame CAT, donc un seul dans une macro coupait la commande.",
|
||||||
"Le CAT partagé signale désormais un client mal configuré. Un logiciel réglé sur un MODÈLE de rig Kenwood ou Yaesu au lieu de Hamlib NET rigctl envoie des commandes rig brutes sur le port de partage ; la réponse qu il reçoit ne porte pas le terminateur qu il attend, il annonce donc un délai dépassé sans données et l opérateur en conclut que le partage CAT est cassé. Le log nomme maintenant l erreur et le réglage qui la corrige.",
|
"Le CAT partagé signale désormais un client mal configuré. Un logiciel réglé sur un MODÈLE de rig Kenwood ou Yaesu au lieu de Hamlib NET rigctl envoie des commandes rig brutes sur le port de partage ; la réponse qu il reçoit ne porte pas le terminateur qu il attend, il annonce donc un délai dépassé sans données et l opérateur en conclut que le partage CAT est cassé. Le log nomme maintenant l erreur et le réglage qui la corrige.",
|
||||||
"Le CAT partagé signale désormais qu un autre programme lui a pris son port. Réussir à ouvrir le port n est pas la même chose qu être joignable : OpsLog écoute sur toutes les interfaces, et Windows autorise un second programme à ouvrir le MÊME port sur la seule adresse 127.0.0.1 — dès lors toutes les connexions locales vont à celui-là, pendant qu OpsLog attend des clients qui n arrivent jamais sans rien signaler. Constaté avec Nexus, qui lance son propre rigctld. Le log le dit maintenant au démarrage, et indique quoi faire."
|
"Le CAT partagé signale désormais qu un autre programme lui a pris son port. Réussir à ouvrir le port n est pas la même chose qu être joignable : OpsLog écoute sur toutes les interfaces, et Windows autorise un second programme à ouvrir le MÊME port sur la seule adresse 127.0.0.1 — dès lors toutes les connexions locales vont à celui-là, pendant qu OpsLog attend des clients qui n arrivent jamais sans rien signaler. Constaté avec Nexus, qui lance son propre rigctld. Le log le dit maintenant au démarrage, et indique quoi faire.",
|
||||||
|
"Le CAT partagé ne relaie plus un état PTT inchangé. Un client a le droit de répéter son PTT aussi souvent qu il veut, et certains le font — seize fois par seconde — ce qui provoquait une écriture vers la radio toutes les 60 ms sans aucune raison. Seul un vrai changement est transmis désormais, et chacun est journalisé : une émission qui ne part pas peut donc être remontée à celui qui l a demandée."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -72,6 +72,10 @@ type Server struct {
|
|||||||
// don't read PTT back from every backend, so echo what the client last set —
|
// 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.
|
// always consistent with its own command, and enough to satisfy the check.
|
||||||
ptt atomic.Bool
|
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 {
|
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
|
return rprt(-1), false
|
||||||
}
|
}
|
||||||
on := args[0] != "0"
|
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 {
|
if err := s.rig.SetPTT(on); err != nil {
|
||||||
s.log("rigctld: set_ptt %v failed: %v", on, err)
|
s.log("rigctld: set_ptt %v failed: %v", on, err)
|
||||||
return rprt(-9), false
|
return rprt(-9), false
|
||||||
}
|
}
|
||||||
s.ptt.Store(on)
|
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
|
return rprt(0), false
|
||||||
|
|
||||||
case "v", "\\get_vfo":
|
case "v", "\\get_vfo":
|
||||||
|
|||||||
Reference in New Issue
Block a user