mirror of
https://github.com/praktimarc/kst4contest.git
synced 2026-10-19 22:02:57 +02:00
* Spec: SO2R with two radios in one instance (#46) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Plan: SO2R implementation (#46) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move the rotator command rules into RotatorControl (#46) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * Store the SO2R switch, the second Win-Test station and rotator 2 (#46) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Route frequency reports to radio 1 or 2 (#46) Add the RadioSlot enum (FIRST, SECOND) with its QRG and QTF targets, and the pure RadioSlotRouter that decides per RadioInfo packet and per Win-Test station which radio a report belongs to. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Send RadioInfo of radio 2 to SECONDQRG when SO2R is on (#46) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Send Win-Test STATUS of the second station to SECONDQRG when SO2R is on (#46) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Run a second PSTRotator for radio 2 with SO2R (#46) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Start rotator 2 only while an ON4KST session runs (#46) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Settings for SO2R, the second Win-Test station and rotator 2 (#46) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Turn antenna 2 and show QTF2 with SO2R (#46) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Make the SO2R switches observable so Apply shows them (#46) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Document SO2R (#46) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Refuse clashing PSTRotator ports in both directions (#46) Writing either port now checks same-or-adjacent against the drafted value of the other; rotor 1 is only checked while SO2R and rotor 2 are on. Also fixes a misplaced Javadoc, stale WinTest parseStatus Javadoc, docs wording and removes an unused import and dead comment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Remove the executed SO2R plan (#46) The plan's content lives on in the commits, the spec and PROJECT_CONTEXT. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
198 lines
8.3 KiB
Markdown
198 lines
8.3 KiB
Markdown
# Entwurf — SO2R: zwei Funkgeräte, eine Instanz (#46)
|
|
|
|
Freigegeben vom Maintainer am 2026-10-16 (Gespräch). Erster Schritt zu #46; MO2R und
|
|
Multi-Operator über mehrere Rechner sind eigene Vorhaben mit eigenem Entwurf.
|
|
|
|
## Warum
|
|
|
|
KST4Contest kennt heute genau ein Funkgerät:
|
|
|
|
- Jede RadioInfo-Meldung aus dem Logprogramm (N1MM, DXLog, UCXLog) überschreibt MYQRG. Das
|
|
Feld `RadioNr` wird nicht gelesen. Wer mit zwei Geräten arbeitet, sieht MYQRG bei jedem
|
|
Gerätewechsel springen, und die Makros tragen die QRG des zuletzt gemeldeten Geräts.
|
|
- Win-Test kennt einen einzigen Stationsnamen-Filter, also ebenfalls ein Gerät.
|
|
- Es gibt einen PSTRotator-Client, also nur „Antenne 1 drehen".
|
|
|
|
Ein SO2R-Platz (ein Operator, ein Rechner, eine ON4KST-Anmeldung, zwei Geräte mit je eigener
|
|
Antenne) braucht pro Gerät eine eigene QRG und einen eigenen Rotor.
|
|
|
|
## Umfang
|
|
|
|
Drin:
|
|
|
|
- Pro Gerät eine eigene QRG: Gerät 1 schreibt MYQRG, Gerät 2 schreibt SECONDQRG.
|
|
- Zuordnung über `RadioNr` (N1MM, DXLog, UCXLog) und über je einen Win-Test-Stationsnamen.
|
|
- Ein zweiter PSTRotator mit Button „Antenne 2 drehen" und eigenem QTF-Feld.
|
|
- Ein Schalter „SO2R", standardmäßig aus. Aus heißt: alles wie heute.
|
|
|
|
Bewusst nicht drin:
|
|
|
|
- Ein eigenes Rechenband pro Gerät (Pfadanalyse, Tropo-Spalte, Karte bleiben wie heute).
|
|
- Ein „aktiver Platz", auf den sich Gearbeitet, Skeds und Makros beziehen.
|
|
- Strahlrichtung beider Antennen auf der Karte.
|
|
- Mehr als zwei Geräte.
|
|
- MO2R und Multi-Operator. Das Modell schließt sie nicht aus (siehe unten), wird aber nicht
|
|
dafür ausgebaut.
|
|
|
|
## Modell
|
|
|
|
### `RadioSlot` (core)
|
|
|
|
Genau zwei Instanzen, Platz 1 und Platz 2. Ein Platz bündelt:
|
|
|
|
| | Platz 1 | Platz 2 |
|
|
|---|---|---|
|
|
| QRG-Ziel | `getMYQRGFirstCat()` (MYQRG) | `getMYQRGSecondCat()` (SECONDQRG) |
|
|
| Rotor | `RotatorControl` über `stn_pstRotator*` | `RotatorControl` über `stn_pstRotator2*` |
|
|
| gemeldete Richtung | `getActualQTF()` | neu `getActualQTF2()` |
|
|
| Win-Test-Stationsname | vorhandener Filter `logsynch_wintestNetworkStationNameOfWintestClient1` | neu `logsynch_wintestNetworkStationNameOfWintestClient2` |
|
|
|
|
Platz 2 existiert nur bei eingeschaltetem SO2R. Ohne SO2R gibt es keinen Rotor 2 und kein
|
|
QTF2.
|
|
|
|
`RadioSlot` ist die Einheit, an die ein späteres MO2R einen Operator oder eine Arbeitsfläche
|
|
hängen kann. Für SO2R wird nichts davon gebaut.
|
|
|
|
### `RotatorControl` (core, herausgezogen)
|
|
|
|
Drehbefehl, Wiederholung und die Toleranz „erreicht" (1°, `ROTATOR_REACHED_TOLERANCE_DEGREES`)
|
|
liegen heute im `ChatController`. Sie ziehen unverändert in eine eigene Klasse, die einmal pro
|
|
Platz instanziert wird: eigener `PstRotatorClient`, eigener Wiederholungs-Scheduler, eigene
|
|
zuletzt gemeldete Richtung. Das Verhalten bleibt bitgenau gleich, einschließlich der
|
|
vorhandenen Kompatibilitäts-Wiederholung; der `ChatController` delegiert nur noch.
|
|
|
|
PSTRotator antwortet auf Port+1. Eine zweite PSTRotator-Instanz braucht also eigene Ports; die
|
|
Vorgabe für Rotor 2 ist 12010 (Antwort auf 12011).
|
|
|
|
### `RadioSlotRouter` (core, rein)
|
|
|
|
Entscheidet, zu welchem Platz eine Meldung gehört. Rein und ohne Abhängigkeiten, damit die
|
|
Regel ohne Netz testbar ist.
|
|
|
|
RadioInfo:
|
|
|
|
| SO2R | `RadioNr` | Platz |
|
|
|---|---|---|
|
|
| aus | beliebig, auch fehlend | 1 |
|
|
| an | 1 | 1 |
|
|
| an | 2 | 2 |
|
|
| an | fehlend | 1 |
|
|
| an | anderer Wert oder nicht lesbar | verworfen, geloggt |
|
|
|
|
Win-Test STATUS:
|
|
|
|
| SO2R | Stationsname | Platz |
|
|
|---|---|---|
|
|
| aus | wie heute: Filter leer oder passt | 1, sonst verworfen |
|
|
| an | passt auf Name von Platz 2 | 2 |
|
|
| an | Name von Platz 1 leer oder passt | 1 |
|
|
| an | sonst | verworfen |
|
|
|
|
Namensvergleich wie heute beim Filter (`equalsIgnoreCase`). Die Filterung der ADDQSO-Pakete nach Stationsname bleibt unberührt.
|
|
|
|
## Datenfluss und Fäden
|
|
|
|
- `ReadUDPbyUCXMessageThread` liest zusätzlich `RadioNr`, fragt den Router und schreibt die QRG
|
|
über `uiDispatcher.runOnUi` in das QRG-Ziel des Platzes. Der Weg für eine RadioInfo ohne
|
|
Freq oder Mode bleibt unverändert (Paket verwerfen, weiter empfangen).
|
|
- `ReadUDPByWintestThread` fragt den Router mit dem Stationsnamen; Passfrequenz-Option und
|
|
Formatierung bleiben, nur das Ziel hängt vom Platz ab.
|
|
- Rotor-Rückmeldungen laufen im Empfangsfaden des jeweiligen Rotors und schreiben die Richtung
|
|
des Platzes, wie heute bei Rotor 1. Nichts wartet auf dem AWT-Ereignisfaden.
|
|
|
|
## Einstellungen
|
|
|
|
### Reiter TRX-Abgleich
|
|
|
|
- Neuer Schalter „SO2R: zwei Geräte getrennt führen" (`trxSynch_so2rEnabled`, Vorgabe aus).
|
|
- Bei SO2R an wird der vorhandene Win-Test-Stationsnamen-Filter zum Namen für Platz 1; ein neues
|
|
Feld nimmt den Namen für Platz 2 auf. Bei SO2R aus ist das neue Feld ausgegraut.
|
|
- Hinweistext: N1MM, DXLog und UCXLog werden über `RadioNr` zugeordnet, dafür ist nichts
|
|
einzustellen.
|
|
|
|
### Reiter Station, Abschnitt PSTRotator
|
|
|
|
- Zweiter Block „PSTRotator 2 (SO2R)": Schalter, Host, Port (Vorgaben aus, 127.0.0.1, 12010).
|
|
- Nur aktiv bei SO2R an. Der Hinweis „antwortet auf Port+1" gilt auch hier.
|
|
- Gleicher Port wie Rotor 1 wird beim Übernehmen abgelehnt, mit Meldung, wie andere ungültige
|
|
Eingaben.
|
|
|
|
### Übernehmen
|
|
|
|
Wie seit dem Entwurf vom 2026-10-16 (Einstellungen mit „Übernehmen"): alles wirkt erst mit
|
|
Übernehmen/Schließen oder Speichern.
|
|
|
|
- Ändern sich SO2R oder ein Wert von Rotor 2, wird Rotor 2 einmal neu gestartet oder gestoppt —
|
|
ein eigener Effekt-Schlüssel neben dem von Rotor 1.
|
|
- SO2R aus stoppt Rotor 2 und leert QTF2.
|
|
|
|
### preferences.xml
|
|
|
|
Neue Elemente: `trxSynch_so2rEnabled`, `logsynch_wintestNetworkStationNameOfWintestClient2`,
|
|
`stn_pstRotator2Enabled`, `stn_pstRotator2Host`, `stn_pstRotator2Port`. Fehlen sie in einer
|
|
älteren Datei, gelten die Vorgaben; keine Migration. Alles gilt pro Profil.
|
|
|
|
## Oberfläche
|
|
|
|
### Stationspanel
|
|
|
|
- Neben „Antenne 1 Richtung {0} drehen" steht „Antenne 2 Richtung {0} drehen"
|
|
(`selected.turnAntenna2`, de/en).
|
|
- Sichtbar nur bei SO2R an und aktiviertem Rotor 2. Ausgegraut nach derselben Regel wie
|
|
`canTurnAntenna` bei Rotor 1 (Rotor nicht verbunden, Station ohne Locator).
|
|
- Überall, wo heute „Antenne 1 drehen" angeboten wird, kommt „Antenne 2 drehen" dazu.
|
|
|
|
### Sendezeile
|
|
|
|
- Reihenfolge MYQRG | SECONDQRG | QTF | QTF2. QTF2 zeigt die Richtung von Rotor 2, nur zur
|
|
Anzeige, und ist nur bei SO2R sichtbar.
|
|
- Bei SO2R an lautet der Tooltip von SECONDQRG „QRG Gerät 2 (aus RadioNr 2 bzw.
|
|
Win-Test-Station 2)".
|
|
- Bei SO2R aus sieht die Zeile aus wie heute.
|
|
|
|
### Statusleiste
|
|
|
|
Rotor 2 meldet seinen Zustand wie Rotor 1 über `ThreadStatusCallback`, aber unter eigenem Thread-Namen, und bekommt so einen eigenen Knopf in der Statusleiste. Ein
|
|
Ausfall von Rotor 2 berührt Rotor 1 nicht.
|
|
|
|
### Unverändert
|
|
|
|
QTF-Filter der Stationsliste (Rotor 1), Karte, Pfadanalyse, Gearbeitet-Logik. Die Makros
|
|
MYQRG und SECONDQRG tragen bei SO2R die Frequenzen der beiden Geräte.
|
|
|
|
## Dokumentation
|
|
|
|
- Changelog-Eintrag de/en.
|
|
- Handbuch: kurzer Abschnitt „SO2R" — N1MM/DXLog/UCXLog brauchen nichts, Win-Test braucht zwei
|
|
Stationsnamen, die zweite PSTRotator-Instanz braucht einen anderen Port.
|
|
|
|
## Tests
|
|
|
|
Core:
|
|
|
|
- `RadioSlotRouterTest`: alle Zeilen der beiden Tabellen oben.
|
|
- `RotatorControlTest`: Toleranz „erreicht", keine Wiederholung bei Bewegung, die vorhandene
|
|
Wiederholung bei Stillstand — mit Fake-Client und Fake-Scheduler. Die bisherigen Rotor-Tests
|
|
bleiben unverändert grün; sie sichern das Herausziehen ab.
|
|
- Empfänger: ein echtes RadioInfo-Paket mit `RadioNr` 2 bzw. ein Win-Test-STATUS mit
|
|
Stationsname 2 setzt SECONDQRG, MYQRG bleibt unverändert. Bei SO2R aus setzt dasselbe Paket
|
|
MYQRG.
|
|
- `ChatPreferences`: Roundtrip der fünf neuen Elemente; eine alte Datei ohne sie ergibt die
|
|
Vorgaben (SO2R aus, Port 12010).
|
|
|
|
App:
|
|
|
|
- Einstellungen (`DraftedSettingsTableTest`-Gerüst): Übernehmen startet bzw. stoppt Rotor 2
|
|
genau einmal; gleicher Port wie Rotor 1 wird abgelehnt; SO2R aus stoppt Rotor 2 und leert
|
|
QTF2.
|
|
- Oberfläche (Compose-UI-Tests wie beim Stationspanel): Button Antenne 2 und QTF2 nur bei SO2R
|
|
sichtbar; Button ohne Rotor 2 ausgegraut; ohne SO2R ist die Sendezeile wie heute.
|
|
- i18n: neue Schlüssel de/en, vom Erzeuger beim Bau geprüft.
|
|
|
|
Live, durch den Maintainer:
|
|
|
|
- N1MM oder DXLog mit zwei Geräten: Gerätewechsel bewegt MYQRG und SECONDQRG getrennt.
|
|
- Zwei PSTRotator-Instanzen auf verschiedenen Ports: beide Buttons drehen die richtige Antenne,
|
|
QTF und QTF2 folgen.
|
|
- Win-Test mit zwei Stationen, falls verfügbar.
|