diff --git a/changelog.json b/changelog.json index 897a331..95ecccb 100644 --- a/changelog.json +++ b/changelog.json @@ -4,11 +4,13 @@ "date": "", "en": [ "CW keyer (Kenwood/Elecraft): choosing the Kenwood/Elecraft engine now actually switches to it. A bug left the keyer on WinKeyer even though the setting showed Kenwood/Elecraft, so its CW-over-CAT never ran.", - "Kenwood/Elecraft data mode: a new setting (Settings → CAT) chooses what a data mode (FT8/PSK…) sets on the rig — USB (default), DATA mode (MD6, for an Elecraft K3/K4), or leave the rig's mode unchanged (safest for a TS-590SG/TS-990S, whose data mode is a USB modifier set on the radio). There is no single command that fits every rig, so it's now the operator's choice." + "Kenwood/Elecraft data mode: a new setting (Settings → CAT) chooses what a data mode (FT8/PSK…) sets on the rig — USB (default), DATA mode (MD6, for an Elecraft K3/K4), or leave the rig's mode unchanged (safest for a TS-590SG/TS-990S, whose data mode is a USB modifier set on the radio). There is no single command that fits every rig, so it's now the operator's choice.", + "Ultrabeam over a remote link: changing the pattern (Normal / 180° / bidirectional) no longer snaps back to the old one after a few seconds. The commanded pattern is now held while the motors are still moving plus a grace window after they stop, so the slow remote status poll — which lagged behind the antenna — can't revert the display while the change is in flight." ], "fr": [ "Keyer CW (Kenwood/Elecraft) : choisir le moteur Kenwood/Elecraft y bascule désormais réellement. Un bug laissait le keyer sur WinKeyer alors que le réglage affichait Kenwood/Elecraft, son CW-sur-CAT ne démarrait donc jamais.", - "Mode data Kenwood/Elecraft : un nouveau réglage (Réglages → CAT) choisit ce qu'un mode data (FT8/PSK…) règle sur la radio — USB (défaut), mode DATA (MD6, pour un Elecraft K3/K4), ou ne pas changer le mode de la radio (le plus sûr pour un TS-590SG/TS-990S dont le mode data est un modificateur d'USB réglé sur la radio). Aucune commande unique ne convient à toutes les radios, c'est donc désormais au choix de l'opérateur." + "Mode data Kenwood/Elecraft : un nouveau réglage (Réglages → CAT) choisit ce qu'un mode data (FT8/PSK…) règle sur la radio — USB (défaut), mode DATA (MD6, pour un Elecraft K3/K4), ou ne pas changer le mode de la radio (le plus sûr pour un TS-590SG/TS-990S dont le mode data est un modificateur d'USB réglé sur la radio). Aucune commande unique ne convient à toutes les radios, c'est donc désormais au choix de l'opérateur.", + "Ultrabeam en remote : changer le diagramme (Normal / 180° / bidirectionnel) ne revient plus à l'ancien au bout de quelques secondes. Le diagramme commandé est maintenu tant que les moteurs bougent, plus une fenêtre de grâce après leur arrêt — le poll de statut distant, lent et en retard sur l'antenne, ne peut donc plus faire revenir l'affichage pendant que le changement est en cours." ] }, { diff --git a/internal/ultrabeam/ultrabeam.go b/internal/ultrabeam/ultrabeam.go index 9cf37ba..248e9a9 100644 --- a/internal/ultrabeam/ultrabeam.go +++ b/internal/ultrabeam/ultrabeam.go @@ -23,6 +23,12 @@ const ( ubReadTimeout = 4 * time.Second // was 1s — too tight for a remote link ubKeepAlive = 15 * time.Second // OS-level TCP keepalive ubMaxPollTimeout = 3 // consecutive read timeouts tolerated before reconnecting + // How long a just-commanded direction is trusted AFTER the motors have stopped + // but before the antenna's status confirms it. The timer is held off entirely + // while the motors are still moving, so this is only the grace period for the + // confirmation poll to arrive once the elements have settled — generous, because + // over a remote link that poll lags by several seconds. + ubPendingDirGrace = 8 * time.Second ) // Protocol constants @@ -221,12 +227,30 @@ func (c *Client) pollLoop() { } c.statusMu.Lock() - // Keep a just-commanded direction until the antenna reports it. + // Keep a just-commanded direction until the antenna actually reports it. + // Over a remote link the confirmation arrives several seconds after the + // command — the motors flip the elements first — so the old fixed 4 s + // timeout expired WHILE the change was still in flight, and the stale poll + // reverted the UI to the old pattern even though the antenna was on its way + // to the new one. Now: while the motors are still moving the change is in + // progress, so hold the commanded pattern and keep resetting the timer; + // only once the motors have stopped does the short grace window run, giving + // the confirmation poll time to land. The poll only wins if the motors are + // idle AND the antenna still reports a different pattern past that window — + // i.e. the command genuinely did not take. if c.pendingDirSet { - if time.Since(c.pendingDirAt) > 4*time.Second || status.Direction == c.pendingDir { - c.pendingDirSet = false - } else { - status.Direction = c.pendingDir + if status.MotorsMoving != 0 { + c.pendingDirAt = time.Now() // still repositioning — don't start the grace timer + } + switch { + case status.Direction == c.pendingDir: + c.pendingDirSet = false // confirmed by the antenna + case time.Since(c.pendingDirAt) > ubPendingDirGrace: + c.pendingDirSet = false // motors idle, still unconfirmed → accept the poll + log.Printf("Ultrabeam: antenna never confirmed direction %d (reports %d) — dropping the hold", + c.pendingDir, status.Direction) + default: + status.Direction = c.pendingDir // still changing, or within the grace window } } c.lastStatus = status