diff --git a/app.go b/app.go index a1f79cb..edac75e 100644 --- a/app.go +++ b/app.go @@ -14187,7 +14187,7 @@ type motorAntenna interface { type ubAdapter struct { c *ultrabeam.Client // Configured tunable range (MHz) from Settings → Antenna. The follow logic - // uses this as a hard floor/ceiling: some controllers (e.g. an RCU-01 behind + // uses this as a hard floor/ceiling: some controllers (e.g. an RCU-06 behind // an RS232-to-Ethernet bridge) answer with the short status frame that omits // FreqMax, which would disable the out-of-range guard and let OpsLog forward // an un-tunable frequency (80 m → the controller clamps the elements to its @@ -14456,7 +14456,7 @@ func (a *App) startUltrabeam() { if s.TXInhibit { stop := make(chan struct{}) a.motorInhibStop = stop - go a.motorTXInhibitLoop(a.motorAnt, stop) + go a.motorTXInhibitLoop(a.motorAnt, s.Bands, stop) } } @@ -14591,7 +14591,7 @@ func (a *App) applyMotorInhibit(on bool) { // active; it errs toward SAFE — TX is inhibited while the status reports motion // OR within a grace window after a commanded move — and always releases the // inhibit when it stops (so a settings change / shutdown never leaves TX blocked). -func (a *App) motorTXInhibitLoop(c motorAntenna, stop <-chan struct{}) { +func (a *App) motorTXInhibitLoop(c motorAntenna, bands []string, stop <-chan struct{}) { const grace = 3 * time.Second // cover the poll latency at the very start of a move ticker := time.NewTicker(300 * time.Millisecond) defer ticker.Stop() @@ -14604,6 +14604,17 @@ func (a *App) motorTXInhibitLoop(c motorAntenna, stop <-chan struct{}) { st := c.Status() recentCmd := time.Since(time.Unix(0, a.motorMoveCmdNs.Load())) < grace moving := st.Connected && (st.Moving || recentCmd) + // On a band the antenna doesn't cover, OpsLog never commands a move — + // so it must never gag TX for "antenna moving" either. Otherwise a + // stray polled Moving flag, or a move finishing from the previous band, + // blocks the operator's transmit on a band they work with a different + // antenna (the whole point of un-ticking the band). Hands off means + // hands off: no tune AND no inhibit. + if moving && a.cat != nil { + if rs := a.cat.State(); rs.Connected && rs.FreqHz > 0 && !motorBandAllowed(bands, rs.FreqHz) { + moving = false + } + } a.applyMotorInhibit(moving) } } diff --git a/changelog.json b/changelog.json index 693e900..282cc45 100644 --- a/changelog.json +++ b/changelog.json @@ -10,7 +10,8 @@ "Station Control relays (WebSwitch / KMTronic / Dingtian): the Host field now accepts a full URL, so you can reach a network relay board through an HTTPS reverse proxy — e.g. https://relay.yourdomain.com.", "Stats slot drill-down: the pop-up listing the QSOs behind a band/mode square looks tidier (banded rows, cleaner header), and you can now click a callsign in it to open that QSO for editing.", "DCU-1 rotor support: OpsLog can now steer controllers that speak the Hy-Gain DCU-1 protocol (RotorCard DXA for Yaesu DXA rotors, Idiom Press Rotor-EZ, Green Heron) over their COM port or a serial-over-IP bridge.", - "Motorized antenna: Settings → Antenna now has a Covered bands selector (40 m–6 m) instead of a min/max range, for both the Ultrabeam and the SteppIR. Tick only the bands your antenna does — untick one you can't (e.g. 30 m without its extension) while keeping the rest — and OpsLog leaves the antenna put on every other band. This overrides an unreliable controller, so 80 m no longer clamps the elements down to 30 m. Existing range settings migrate automatically." + "Motorized antenna: Settings → Antenna now has a Covered bands selector (40 m–6 m) instead of a min/max range, for both the Ultrabeam and the SteppIR. Tick only the bands your antenna does — untick one you can't (e.g. 30 m without its extension) while keeping the rest — and OpsLog leaves the antenna put on every other band. This overrides an unreliable controller, so 80 m no longer clamps the elements down to 30 m. Existing range settings migrate automatically.", + "Motorized antenna: on a band you did not tick in Covered bands, OpsLog no longer inhibits FlexRadio transmit for \"antenna moving\". Un-ticking a band now means hands off completely — no tuning and no TX block — so working it on another antenna is never gagged." ], "fr": [ "Édition de QSO : ajout du bouton QRZ ↗ à côté de l'indicatif, comme dans le formulaire de saisie — un clic ouvre le profil qrz.com de la station.", @@ -20,7 +21,8 @@ "Relais du Contrôle station (WebSwitch / KMTronic / Dingtian) : le champ Hôte accepte désormais une URL complète ex. https://relais.tondomaine.com derrière Nginx Proxy Manager. Avant, OpsLog forçait http://, donc une carte sur le LAN derrière un proxy (quand vos 80/443 vont déjà ailleurs) était injoignable de l'extérieur.", "Détail d’un slot Stats : la fenêtre listant les QSO derrière une case bande/mode est plus soignée (lignes alternées, en-tête plus propre), et vous pouvez maintenant cliquer un indicatif pour ouvrir ce QSO en édition.", "Prise en charge des rotors DCU-1 : OpsLog pilote désormais les contrôleurs parlant le protocole Hy-Gain DCU-1 (RotorCard DXA pour rotors Yaesu DXA, Idiom Press Rotor-EZ, Green Heron) via leur port COM ou un pont série-sur-IP.", - "Antenne motorisée : Réglages → Antenne propose désormais un sélecteur Bandes couvertes (40 m–6 m) au lieu d'une plage min/max, pour l'Ultrabeam comme pour la SteppIR. Coche seulement les bandes que fait ton antenne — décoche celle que tu ne fais pas (p. ex. le 30 m sans son extension) en gardant les autres — et OpsLog laisse l'antenne en place sur toutes les autres. Ceci prime sur un contrôleur peu fiable : le 80 m ne replie plus les éléments sur le 30 m. Les anciens réglages de plage sont migrés automatiquement." + "Antenne motorisée : Réglages → Antenne propose désormais un sélecteur Bandes couvertes (40 m–6 m) au lieu d'une plage min/max, pour l'Ultrabeam comme pour la SteppIR. Coche seulement les bandes que fait ton antenne — décoche celle que tu ne fais pas (p. ex. le 30 m sans son extension) en gardant les autres — et OpsLog laisse l'antenne en place sur toutes les autres. Ceci prime sur un contrôleur peu fiable : le 80 m ne replie plus les éléments sur le 30 m. Les anciens réglages de plage sont migrés automatiquement.", + "Antenne motorisée : sur une bande non cochée dans Bandes couvertes, OpsLog n'inhibe plus l'émission du FlexRadio pour « antenne en mouvement ». Décocher une bande signifie désormais ne plus y toucher du tout — ni accord ni blocage TX — pour ne jamais couper le trafic sur une autre antenne." ] }, { diff --git a/internal/ultrabeam/ultrabeam.go b/internal/ultrabeam/ultrabeam.go index 448c88e..945239a 100644 --- a/internal/ultrabeam/ultrabeam.go +++ b/internal/ultrabeam/ultrabeam.go @@ -509,7 +509,7 @@ func (c *Client) queryStatus() (*Status, error) { return nil, err } - // An older controller — seen behind an RS232-to-Ethernet bridge — answers with + // An RCU-06 controller — seen behind an RS232-to-Ethernet bridge — answers with // an 11-byte status frame: the standard one WITHOUT the trailing FreqMax byte. // The packet checksum was already verified, so a short-but-valid frame is real, // not a fragment. Accept it and default the missing tail fields instead of