mirror of
https://github.com/praktimarc/kst4contest.git
synced 2026-08-23 18:47:34 +02:00
Compare commits
9
Commits
bdd10ee00b
...
8bd5d8877d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bd5d8877d | ||
|
|
97a93f726b | ||
|
|
c682ecf3f9 | ||
|
|
259d0a4916 | ||
|
|
6d65bc365c | ||
|
|
084923366f | ||
|
|
eb38268be5 | ||
|
|
36d2bd512d | ||
|
|
ffe7343671 |
@@ -33,7 +33,7 @@ Die zentrale Tabelle aller aktuell aktiven Chat-Nutzer. Spalten (je nach Konfigu
|
||||
| QTF | Richtung in Grad |
|
||||
| QRG | Zuletzt aus einer Chat-Nachricht erkannte Frequenz |
|
||||
| Tropo | Ergebnis der bandbezogenen Tropo- beziehungsweise Streckenbewertung |
|
||||
| Score | Aktueller Prioritätswert |
|
||||
| Score | Aktueller, numerisch sortierbarer Prioritätswert des normalisierten Basisrufzeichens |
|
||||
| Act | Minuten seit der letzten Aktivität |
|
||||
| AP | AirScout-Flugzeugdaten, sofern aktiviert |
|
||||
| worked | Bandbezogener Worked-, Bandmöglichkeits- und Großfeldstatus sowie `wkdany` |
|
||||
@@ -128,13 +128,35 @@ Die Änderung wirkt sofort auf die Spalte **NOT QRV @**, die Bandmöglichkeiten
|
||||
|
||||

|
||||
|
||||
Hier können auch **Sked-Erinnerungen / Wecker** für beide Skkedpartner aktiviert werden.
|
||||
Im selben Bereich wird der aktuelle **Priority score** der ausgewählten Station angezeigt.
|
||||
|
||||
Mit **Sked fail** lässt sich ein fehlgeschlagener Versuch markieren. Der Score des normalisierten Basisrufzeichens wird dadurch stark reduziert. **Reset fail** entfernt diese Markierung wieder. Die Markierung gilt für alle aktiven Suffix- und Kategorievarianten der Station und bleibt innerhalb der laufenden Programmsitzung erhalten.
|
||||
|
||||
Darunter können ein Sked und die zugehörigen **Sked-Erinnerungen / Wecker** angelegt werden. Ein nahender Sked erhöht den Priority Score zeitabhängig; unmittelbar vor dem Termin erhält er eine sehr hohe Gewichtung.
|
||||
|
||||
---
|
||||
|
||||
## Prioritätsliste
|
||||
|
||||
Zeigt die vom Score-Service berechneten Top-Kandidaten. Aktualisiert sich automatisch im Hintergrund basierend auf Richtung, Entfernung und AP-Verfügbarkeit.
|
||||
Die kompakte Prioritätsleiste befindet sich rechts zwischen Benutzerliste und Further-Info-Bereich. Sie zeigt die beiden derzeit höchstbewerteten Kandidaten unmittelbar im Hauptfenster:
|
||||
|
||||
```text
|
||||
Priority: 1 RUFZEICHEN SCORE 2 RUFZEICHEN SCORE more
|
||||
```
|
||||
|
||||
Ein Klick auf einen der beiden Kandidaten wählt den dazugehörigen aktiven Chatmember aus. Dabei werden das vollständige Rufzeichen einschließlich Suffix und die zugehörige Chat-Kategorie verwendet.
|
||||
|
||||
Die Schaltfläche **more** öffnet ein separates Fenster mit bis zu 15 Kandidaten. Die Liste ist nach absteigendem Score sortiert. Ein Doppelklick wählt den betreffenden Kandidaten aus und schließt das Fenster.
|
||||
|
||||

|
||||
|
||||
Stationen mit einem Score von `0` werden nicht in die Prioritätsliste aufgenommen. In der Benutzerliste bleiben sie sichtbar, sodass der Ausschluss nachvollzogen und beispielsweise durch eine geänderte NOT-QRV-Markierung korrigiert werden kann.
|
||||
|
||||
Der Score wird für das normalisierte Basisrufzeichen berechnet. Mehrere aktive Varianten wie `9A0BB-2` und `9A0BB-70` können daher in der Benutzerliste denselben Wert anzeigen. Die Chatmember bleiben trotzdem getrennte Nachrichtenziele.
|
||||
|
||||
Neue Nachrichten, AirScout-Daten, Skeds und Statusänderungen lösen eine Neuberechnung aus. Zusätzlich erfolgt eine regelmäßige Aktualisierung im Hintergrund. Eine kurzzeitig noch nicht angepasste Reihenfolge ist deshalb kein Fehler.
|
||||
|
||||
Herleitung und Grenzen: [Prioritätsscore und Prioritätsliste](de-Funktionen#prioritätsscore-und-prioritätsliste-ab-v140).
|
||||
|
||||
---
|
||||
|
||||
|
||||
+106
-12
@@ -372,21 +372,113 @@ Konfiguration: [Band-Upgrade-Hinweis nach einem Logeintrag](de-Konfiguration#ban
|
||||
Worked-, NOT-QRV- und Großfelddaten laufen nach drei Tagen automatisch ab. Einzelheiten und manueller Reset: [Worked Station Database Settings](de-Konfiguration#worked-station-database-settings-gearbeitete-stationen-datenbank).
|
||||
|
||||
---
|
||||
## Chatmember Score-System / Prioritätsliste (ab v1.40)
|
||||
## Prioritätsscore und Prioritätsliste (ab v1.40)
|
||||
|
||||
KST4Contest berechnet automatisch eine **Prioritätsbewertung** für jeden aktiven Chatmember. Der Score setzt sich zusammen aus:
|
||||
### Warum wird überhaupt ein Score benötigt?
|
||||
|
||||
- Antennenrichtung der Gegenstation (zeigt sie auf mich?)
|
||||
- QRB (Entfernung)
|
||||
- Aktivitätszeit und Nachrichtenanzahl
|
||||
- Aktive Bänder und Frequenzen
|
||||
- AP-Verfügbarkeit (AirScout)
|
||||
- Sked-Richtung
|
||||
- Sked-Erfolgsrate und Skedfail-Markierungen
|
||||
Eine klassische Chat-Benutzerliste zeigt zunächst nur, welche Stationen gerade eingeloggt sind. Im Contestbetrieb reicht diese Information nicht aus. Der Operator muss zusätzlich abschätzen, welche Station noch nicht gearbeitet wurde, auf welchem Band ein QSO möglich sein könnte, wohin die Antenne zeigt, ob ein passendes Flugzeug verfügbar ist und ob ein vereinbarter Sked unmittelbar bevorsteht.
|
||||
|
||||
Die Top-Kandidaten werden in einer eigenen Prioritätsliste hervorgehoben und helfen, im Contest-Stress die wichtigsten Stationen nicht zu übersehen.
|
||||
Bei einer kurzen Liste lässt sich das noch im Kopf erledigen. Mit zunehmender Contestdauer, mehreren Bändern und zwei gleichzeitig verwendeten Chat-Kategorien wird daraus jedoch eine ständig wiederholte Entscheidung.
|
||||
|
||||
Stationen, bei denen ein Sked gescheitert ist, können über den **Skedfail-Button** im FurtherInfo-Panel markiert werden – das senkt ihren Score vorübergehend.
|
||||
KST4Contest führt die bereits vorhandenen Informationen deshalb in einem Prioritätsscore zusammen. Der Score beantwortet nicht die Frage, ob ein QSO sicher möglich ist. Er hilft bei der praktisch wichtigeren Frage:
|
||||
|
||||
> Welche der aktuell sichtbaren Stationen sollte ich mir als Nächstes ansehen?
|
||||
|
||||
### Wann wird eine Station ausgeschlossen?
|
||||
|
||||
Vor der eigentlichen Gewichtung prüft KST4Contest, ob überhaupt eine bekannte Bandmöglichkeit besteht. Dafür werden alle aktiven Chat-Einträge desselben normalisierten Basisrufzeichens gemeinsam ausgewertet.
|
||||
|
||||
Berücksichtigt werden:
|
||||
|
||||
1. die in den Stationseinstellungen aktivierten eigenen Bänder,
|
||||
2. höchstens 30 Minuten alte QRG-Erkennungen der Gegenstation,
|
||||
3. eindeutige Bandangaben im Namensfeld ihrer aktiven Chat-Einträge,
|
||||
4. die pro Band gespeicherten Worked-Markierungen und
|
||||
5. manuell gesetzte NOT-QRV-Tags.
|
||||
|
||||
NOT QRV hat dabei Vorrang vor automatisch erkannten Frequenzen oder Bandangaben.
|
||||
|
||||
Sind Bänder der Gegenstation bekannt, aber keines davon ist lokal aktiviert und noch verfügbar, erhält die Station einen Score von `0`. Dasselbe gilt, wenn alle gemeinsam möglichen Bänder bereits gearbeitet wurden.
|
||||
|
||||
Fehlen dagegen sämtliche Bandinformationen, wird die Station nicht allein deshalb ausgeschlossen. Eine unbekannte Bandmöglichkeit ist nicht dasselbe wie eine nachweislich unmögliche Bandmöglichkeit. Erst wenn alle eigenen aktivierten Bänder für die Station manuell als NOT QRV markiert wurden, ist auch in diesem Fall keine aktuelle Contestmöglichkeit mehr vorhanden.
|
||||
|
||||
Stationen mit einem Score von `0` bleiben in der Benutzerliste sichtbar, erscheinen aber nicht in der Prioritätsliste.
|
||||
|
||||
### Welche Informationen erhöhen oder verringern den Score?
|
||||
|
||||
Der Score entsteht aus mehreren voneinander unabhängigen Hinweisen. Ein einzelnes Kriterium entscheidet daher normalerweise nicht über den endgültigen Listenplatz.
|
||||
|
||||
| Faktor | Wirkung auf die Priorisierung |
|
||||
|---|---|
|
||||
| Worked-Status | Ein noch auf keinem unterstützten Band gearbeitetes Rufzeichen erhält eine höhere Ausgangspriorität. Bereits gearbeitete Stationen werden niedriger bewertet, bleiben bei offenen Bandmöglichkeiten aber Kandidaten. |
|
||||
| Verfügbare Bänder | Mehrere gemeinsam nutzbare und noch nicht gearbeitete Bänder erhöhen die Priorität. Optional kann für Band-Upgrades ein zusätzlicher Boost aktiviert werden. |
|
||||
| Entfernung | Entfernungen unter 200 km werden niedriger gewichtet. Der Bereich zwischen 200 km und dem konfigurierten maximalen QRB wird bevorzugt. Stationen jenseits des maximalen QRB werden deutlich herabgestuft. Fehlt der QRB, entfällt dieser Faktor. |
|
||||
| Antennenrichtung | Liegt der QTF zur Gegenstation innerhalb der Hälfte des konfigurierten Antennen-Öffnungswinkels um den aktuellen eigenen QTF, steigt der Score. Je näher die Richtungen zusammenliegen, desto stärker wirkt der Hinweis. |
|
||||
| AirScout | Mindestens ein aktuell erreichbares Flugzeug erhöht den Score. Eine erwartete AP-Gelegenheit in null, einer oder zwei Minuten wird zusätzlich zeitlich gewichtet. |
|
||||
| Aktuelle Chat-Aktivität | Eine Nachricht innerhalb der letzten Minute wirkt stärker als eine Nachricht innerhalb der letzten drei Minuten. Mehrere eingehende Zeilen innerhalb des Aktivitätsfensters erhöhen den Score zusätzlich. |
|
||||
| Positive Signale | Erkannte Angaben wie `QRV`, `READY`, `RGR`, `OK`, `TNX` oder vergleichbare konfigurierte Textmuster werden für einige Minuten als positiver Hinweis berücksichtigt. |
|
||||
| Antwortverhalten | Reagiert eine Station nach einer eigenen `/cq`-Nachricht schnell mit einer weiteren sichtbaren Chat-Zeile, wirkt sich die gemittelte Reaktionszeit positiv aus. Bleibt eine solche Zeile aus, entsteht nach dem konfigurierten Timeout eine negative Bewertung. |
|
||||
| Skeds | Ein eingetragener Sked erhöht die Priorität zunächst leicht. Innerhalb der letzten 15 Minuten vor dem Termin steigt der Einfluss kontinuierlich an. Zwischen drei Minuten vor und einer Minute nach dem Termin erhält der Sked eine sehr hohe Priorität. |
|
||||
| Fehlgeschlagener Versuch | **Sked fail** reduziert den Score der Station stark, bis die Markierung mit **Reset fail** zurückgesetzt oder KST4Contest neu gestartet wird. |
|
||||
|
||||
Das standardmäßige Aktivitätsfenster für die Anzahl eingehender Nachrichten beträgt 180 Sekunden. Eine aktuelle Nachricht innerhalb der letzten 60 Sekunden wird noch einmal gesondert bewertet. Der standardmäßige No-Reply-Timeout beträgt 13 Minuten.
|
||||
|
||||
Beim Antwortverhalten kann KST4Contest nicht sicher feststellen, ob eine nachfolgende öffentliche oder private Nachricht tatsächlich die Antwort auf die eigene Anfrage war. Jede anschließend empfangene Zeile derselben Station beendet deshalb den laufenden Antwortzeitversuch. Der Wert ist eine praktische Näherung und keine statistisch belastbare Antwortquote.
|
||||
|
||||
### Was bedeutet ein eingetragener Sked?
|
||||
|
||||
Ein Sked ist eine zeitlich vereinbarte Arbeitsaufgabe. Deshalb übersteuert ein unmittelbar bevorstehender Sked die meisten normalen Aktivitäts- und Entfernungshinweise. Ohne diese Gewichtung könnte eine gerade sehr aktive Station einen vereinbarten Termin aus der Prioritätsliste verdrängen.
|
||||
|
||||
Der starke Sked-Boost ist absichtlich auf den Zeitraum von drei Minuten vor bis eine Minute nach dem eingetragenen Termin begrenzt. Ein weiter in der Zukunft liegender Sked bleibt sichtbar, soll den laufenden Betrieb aber noch nicht dominieren.
|
||||
|
||||
Die Bewertung wird für das normalisierte Basisrufzeichen vorgenommen. Ein Sked für eine aktive Variante wie `9A0BB-23` beeinflusst daher den gemeinsamen Score der zu `9A0BB` gehörenden Chat-Einträge.
|
||||
|
||||
### Wie werden mehrere SSIDs und Chat-Kategorien behandelt?
|
||||
|
||||
Aktive Rufzeichen wie `9A0BB-2`, `9A0BB-70`, `9A0BB-23` und `9A0BB-13` bleiben getrennte Chatmember. Dadurch können Nachrichten weiterhin an das vollständige Rufzeichen und die richtige Chat-Kategorie adressiert werden.
|
||||
|
||||
Worked-, Band-, NOT-QRV- und Score-Informationen beziehen sich dagegen auf das gemeinsame Basisrufzeichen `9A0BB`. Der Score wird deshalb einmal berechnet und auf alle aktiven Varianten übertragen. Die Benutzerliste kann mehrere getrennte Zeilen mit demselben Score enthalten; in der Prioritätsliste erscheint das Basisrufzeichen nur einmal.
|
||||
|
||||
Als konkretes Nachrichtenziel verwendet KST4Contest den zuletzt passenden aktiven Login in der zuletzt verwendeten Chat-Kategorie. Beim Anklicken eines Kandidaten wird anschließend das vollständige Rufzeichen einschließlich Suffix und Kategorie ausgewählt.
|
||||
|
||||
### Aktualisierung und Anzeige
|
||||
|
||||
Änderungen durch neue Nachrichten, AirScout-Daten, Skeds, Worked-Informationen oder manuelle NOT-QRV- und Sked-fail-Markierungen fordern unmittelbar eine Neuberechnung an. Zusätzlich wird der Score regelmäßig im Hintergrund aktualisiert, weil Aktivitäts-, AP- und Sked-Informationen auch ohne neues Ereignis altern.
|
||||
|
||||
Eine kurze Verzögerung von einigen Sekunden zwischen einem Ereignis und der sichtbaren neuen Reihenfolge ist daher normal.
|
||||
|
||||
Die Benutzeroberfläche zeigt den Score an drei Stellen:
|
||||
|
||||
- als numerisch sortierbare Spalte **Score** in der Benutzerliste,
|
||||
- für die ausgewählte Station im Bereich **Further Info** und
|
||||
- als kompakte Liste der beiden derzeit höchstbewerteten Kandidaten mit einem zusätzlichen Fenster für bis zu 15 Kandidaten.
|
||||
|
||||
Bedienung: [Prioritätsliste in der Benutzeroberfläche](de-Benutzeroberflaeche#prioritätsliste).
|
||||
|
||||
### Was sagt der Score nicht aus?
|
||||
|
||||
Der Zahlenwert ist weder eine Erfolgswahrscheinlichkeit noch eine Signalprognose. Ein doppelt so hoher Score bedeutet nicht, dass ein QSO doppelt so wahrscheinlich ist.
|
||||
|
||||
Die Berechnung kennt unter anderem nicht:
|
||||
|
||||
- die tatsächliche Antennenrichtung der Gegenstation,
|
||||
- deren momentane Betriebssituation,
|
||||
- lokale Störungen,
|
||||
- kurzfristige Ausbreitungsänderungen,
|
||||
- Geländeabschattungen außerhalb der jeweils angebundenen Funktionen oder
|
||||
- die Frage, ob eine im Chat aktive Station tatsächlich gerade am Funkgerät sitzt.
|
||||
|
||||
Auch bekannte Eingabedaten können veraltet oder missverständlich sein. Eine erkannte Frequenz belegt beispielsweise nur, dass diese QRG kürzlich im Zusammenhang mit der Station aufgetreten ist.
|
||||
|
||||
Im Klartext: Der Score ersetzt nicht die Entscheidung des Operators. Er sorgt dafür, dass die dafür bereits vorhandenen Informationen nicht bei jedem Kandidaten erneut im Kopf zusammengesucht werden müssen.
|
||||
|
||||
Zugehörige Einstellungen:
|
||||
|
||||
- [Aktivierte Bänder](de-Konfiguration#aktivierte-bänder)
|
||||
- [Antennen-Öffnungswinkel](de-Konfiguration#antennen-öffnungswinkel-antenna-beamwidth)
|
||||
- [Standard-Maximum-QRB](de-Konfiguration#standard-maximum-qrb)
|
||||
- [AirScout-Einstellungen](de-Konfiguration#airscout-einstellungen)
|
||||
- [Band-Upgrade-Hinweis und Priority Boost](de-Konfiguration#band-upgrade-hinweis-nach-einem-logeintrag)
|
||||
|
||||
---
|
||||
|
||||
@@ -404,8 +496,10 @@ So kann der Contest-Operator auf einem Blick sehen, welche Stationen wann und ü
|
||||
## Intervall-Beacon
|
||||
|
||||
KST4Contest kann wiederkehrende CQ-Nachrichten in den öffentlichen Chat senden. Beide Chat-Kategorien verwenden ein gemeinsames Intervall, besitzen aber jeweils einen eigenen Aktivierungsschalter und Nachrichtentext. Globale Variablen wie `MYQRG`, `SECONDQRG` oder `MYLOCATOR` werden unmittelbar vor jeder Aussendung aktualisiert.
|
||||
|
||||
|
||||
Der Beacon ist für längeres CQ-Rufen auf einer festen Frequenz gedacht. Beim Absuchen oder häufigen Wechseln der QRG sollte er ausgeschaltet werden, damit keine inzwischen falsche Frequenz verbreitet wird. Details: [Konfiguration – Beacon Settings](de-Konfiguration#beacon-settings-automatischer-beacon).
|
||||
|
||||
---
|
||||
|
||||
## Simplelogfile
|
||||
@@ -418,7 +512,7 @@ Dateibasierte Log-Auswertung per Regex. Details: [Log-Synchronisation](Log-Synch
|
||||
|
||||
Ein separates Fenster zeigt den QSO-Fluss zwischen anderen Stationen. Besonders interessant in ruhigeren Nacht-Stunden während des Contests, wenn weniger Verkehr herrscht.
|
||||
|
||||
Dieses Fenster kann miniaturisiert werden, wenn es nicht benötigt wird. Zukünftig geplant: Filterung auf Stationen im ausgewählten QTF.
|
||||
Dieses Fenster kann minimiert werden, wenn es nicht benötigt wird. Zukünftig geplant: Filterung auf Stationen im ausgewählten QTF.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -186,7 +186,13 @@ Bleibt mindestens ein gemeinsames, noch nicht gearbeitetes Band übrig, erschein
|
||||
Die beiden Optionen haben unterschiedliche Aufgaben:
|
||||
|
||||
- **Blink + sound …** aktiviert den Hinweis nach einem passenden Logeintrag.
|
||||
- **Priority boost …** erhöht zusätzlich die Priorität von Stationen mit einer offenen Bandmöglichkeit. Der Boost ist ein Faktor innerhalb der gesamten Prioritätsberechnung und garantiert keinen bestimmten Listenplatz.
|
||||
- **Priority boost …** erhöht zusätzlich den Score von Stationen, die bereits auf mindestens einem Band gearbeitet wurden, aber noch ein weiteres gemeinsames und nicht gearbeitetes Band anbieten.
|
||||
|
||||
Der Priority Boost ist nur ein Faktor innerhalb der gesamten Berechnung. Entfernung, Antennenrichtung, aktuelle Aktivität, AirScout-Daten, Skeds und negative Hinweise können den endgültigen Listenplatz weiterhin verändern. Die aktivierte Option garantiert deshalb weder einen bestimmten Score noch einen bestimmten Platz in der Prioritätsliste.
|
||||
|
||||
Die übrigen Score-Gewichte besitzen derzeit keine eigenen Bedienelemente. Mehrere vorhandene Einstellungen liefern jedoch Eingangsdaten für die Berechnung, insbesondere die [aktivierten Bänder](#aktivierte-bänder), der [Antennen-Öffnungswinkel](#antennen-öffnungswinkel-antenna-beamwidth), der [Standard-Maximum-QRB](#standard-maximum-qrb) und die [AirScout-Einstellungen](#airscout-einstellungen).
|
||||
|
||||
Die vollständige Herleitung ist unter [Prioritätsscore und Prioritätsliste](de-Funktionen#prioritätsscore-und-prioritätsliste-ab-v140) beschrieben.
|
||||
|
||||
Der Hinweis setzt eine Log-Synchronisation mit Bandinformation voraus. Der einfache dateibasierte Callsign-Interpreter erkennt lediglich Rufzeichen und liefert deshalb keine sichere Information über das Band des gerade geloggten QSOs.
|
||||
|
||||
|
||||
@@ -25,7 +25,18 @@ Enter your own callsign and Maidenhead locator (6 characters, e.g., `JN49IJ`). T
|
||||
|
||||
### Active Bands
|
||||
|
||||
Use the **"my station uses band"** checkboxes to select the active bands. Buttons and table rows will only appear in the user interface for selected bands. The software must be restarted after making changes.
|
||||
The **My station uses …** checkboxes define the bands available in the current local station setup. Supported choices are 50 MHz, 70 MHz, 144 MHz, 432 MHz, 1296 MHz, 2320 MHz, 3400 MHz, 5760 MHz and 10 GHz.
|
||||
|
||||
This selection controls more than the visible band columns. It is also used for:
|
||||
|
||||
- the per-band Worked and NOT-QRV filters,
|
||||
- the NOT-QRV controls visible in the **Further Info** panel,
|
||||
- the `a` and `B+` band-opportunity calculation,
|
||||
- the **New bands** filter,
|
||||
- the band-upgrade hint after a log entry, and
|
||||
- band-specific priority and Reachability functions.
|
||||
|
||||
After a change, click **Save Settings** and restart KST4Contest. Band columns and several related controls are created while the user interface is being built and are therefore not added or removed completely during the current session.
|
||||
|
||||
### Antenna Beamwidth
|
||||
|
||||
@@ -87,12 +98,71 @@ Configuration of the interface to AirScout for aircraft scatter detection. Detai
|
||||
|
||||
## Notification Settings
|
||||
|
||||

|
||||
|
||||
Three notification types are available:
|
||||
|
||||
1. **Simple sounds**: TADA sound for incoming messages, tick for sked direction detection, etc.
|
||||
2. **CW announcement**: The callsign of a station sending a private message is output as a CW signal.
|
||||
3. **Phonetic announcement**: The callsign is pronounced phonetically.
|
||||
|
||||
### Fallback Band for Relative QRG Detection
|
||||
|
||||
The **Fallback band for relative QRG detection** dropdown selects the band used when a relative QRG cannot be assigned to a recent station-specific band context.
|
||||
|
||||
Only band prefixes supported by the frequency parser are available:
|
||||
|
||||
```text
|
||||
50 MHz
|
||||
70 MHz
|
||||
144 MHz
|
||||
432 MHz
|
||||
1296 MHz
|
||||
2320 MHz
|
||||
3400 MHz
|
||||
5760 MHz
|
||||
10368 MHz (10G)
|
||||
24048 MHz (24G)
|
||||
```
|
||||
|
||||
The dropdown is neither a filter nor an override for complete frequencies. `432.088` is recognised as a frequency in the 432 MHz band regardless of the selection. The fallback is needed for relative values such as `.205`, `,205` or `qrg 205`.
|
||||
|
||||
Before using the fallback, KST4Contest checks the sender's recent band context. If a complete frequency has been detected for the same station during the previous 30 minutes, that band takes precedence. A fallback setting of `144 MHz` therefore still turns `.100` into `432.100 MHz` if the station mentioned `432.088` shortly before.
|
||||
|
||||
Although the setting is located in the Notification tab, it affects the general QRG parser. It therefore influences the QRG column, detected active bands, priority calculations, band-upgrade hints and other functions which use a known station frequency – not only DX cluster spots.
|
||||
|
||||
### Band Upgrade Hint after a Log Entry
|
||||
|
||||
After receiving a log entry from UCXLog or Win-Test, KST4Contest can check whether the station which has just been worked still offers another common and unworked band.
|
||||
|
||||
The check uses the same derivation as the `a` and `B+` display:
|
||||
|
||||
1. the bands enabled in the local station settings,
|
||||
2. QRGs detected for the remote station during the previous 30 minutes,
|
||||
3. explicit band designators in the name fields of its active chat entries,
|
||||
4. stored per-band Worked marks, and
|
||||
5. manually assigned NOT-QRV marks.
|
||||
|
||||
Active chat variants of the same normalised callsign are evaluated together. NOT-QRV takes precedence over an automatically detected QRG or band designator.
|
||||
|
||||
If at least one common and unworked band remains, the main window displays a blinking **BAND+** hint for approximately twelve seconds. The callsign and remaining bands are included in the button text; the tooltip contains the complete derivation. If general notification sounds are enabled, KST4Contest also plays a short sound.
|
||||
|
||||
The two options serve different purposes:
|
||||
|
||||
- **Blink + sound …** enables the hint after a matching log entry.
|
||||
- **Priority boost …** additionally raises the score of stations which have already been worked on at least one band but still offer another common and unworked band.
|
||||
|
||||
The Priority Boost is only one factor in the complete calculation. Distance, antenna direction, recent activity, AirScout data, skeds and negative hints may still change the final order. Enabling the option therefore guarantees neither a particular score nor a particular position in the priority list.
|
||||
|
||||
The other score weights currently have no separate user-interface controls. Several existing settings nevertheless provide input data for the calculation, particularly the [enabled bands](#enabled-bands), [antenna beamwidth](#antenna-beamwidth), [default maximum QRB](#default-maximum-qrb) and [AirScout settings](#airscout-settings).
|
||||
|
||||
The complete calculation is described under [Priority Score and Priority List](en-Features#priority-score-and-priority-list-from-v140).
|
||||
|
||||
|
||||
The hint requires a log-synchronisation source which provides band information. The file-based callsign interpreter sees callsigns only and cannot reliably identify the band of the QSO which has just been logged.
|
||||
|
||||
Further explanation: [Band Upgrade Hint after a Log Entry](en-Features#band-upgrade-hint-after-a-log-entry).
|
||||
|
||||
---
|
||||
|
||||
## Shortcut Settings
|
||||
@@ -174,14 +244,37 @@ Use case: Keep track of important stations (e.g. DX expeditions or trusted conte
|
||||
|
||||
---
|
||||
|
||||
## GUI Settings: Band-Column Hints
|
||||
|
||||
Two optional additions to the band columns can be enabled or disabled in the **GUI** tab:
|
||||
|
||||
- **Show "o" in band columns …** displays an `o` if the four-character grid square has already been worked on the relevant band. Disabling the option does not delete any database records; it only hides the additional indicator in the band columns. `wkdany` is unaffected.
|
||||
- **Show "a" in band columns …** distinguishes a completely new callsign from a band opportunity involving a callsign already worked elsewhere. When disabled, both cases are displayed as `B+`. The band-opportunity calculation itself remains unchanged.
|
||||
|
||||
Changes are reflected in the current user interface immediately. Click **Save Settings** afterwards if they should persist after the next start.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Worked Station Database Settings
|
||||
|
||||
The internal worked database contains:
|
||||
The internal SQLite database stores contest-related state independently of the logging application's database:
|
||||
|
||||
- Worked status of all stations (per band)
|
||||
- NOT-QRV tags (since v1.2)
|
||||
- the global Worked status of a callsign,
|
||||
- Worked status per band,
|
||||
- manually assigned NOT-QRV marks per band, and
|
||||
- worked four-character grid squares per band.
|
||||
|
||||
**From v1.40**: Entries have an automatic lifetime of **3 days** – manually resetting before each contest is no longer strictly necessary. For a full reset, the **"Reinitialize"** button is still available.
|
||||
The normalised callsign, without visible chat brackets or category formatting, is used as the key. This allows active variants of the same callsign to be evaluated consistently.
|
||||
|
||||
Worked and NOT-QRV information expires automatically three days after its most recent change. Stored grid squares expire three days after the corresponding log entry. A manual reset before every contest is therefore normally unnecessary.
|
||||
|
||||
The **Reset worked, NOT-QRV and grid data...** button removes every Worked mark, NOT-QRV mark and stored worked grid square. A confirmation dialog is displayed first. Known callsign rows remain in the database; only the contest-related state is reset.
|
||||
|
||||
A reset is useful when you deliberately want to start with an empty contest state or have imported test data. It is not intended as a daily maintenance step.
|
||||
|
||||
Display and derivation: [Worked Callsigns, New Bands and New Grid Squares](en-Features#worked-callsigns-new-bands-and-new-grid-squares).
|
||||
|
||||
---
|
||||
|
||||
|
||||
+200
-28
@@ -48,26 +48,92 @@ Recognised formats: `144.205`, `432.088`, `.205` (with configured band assumptio
|
||||
|
||||
---
|
||||
|
||||
## Worked Marking
|
||||
## Worked Callsigns, New Bands and New Grid Squares
|
||||
|
||||
Worked stations are visually marked in the user list – per band. Based on [Log Synchronisation](en-Log-Sync) via UDP or Simplelogfile.
|
||||
KST4Contest distinguishes between three pieces of information which may look similar during a contest but answer different questions:
|
||||
|
||||
Reset the database before each contest: [Configuration – Worked Station Database Settings](Configuration#worked-station-database-settings).
|
||||
1. Has this callsign been worked before?
|
||||
2. Has this callsign been worked on a particular band?
|
||||
3. Has the four-character Maidenhead grid square already been worked, possibly with a different station?
|
||||
|
||||
---
|
||||
This distinction matters. A callsign already worked on one band may still be useful on another. Conversely, a new callsign may be located in a grid square which is already in the log.
|
||||
|
||||
## NOT-QRV Tags (from v1.2)
|
||||
### Worked information from the log
|
||||
|
||||
When a station indicates it is not QRV on a specific band, this can be manually marked:
|
||||
[Log Synchronisation](en-Log-Sync) imports new QSOs from the logging application. The amount of information available depends on the interface being used:
|
||||
|
||||
- The file-based Simplelogfile interpreter detects callsigns only. It can therefore set only the global Worked status.
|
||||
- The QSO UDP interfaces and the Win-Test network listener can also provide the band.
|
||||
- If the log packet contains a valid locator, KST4Contest additionally stores the worked four-character grid square for that band.
|
||||
|
||||
Missing information is not guessed. A QSO without a locator does not create a worked-grid record, and a Simplelogfile match does not create a band-specific Worked mark.
|
||||
|
||||
### Meaning of the band columns
|
||||
|
||||
The shared **worked** column contains only the bands enabled under **Station → My station uses …**. Its cells deliberately use short status codes because a full description would leave very little room for the actual user list.
|
||||
|
||||
| Display | Meaning |
|
||||
|---|---|
|
||||
| `X` | The callsign has been worked on this band. |
|
||||
| `a` | The station offers this band, the band has not been worked yet, and the callsign has not been worked on any band. |
|
||||
| `B+` | The station offers this band and it has not been worked yet. The callsign has already been worked on another band. If the separate `a` display is disabled, a completely new callsign is also shown as `B+`. |
|
||||
| `o` | The station's four-character grid square has already been worked on this band, regardless of callsign. |
|
||||
| empty | No matching information is available for this band. This does not mean that the station is not QRV. |
|
||||
|
||||
The `o` is an independent overlay and can therefore be combined with the other codes. Examples include `Xo`, `ao` and `B+o`. A single `o` means that the grid square has been worked on this band, while the displayed callsign has neither a Worked mark nor a current band opportunity.
|
||||
|
||||

|
||||
|
||||
### How is a band opportunity derived?
|
||||
|
||||
KST4Contest displays `a` or `B+` only if it can derive an open band opportunity. The calculation combines:
|
||||
|
||||
1. the bands enabled for the local station,
|
||||
2. QRGs detected for the remote station during the previous 30 minutes,
|
||||
3. explicit band designators in the remote station's name field,
|
||||
4. stored per-band Worked marks, and
|
||||
5. manually assigned NOT-QRV marks.
|
||||
|
||||
Active chat entries with the same normalised callsign are evaluated together. This is particularly relevant when the station appears in several chat categories or with different visible callsign variants. An explicit band designator in the name field remains useful while the corresponding chat entry is active. A band derived from a detected QRG expires after 30 minutes.
|
||||
|
||||
The remaining set contains only bands which are enabled locally, known for the remote station and not yet worked. A manual NOT-QRV mark overrides automatically detected evidence. The chat category alone is not sufficient evidence that an individual station is QRV on a particular band.
|
||||
|
||||
The global Worked mark does not decide whether a band opportunity exists. It merely selects `a` or `B+` for the display. The actual opportunity calculation uses per-band Worked information.
|
||||
|
||||
### Meaning of `wkdany`
|
||||
|
||||
The **wkdany** subcolumn combines the global callsign and grid-square status:
|
||||
|
||||
| Display | Meaning |
|
||||
|---|---|
|
||||
| empty | Neither the callsign nor the four-character grid square has been worked. |
|
||||
| `x` | The callsign has been worked on at least one band. |
|
||||
| `o` | The four-character grid square has been worked on at least one band. |
|
||||
| `xo` | Both the callsign and the grid square have been worked. |
|
||||
|
||||
`wkdany` is deliberately band-independent. The lower-case `x` must therefore not be confused with the upper-case `X` in a band column. The global status is used for the overview and the global **wkd** filter; it is not a substitute for per-band Worked information.
|
||||
|
||||
### NOT-QRV marks
|
||||
|
||||
If a station reports that it is not QRV on a particular band, mark this in the selected station's **Further Info** panel:
|
||||
|
||||
1. Select the station in the user list.
|
||||
2. Right-click → Set NOT-QRV for the appropriate band.
|
||||
2. Enable the relevant band under **Not QRV**.
|
||||
3. Use **tag not qrv all** only if the station should not be requested on any supported band.
|
||||
|
||||
These tags are stored in the internal database and persist after a KST4Contest restart. Can be reset via the settings.
|
||||
The individual NOT-QRV controls are shown for the bands enabled at the local station. **tag not qrv all**, however, marks every supported band, including bands which are not currently visible in the user interface. The state is stored per band under the normalised callsign and propagated to its active chat variants.
|
||||
|
||||
**Benefit**: Prevents repeated sked requests on bands where the station is not active – saves time for both sides.
|
||||

|
||||
|
||||
---
|
||||
NOT-QRV is a manual correction and therefore takes precedence over detected QRGs and band designators in the name field. The affected band is no longer offered as `a` or `B+`, is not counted as an opportunity by the **New bands** filter and is excluded by the corresponding band filter.
|
||||
|
||||
In plain terms: an automatically detected hint means "probably active on this band". A manual NOT-QRV mark means "do not request this station on this band". The next detected number must not silently reverse that decision.
|
||||
|
||||
### Storage and lifetime
|
||||
|
||||
Worked, NOT-QRV and worked-grid information is stored in the internal SQLite database and restored on the next start. Entries expire automatically after three days, so a reset before every contest is normally unnecessary.
|
||||
|
||||
A manual reset under **Workedstn database** removes all Worked marks, NOT-QRV marks and stored worked grid squares. The known callsign rows remain in the database. See [Worked Station Database Settings](en-Configuration#worked-station-database-settings) for details.
|
||||
|
||||
## Direction Filter
|
||||
|
||||
@@ -83,9 +149,19 @@ Hide stations beyond a maximum distance. The **"Show only QRB [km] <="** button
|
||||
|
||||
---
|
||||
|
||||
## Worked and NOT-QRV Filter
|
||||
## Filters for Worked Status, New Bands and New Grid Squares
|
||||
|
||||
Toggle buttons (one per band) to hide already-worked stations and/or NOT-QRV-tagged stations. The filter takes effect **immediately** without manually reactivating (live since v1.22).
|
||||
The filters above the user list use the same information as the Worked columns:
|
||||
|
||||
- **wkd** hides callsigns which have been worked on at least one band.
|
||||
- The individual band buttons hide a station if the callsign has already been worked on that band or has manually been marked NOT QRV there.
|
||||
- **New bands** shows only stations for which at least one locally enabled and unworked band is known. It evaluates recent QRG detections and band designators in the name field; NOT-QRV takes precedence.
|
||||
- **Only new grids** shows only stations whose four-character grid square has not been worked on any band. Stations without a valid locator do not pass this filter.
|
||||
- **Grid color** does not filter the list. When enabled, it gives the QRA cell of an already worked grid square a slightly darker background. New grid squares retain the normal table colour.
|
||||
|
||||
Several active filters are applied together. A station remains visible only if it satisfies every selected condition. The filters react immediately to new log entries and changed NOT-QRV marks.
|
||||
|
||||
Operation and layout of the filter bar: [User Interface – Filters](en-User-Interface#filters).
|
||||
|
||||
---
|
||||
|
||||
@@ -177,33 +253,129 @@ Configuration: [Configuration – PSTRotator Settings](en-Configuration#pstrotat
|
||||
|
||||
---
|
||||
|
||||
## Band Alert for New QSOs (from v1.40)
|
||||
## Band Upgrade Hint after a Log Entry
|
||||
|
||||
When a station is logged, KST4Contest automatically checks whether that station has shown any other active bands in the chat that you are also QRV on. If so, a **hint alert** appears so no multi-band opportunity is missed.
|
||||
When UCXLog or Win-Test reports a new log entry with band information, KST4Contest checks whether the worked station still offers another common band.
|
||||
|
||||
The calculation follows the same rules as `a`, `B+` and the **New bands** filter: locally enabled bands, recent QRG detections, band designators in the name field, per-band Worked marks and NOT-QRV marks. Active chat variants of the same normalised callsign are evaluated together.
|
||||
|
||||
If at least one common and unworked band remains, a blinking hint appears for approximately twelve seconds. It includes the callsign and the remaining bands, for example `BAND+ DL0ABC 432, 1296`. Its tooltip also lists the enabled, worked and NOT-QRV bands used for the decision. If general notification sounds are enabled, KST4Contest also plays a short sound.
|
||||
|
||||
The Simplelogfile interpreter cannot trigger this hint reliably because it provides no band information for the QSO which has just been logged.
|
||||
|
||||
Configuration: [Band Upgrade Hint after a Log Entry](en-Configuration#band-upgrade-hint-after-a-log-entry).
|
||||
|
||||
Worked, NOT-QRV and worked-grid data expire automatically after three days. See [Worked Station Database Settings](en-Configuration#worked-station-database-settings) for the lifetime and manual reset behaviour.
|
||||
|
||||
---
|
||||
|
||||
## Worked Tag Lifetime (from v1.40)
|
||||
## Priority Score and Priority List (from v1.40)
|
||||
|
||||
Worked stations are automatically removed from the database after **3 days**. Manually resetting the worked database before each contest is therefore no longer strictly necessary – the database keeps itself up to date.
|
||||
### Why is a score needed at all?
|
||||
|
||||
---
|
||||
A conventional chat user list initially tells the operator only which stations are logged in. That is not enough during a contest. The operator must also consider which stations have not yet been worked, which bands may still be available, where the antenna is pointing, whether a suitable aircraft is approaching and whether an agreed sked is about to begin.
|
||||
|
||||
## Chatmember Score System / Priority List (from v1.40)
|
||||
With a short list, much of this can still be handled mentally. As the contest continues, several bands are used and two chat categories are monitored at the same time, the same decision has to be reconstructed over and over again.
|
||||
|
||||
KST4Contest automatically calculates a **priority score** for each active chat member. The score is derived from:
|
||||
KST4Contest therefore combines the available information into a priority score. The score does not answer whether a QSO will definitely be possible. It supports the more practical question:
|
||||
|
||||
- Antenna direction of the remote station (is it pointing towards me?)
|
||||
- QRB (distance)
|
||||
- Activity time and message count
|
||||
- Active bands and frequencies
|
||||
- AP availability (AirScout)
|
||||
- Sked direction (degrees)
|
||||
- Sked success rate and skedfail markings
|
||||
> Which of the currently visible stations should I examine next?
|
||||
|
||||
The top candidates are highlighted in a dedicated priority list, helping you not to miss the most important contacts during contest stress.
|
||||
### When is a station excluded?
|
||||
|
||||
Stations with a failed sked can be marked using the **Skedfail button** in the FurtherInfo panel – this temporarily lowers their score.
|
||||
Before applying the weighted factors, KST4Contest checks whether a known band opportunity exists. All active chat entries belonging to the same normalised base callsign are evaluated together.
|
||||
|
||||
The calculation uses:
|
||||
|
||||
1. the bands enabled in the local station settings,
|
||||
2. QRGs detected for the remote station during the previous 30 minutes,
|
||||
3. explicit band designators in the name fields of its active chat entries,
|
||||
4. stored per-band Worked marks, and
|
||||
5. manually assigned NOT-QRV marks.
|
||||
|
||||
NOT QRV takes precedence over automatically detected frequencies and band designators.
|
||||
|
||||
If the remote station’s bands are known but none of them is both enabled locally and still available, the station receives a score of `0`. The same applies when every common band opportunity has already been worked.
|
||||
|
||||
A station is not excluded merely because all band information is missing. An unknown band opportunity is not the same as a known incompatibility. In this case, the station is removed from consideration only if all locally enabled bands have been manually marked NOT QRV for that station.
|
||||
|
||||
Stations with a score of `0` remain visible in the user list but are not included in the priority list.
|
||||
|
||||
### Which information raises or lowers the score?
|
||||
|
||||
The score combines several independent hints. One factor will therefore not normally determine the final position on its own.
|
||||
|
||||
| Factor | Effect on priority |
|
||||
|---|---|
|
||||
| Worked status | A callsign which has not been worked on any supported band receives a higher initial priority. A station which has already been worked is ranked lower but remains a candidate when another band opportunity is available. |
|
||||
| Available bands | Several common and unworked bands raise the priority. An additional boost for band-upgrade cases can be enabled separately. |
|
||||
| Distance | Distances below 200 km are weighted lower. The range between 200 km and the configured maximum QRB is preferred. Stations beyond the maximum QRB are reduced substantially. If the QRB is unavailable, this factor is omitted. |
|
||||
| Antenna direction | The score rises when the QTF to the station lies within half of the configured antenna beamwidth around the current local QTF. The closer both directions are, the stronger the effect. |
|
||||
| AirScout | At least one currently reachable aircraft raises the score. An expected AP opportunity in zero, one or two minutes receives an additional time-dependent weighting. |
|
||||
| Recent chat activity | A message received during the previous minute has a stronger effect than one received during the previous three minutes. Several incoming lines within the activity window raise the score further. |
|
||||
| Positive signals | Detected terms such as `QRV`, `READY`, `RGR`, `OK`, `TNX` or comparable configured text patterns are treated as a positive hint for several minutes. |
|
||||
| Reply behaviour | If another visible chat line from the station follows an outgoing `/cq` message quickly, the averaged reaction time raises the score. If no such line arrives before the configured timeout, a negative mark is added. |
|
||||
| Skeds | A scheduled contact initially adds a small amount of priority. During the final 15 minutes, its influence increases continuously. From three minutes before until one minute after the scheduled time, the sked receives very high priority. |
|
||||
| Failed attempt | **Sked fail** strongly reduces the station’s score until the mark is removed with **Reset fail** or KST4Contest is restarted. |
|
||||
|
||||
The default activity window for counting incoming messages is 180 seconds. A message received during the previous 60 seconds is evaluated separately as current activity. The default no-reply timeout is 13 minutes.
|
||||
|
||||
For reply behaviour, KST4Contest cannot prove that a later public or private line is actually a reply to the operator’s request. Any subsequent line received from the same station therefore ends the pending response-time measurement. This is a practical approximation, not a statistically reliable response rate.
|
||||
|
||||
### What does a scheduled contact mean for the score?
|
||||
|
||||
A sked is a time-dependent operating commitment. An imminent sked must therefore take precedence over most normal activity and distance hints. Without this weighting, a station which happens to be very active in the chat could displace an agreed contact from the priority list.
|
||||
|
||||
The strongest sked boost is deliberately limited to the period from three minutes before until one minute after the scheduled time. A sked further in the future remains relevant but should not yet dominate current operation.
|
||||
|
||||
The score is calculated for the normalised base callsign. A sked entered for an active variant such as `9A0BB-23` therefore affects the common score of the chat entries belonging to `9A0BB`.
|
||||
|
||||
### How are multiple suffixes and chat categories handled?
|
||||
|
||||
Active callsigns such as `9A0BB-2`, `9A0BB-70`, `9A0BB-23` and `9A0BB-13` remain separate chat members. Messages can therefore still be addressed to the complete callsign in the correct chat category.
|
||||
|
||||
Worked, band, NOT-QRV and score information belongs to the common base callsign `9A0BB`. The score is calculated once and projected to all active variants. The user list may consequently contain several separate rows with the same score, while the priority list contains only one entry for the base station.
|
||||
|
||||
KST4Contest uses the most recently suitable active login in the last relevant chat category as the concrete message target. Selecting a priority candidate then resolves the complete callsign, including its suffix and chat category.
|
||||
|
||||
### Updating and displaying the score
|
||||
|
||||
New messages, AirScout data, skeds, Worked information and manual NOT-QRV or Sked-fail changes request a new calculation immediately. The score is also refreshed periodically because activity, AP and sked information changes with time even when no new event is received.
|
||||
|
||||
A delay of a few seconds between an event and the visible new order is therefore normal.
|
||||
|
||||
The user interface displays the score in three places:
|
||||
|
||||
- the numerically sortable **Score** column in the user list,
|
||||
- the **Further Info** section for the selected station, and
|
||||
- the compact list of the two highest-ranked candidates, with a separate window containing up to 15 candidates.
|
||||
|
||||
Operation: [Priority List in the User Interface](en-User-Interface#priority-list).
|
||||
|
||||
### What does the score not tell you?
|
||||
|
||||
The numerical value is neither a success probability nor a signal prediction. A score which is twice as high does not mean that the QSO is twice as likely.
|
||||
|
||||
Among other things, the calculation does not know:
|
||||
|
||||
- the actual antenna direction of the remote station,
|
||||
- its current operating situation,
|
||||
- local interference,
|
||||
- short-term propagation changes,
|
||||
- terrain obstruction outside the connected assessment functions, or
|
||||
- whether a station which is active in the chat is currently sitting at the radio.
|
||||
|
||||
Known input data may also be outdated or ambiguous. A detected frequency, for example, proves only that the QRG recently appeared in connection with that station.
|
||||
|
||||
In practical terms, the score does not replace the operator’s decision. It prevents the information already available to KST4Contest from having to be reconstructed mentally for every candidate.
|
||||
|
||||
Related settings:
|
||||
|
||||
- [Enabled Bands](en-Configuration#enabled-bands)
|
||||
- [Antenna Beamwidth](en-Configuration#antenna-beamwidth)
|
||||
- [Default Maximum QRB](en-Configuration#default-maximum-qrb)
|
||||
- [AirScout Settings](en-Configuration#airscout-settings)
|
||||
- [Band Upgrade Hint and Priority Boost](en-Configuration#band-upgrade-hint-after-a-log-entry)
|
||||
|
||||
---
|
||||
|
||||
|
||||
+28
-12
@@ -2,7 +2,7 @@
|
||||
|
||||
> 🇬🇧 You are reading the English version | 🇩🇪 [Deutsche Version](de-Log-Synchronisation)
|
||||
|
||||
KST4Contest automatically marks worked stations in the chat user list. Two basic methods are available:
|
||||
KST4Contest imports worked stations from the logging application and derives the global Worked status, per-band Worked marks and – where a locator is available – worked grid squares. Three input paths are available: the file-based Simplelogfile interpreter, the general QSO UDP listener and the dedicated Win-Test network listener.
|
||||
|
||||
---
|
||||
|
||||
@@ -10,24 +10,25 @@ KST4Contest automatically marks worked stations in the chat user list. Two basic
|
||||
|
||||
## Method 1: Universal File Based Callsign Interpreter (Simplelogfile)
|
||||
|
||||
KST4Contest reads a log file and searches for callsign patterns using a regular expression. Binary log files are also supported – unreadable binary content is simply ignored.
|
||||
KST4Contest reads a log file and searches it for callsigns using a configurable regular expression. The file is read only and is never modified. Binary log files can also be used; content which cannot be interpreted as text is skipped.
|
||||
|
||||
**Advantage**: Works with almost any logging program that writes a file.
|
||||
**Disadvantage**: No band information available – stations are only marked as "worked", not on which band.
|
||||
The advantage is broad compatibility: no dedicated network interface is required from the logging application.
|
||||
|
||||
Enter the path to the log file in the Preferences. The file is only read, never modified (read-only).
|
||||
The limitation is equally clear. A callsign match alone provides neither a reliable band nor a locator. The Simplelogfile interpreter can therefore set only the global Worked status. It does not create a per-band `X`, a worked-grid record or a reliable basis for the band-upgrade hint after a log entry.
|
||||
|
||||
> **Tip**: The Simplelogfile function can also be used to mark stations that are definitely unreachable (e.g. personal notes). This will be replaced in a later version by a better tagging system.
|
||||
Configure the log-file path and regular expression in the **Log sync** tab. Use one of the network interfaces where possible if band-specific information is required.
|
||||
|
||||
---
|
||||
|
||||
## Method 2: Network Listener (UDP Broadcast) – Recommended
|
||||
# Method 2: Network Listener for QSO UDP Packets – Recommended
|
||||
|
||||
When saving a QSO, the logging software sends a UDP packet to the broadcast address of the home network. KST4Contest receives this packet and marks the station including **band information** in its internal SQLite database.
|
||||
UCXLog, QARTest, N1MM+ and DXLog.net can transmit a UDP packet when a QSO is saved. KST4Contest receives these packets on port `12060` by default and imports the callsign together with any band and locator information they contain.
|
||||
|
||||
> **Important**: KST4Contest must be **running in parallel with the logging software**. QSOs logged while KST4Contest is not running will not be captured – except with QARTest (which can send the complete log).
|
||||
If a band is available, the callsign is marked as worked on that band. If the packet also contains a valid locator, KST4Contest stores its four-character grid square for that band. Missing information is not inferred from unrelated fields.
|
||||
|
||||
**Default UDP port**: 12060 (matches the default of most logging programs)
|
||||
KST4Contest must be running when the packet is transmitted. Some logging applications can, however, resend an existing log: QARTest provides **Invia log completo**, while DXLog.net sends `contactreplace` packets when broadcasting the complete log. KST4Contest processes both mechanisms.
|
||||
|
||||
**Default port:** `12060`
|
||||
|
||||
---
|
||||
|
||||
@@ -81,11 +82,16 @@ For the built-in DX cluster server: configure N1MM+ as a DX cluster client (serv
|
||||
- Enter the IP of the KST4Contest computer (green-highlighted fields)
|
||||
- Port: 12060
|
||||
|
||||
When broadcasting the complete logbook, DXLog.net uses `contactreplace` instead of `contactinfo`. KST4Contest processes both packet types. Older QSOs can therefore be imported by starting a complete-log broadcast while KST4Contest is running.
|
||||
|
||||
### Win-Test
|
||||
|
||||
Win-Test is supported with a dedicated UDP network listener that understands the native Win-Test network protocol.
|
||||
|
||||
For a new QSO, KST4Contest imports the callsign and resolves the native Win-Test band ID. This includes 50 and 70 MHz. If the packet contains a valid locator, the worked grid square is also stored for the detected band.
|
||||
|
||||
**Advantages of Win-Test Integration:**
|
||||
- **Per-band Worked data:** New QSOs set the Worked mark for the band reported by Win-Test and update the grid-square status where a locator is available.
|
||||
- Automatic QSO synchronization to mark worked stations.
|
||||
- **Sked Handover (ADDSKED):** Using the "Create sked" button in the station info panel not only creates a sked in KST4Contest but also *sends it directly via UDP to the Win-Test network as an ADDSKED packet* – automatically, as soon as the listener is active. No separate toggle is needed.
|
||||
- You can choose between "AUTO", "SSB", or "CW" sked modes.
|
||||
@@ -144,6 +150,16 @@ For DM5M-style setups (2 radios, 2 computers, one KST4Contest instance or two se
|
||||
|
||||
## Internal Database
|
||||
|
||||
KST4Contest stores worked information in an internal **SQLite database**. This is independent of the logging program's database and is only populated via the UDP broadcast.
|
||||
KST4Contest stores Worked, NOT-QRV and worked-grid information in its own SQLite database. This database is independent of the logging application's database.
|
||||
|
||||
Before each new contest: reset the database! → [Configuration – Worked Station Database Settings](Configuration#worked-station-database-settings)
|
||||
The input sources provide different levels of detail:
|
||||
|
||||
| Source | Global callsign status | Per-band status | Grid square |
|
||||
|---|---:|---:|---:|
|
||||
| Simplelogfile | yes | no | no |
|
||||
| QSO UDP listener | yes | yes, if included in the packet | yes, if both band and locator are available |
|
||||
| Win-Test network listener | yes | yes | yes, if a locator is available |
|
||||
|
||||
The information is restored when KST4Contest starts and updated during operation when new log entries arrive. It expires automatically after three days, so a reset before every contest is normally unnecessary.
|
||||
|
||||
A complete manual reset removes Worked marks, NOT-QRV marks and worked grid squares together. See [Worked Station Database Settings](en-Configuration#worked-station-database-settings) for details.
|
||||
@@ -26,14 +26,29 @@ The central table of all currently active chat users. Columns (depending on conf
|
||||
|
||||
| Column | Content |
|
||||
|---|---|
|
||||
| Call | Station's callsign |
|
||||
| Name | Name from the chat name field |
|
||||
| Loc | Maidenhead locator |
|
||||
| Callsign | Station callsign |
|
||||
| Name | Name and additional information from the chat name field |
|
||||
| QRA | Maidenhead locator |
|
||||
| QRB | Distance in km |
|
||||
| QTF | Direction in degrees |
|
||||
| QRG | Automatically detected frequency |
|
||||
| AP | AirScout aircraft data (when active) |
|
||||
| Band colours | Worked / NOT-QRV status per band |
|
||||
| QRG | Most recent frequency detected in a chat message |
|
||||
| Tropo | Result of the band-specific tropo or path assessment |
|
||||
| Score | Current, numerically sortable priority score of the normalised base callsign |
|
||||
| Act | Minutes since the most recent activity |
|
||||
| AP | AirScout aircraft data, when enabled |
|
||||
| worked | Per-band Worked, band-opportunity and grid-square status, plus `wkdany` |
|
||||
| NOT QRV @ | Bands on which the station has manually been marked not QRV |
|
||||
| Category | Chat category of this entry |
|
||||
|
||||
### Worked, band and grid-square status
|
||||
|
||||
The subcolumns under **worked** use compact codes because several enabled bands leave little room for full descriptions. `X` marks a callsign worked on that band. `a` and `B+` identify an offered band which has not yet been worked. An appended `o` means that the four-character grid square has already been worked on this band.
|
||||
|
||||
The **wkdany** subcolumn is band-independent: `x` means that the callsign has been worked, `o` means that the grid square has been worked on any band, and `xo` means both.
|
||||
|
||||
Each status cell has a tooltip containing the legend and the state derived for that station. For the complete calculation, including NOT-QRV precedence, see [Worked Callsigns, New Bands and New Grid Squares](en-Features#worked-callsigns-new-bands-and-new-grid-squares).
|
||||
|
||||

|
||||
|
||||
**Sorting**: Click column headers. QRB sorting is numerical (corrected in v1.22).
|
||||
|
||||
@@ -53,26 +68,74 @@ Input field for the current antenna direction. Used for the planned `MYQTF` vari
|
||||
|
||||
## Filters
|
||||
|
||||
The filter bar (from v1.21 as a flowpane for small screens):
|
||||
The filter bar is located above the chat-member table and groups related controls:
|
||||
|
||||
- **Show only QTF**: Activate direction filter (N/NE/E/… buttons or degree input)
|
||||
- **Show only QRB [km] <=**: Activate distance filter (toggle button)
|
||||
- **Hide Worked [Band]**: Hide worked stations per band (one toggle per band)
|
||||
- **Hide NOT-QRV [Band]**: Hide NOT-QRV-tagged stations per band
|
||||
- **Show only QTF** limits the list to a selected antenna direction.
|
||||
- **Show only QRB [km] <=** sets a maximum distance.
|
||||
- **Find** searches for a callsign.
|
||||
- **wkd** hides callsigns which have already been worked on at least one band.
|
||||
- The individual band buttons hide a station if it has already been worked on that band or has been marked NOT QRV there. Only bands enabled for the local station are shown.
|
||||
- **Only new grids** shows only stations in four-character grid squares which have not been worked on any band.
|
||||
- **Grid color** is not a filter. It marks the QRA cell of an already worked grid square without hiding stations.
|
||||
- **New bands** shows stations with at least one detected, locally enabled and unworked band opportunity. NOT-QRV marks take precedence.
|
||||
- **Reachability**, **Tropo >=0dB** and **AS next 5m** limit the list according to the selected path or AirScout criteria.
|
||||
|
||||
The filter bar has no fixed width. QTF, Worked and Reachability controls initially use the available space in their respective rows. When the horizontal divider is moved to the right and the chat-member area becomes narrower, controls wrap only when their actual required width no longer fits.
|
||||
|
||||

|
||||
|
||||
In plain terms: the filters determine the table contents, but no longer enforce the minimum width of the entire right-hand side. The bar remains compact in the normal layout and uses additional height only when the view becomes genuinely narrow. Moving the divider back to the left immediately returns the controls to the available rows.
|
||||
|
||||
---
|
||||
|
||||
## Station Info Panel (Further Info)
|
||||
|
||||
Bottom right: Shows all messages of a selected station (CQ messages and PMs in one panel). A message filter can be pre-configured via the default filter in the Preferences.
|
||||
The lower-right panel combines the messages associated with the selected station. This includes public messages, private messages to the local station and, where visible in the chat, private messages addressed to other stations.
|
||||
|
||||
**Sked reminders** can also be activated here.
|
||||
The selected filter controls which of these messages are displayed. Under **Settings → GUI**, the default filter can be set to:
|
||||
|
||||
- all messages,
|
||||
- private messages to the local station,
|
||||
- private messages to other stations, or
|
||||
- public messages.
|
||||
|
||||
This setting changes the Further Info display only. Messages are neither discarded nor removed from the other message tables, and the filter can be changed at any time for the currently selected station.
|
||||
|
||||
The lower part of the panel contains per-band **Not QRV** marks for the selected station. Individual controls are shown for the bands enabled in the local station settings. **tag not qrv all** sets or removes the mark for every supported band, including bands which are not currently visible.
|
||||
|
||||
The change immediately affects the **NOT QRV @** column, band opportunities and the corresponding filters. It is stored in the internal database and restored after a restart.
|
||||
|
||||

|
||||
|
||||
The current **Priority score** of the selected station is displayed in the same section.
|
||||
|
||||
**Sked fail** marks an unsuccessful attempt and strongly reduces the score of the normalised base callsign. **Reset fail** removes the mark. It applies to all active suffix and category variants of the station and remains active for the current program session.
|
||||
|
||||
A sked and the corresponding **sked reminders** can be created underneath these controls. An approaching sked raises the Priority Score over time and receives very high priority immediately before the scheduled contact.
|
||||
|
||||
---
|
||||
|
||||
## Priority List
|
||||
|
||||
Shows the top candidates calculated by the Score Service. Updates automatically in the background based on direction, distance and AP availability.
|
||||
The compact priority bar is located on the right-hand side between the user list and the Further Info section. It displays the two currently highest-ranked candidates directly in the main window:
|
||||
|
||||
```text
|
||||
Priority: 1 CALLSIGN SCORE 2 CALLSIGN SCORE more
|
||||
```
|
||||
|
||||
Clicking either candidate selects the corresponding active chat member. The complete callsign, including its suffix and chat category, is used.
|
||||
|
||||
The **more** button opens a separate window containing up to 15 candidates. The list is sorted by descending score. Double-clicking an entry selects the candidate and closes the window.
|
||||
|
||||

|
||||
|
||||
Stations with a score of `0` are not included in the priority list. They remain visible in the user list so that the reason for their exclusion can be examined and, for example, an incorrect NOT-QRV mark can be changed.
|
||||
|
||||
The score is calculated for the normalised base callsign. Several active variants such as `9A0BB-2` and `9A0BB-70` may therefore display the same value in the user list. They nevertheless remain separate message targets.
|
||||
|
||||
New messages, AirScout data, skeds and status changes request a new calculation. A periodic refresh also runs in the background. A briefly outdated order is therefore not an error.
|
||||
|
||||
Calculation and limitations: [Priority Score and Priority List](en-Features#priority-score-and-priority-list-from-v140).
|
||||
|
||||
---
|
||||
|
||||
@@ -100,6 +163,7 @@ If you encounter display problems: delete the configuration file → KST4Contest
|
||||
## Operating Tips
|
||||
|
||||
- **Keep the settings window open**: Quick access to enable/disable the beacon.
|
||||
- **Right-click in the user list**: Opens the snippet menu and further actions (QRZ.com profile, set NOT-QRV tags).
|
||||
- **Right-click in the user list**: Opens the snippet menu and other context actions.
|
||||
- **Mark a station NOT QRV**: Select the station and use the per-band controls in the **Further Info** panel.
|
||||
- **Enter from anywhere**: When text is in the send field, Enter sends directly – even if the focus is elsewhere.
|
||||
- **Stop the beacon**: Switch off the beacon while scanning frequencies to avoid flooding the chat with messages.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 119 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 100 KiB |
@@ -1175,27 +1175,45 @@ private ObservableList<String>
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the active-member key. The raw/base callsign alone is not enough
|
||||
* because the same station can be logged into multiple ON4KST categories at
|
||||
* the same time. Therefore the category number is part of the key.
|
||||
* Builds the unique identity key for one active ON4KST login.
|
||||
*
|
||||
* <p>The complete callsign must be preserved here. Callsigns such as
|
||||
* {@code 9A0BB-2}, {@code 9A0BB-70} and {@code 9A0BB-144} represent different
|
||||
* active chat sessions and must therefore remain separate objects, even when
|
||||
* they are logged into the same chat category.</p>
|
||||
*
|
||||
* <p>The normalized base callsign ({@code callSignRaw}) is deliberately not
|
||||
* used for this key. It remains the common station key for worked, band and
|
||||
* NOT-QRV information.</p>
|
||||
*/
|
||||
private String buildActiveChatMemberKey(String callSign, ChatCategory category) {
|
||||
String normalizedCallsign = ChatMember.normalizeCallSignToBaseCallSign(callSign);
|
||||
if (normalizedCallsign == null || normalizedCallsign.isBlank()) {
|
||||
|
||||
if (callSign == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int categoryNumber = category == null ? -1 : category.getCategoryNumber();
|
||||
return normalizedCallsign.trim().toUpperCase(Locale.ROOT) + "|" + categoryNumber;
|
||||
String fullCallSign = callSign.trim().toUpperCase(Locale.ROOT);
|
||||
|
||||
if (fullCallSign.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int categoryNumber =
|
||||
category == null ? -1 : category.getCategoryNumber();
|
||||
|
||||
return fullCallSign + "|" + categoryNumber;
|
||||
}
|
||||
|
||||
private String buildActiveChatMemberKey(ChatMember member) {
|
||||
|
||||
if (member == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String callSign = member.getCallSignRaw() != null ? member.getCallSignRaw() : member.getCallSign();
|
||||
return buildActiveChatMemberKey(callSign, member.getChatCategory());
|
||||
return buildActiveChatMemberKey(
|
||||
member.getCallSign(),
|
||||
member.getChatCategory()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -602,76 +602,129 @@ public class MessageBusManagementThread extends Thread {
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a message sender from the thread-safe active-member model. If a
|
||||
* CH/CR message arrives before the matching user-enter message, a marked
|
||||
* fallback sender is used. The returned sender is never null.
|
||||
* Resolves a message sender from the thread-safe active-member model.
|
||||
*
|
||||
* <p>The local login is handled before the active-user lookup because the own
|
||||
* ChatMember is intentionally not stored in the visible user list. This also
|
||||
* prevents another active login with the same base callsign from replacing the
|
||||
* identity of our own message echo.</p>
|
||||
*/
|
||||
private ChatMember resolveInboundSender(String senderCallSign, ChatCategory category, ChatMessage message) {
|
||||
private ChatMember resolveInboundSender(
|
||||
String senderCallSign,
|
||||
ChatCategory category,
|
||||
ChatMessage message
|
||||
) {
|
||||
|
||||
String myCall =
|
||||
this.client.getChatPreferences().getStn_loginCallSign();
|
||||
|
||||
if (senderCallSign != null
|
||||
&& myCall != null
|
||||
&& senderCallSign.equalsIgnoreCase(myCall)) {
|
||||
|
||||
ChatMember ownSender = new ChatMember();
|
||||
ownSender.setCallSign(senderCallSign);
|
||||
ownSender.setChatCategory(category);
|
||||
ownSender.setAirPlaneReflectInfo(
|
||||
new AirPlaneReflectionInfo()
|
||||
);
|
||||
|
||||
return ownSender;
|
||||
}
|
||||
|
||||
ChatMember lookup = new ChatMember();
|
||||
lookup.setCallSign(senderCallSign);
|
||||
lookup.setChatCategory(category);
|
||||
|
||||
ChatMember senderObj = this.client.findActiveChatMember(lookup);
|
||||
ChatMember senderObj =
|
||||
this.client.findActiveChatMember(lookup);
|
||||
|
||||
if (senderObj != null) {
|
||||
senderObj.setActivityTimeLastInEpoch(new Utils4KST().time_generateCurrentEpochTime());
|
||||
senderObj.setActivityTimeLastInEpoch(
|
||||
new Utils4KST().time_generateCurrentEpochTime()
|
||||
);
|
||||
|
||||
// Remember the last active category so later outgoing replies can be routed correctly.
|
||||
this.client.rememberLastInboundCategory(senderObj.getCallSignRaw(), senderObj.getChatCategory());
|
||||
this.client.rememberLastInboundCategory(
|
||||
senderObj.getCallSignRaw(),
|
||||
senderObj.getChatCategory()
|
||||
);
|
||||
|
||||
// Metrics influence priority scoring; process them after message text is known.
|
||||
this.client.getStationMetricsService().onInboundMessage(
|
||||
senderObj.getCallSignRaw(),
|
||||
System.currentTimeMillis(),
|
||||
message == null ? null : message.getMessageText(),
|
||||
this.client.getChatPreferences(),
|
||||
this.client.getChatPreferences().getStn_loginCallSign()
|
||||
myCall
|
||||
);
|
||||
|
||||
this.client.getScoreService().requestRecompute(
|
||||
"rx-chat-message"
|
||||
);
|
||||
|
||||
this.client.getScoreService().requestRecompute("rx-chat-message");
|
||||
return senderObj;
|
||||
}
|
||||
|
||||
ChatMember fallbackSender = new ChatMember();
|
||||
String myCall = this.client.getChatPreferences().getStn_loginCallSign();
|
||||
if (senderCallSign != null && senderCallSign.equalsIgnoreCase(myCall)) {
|
||||
fallbackSender.setCallSign(myCall);
|
||||
} else {
|
||||
fallbackSender.setCallSign("[n/a]" + senderCallSign);
|
||||
}
|
||||
fallbackSender.setCallSign("[n/a]" + senderCallSign);
|
||||
fallbackSender.setChatCategory(category);
|
||||
fallbackSender.setAirPlaneReflectInfo(new AirPlaneReflectionInfo());
|
||||
fallbackSender.setAirPlaneReflectInfo(
|
||||
new AirPlaneReflectionInfo()
|
||||
);
|
||||
|
||||
return fallbackSender;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a message receiver from the active-member model. Unknown receivers
|
||||
* are represented as explicit fallback objects instead of null. This keeps PM
|
||||
* echo display and historic messages stable even if the target station already
|
||||
* left the chat.
|
||||
* Resolves a message receiver from the thread-safe active-member model.
|
||||
*
|
||||
* <p>The local login is handled before the active-user lookup. The receiver
|
||||
* from the ON4KST packet therefore remains authoritative even if another
|
||||
* station with the same base callsign is logged into the same category.</p>
|
||||
*/
|
||||
private ChatMember resolveInboundReceiver(String receiverCallSign, ChatCategory category) {
|
||||
if (receiverCallSign == null || receiverCallSign.equals("0")) {
|
||||
private ChatMember resolveInboundReceiver(
|
||||
String receiverCallSign,
|
||||
ChatCategory category
|
||||
) {
|
||||
|
||||
if (receiverCallSign == null
|
||||
|| receiverCallSign.equals("0")) {
|
||||
return createAllReceiver();
|
||||
}
|
||||
|
||||
String myCall =
|
||||
this.client.getChatPreferences().getStn_loginCallSign();
|
||||
|
||||
if (myCall != null
|
||||
&& receiverCallSign.equalsIgnoreCase(myCall)) {
|
||||
|
||||
ChatMember ownReceiver = new ChatMember();
|
||||
ownReceiver.setCallSign(receiverCallSign);
|
||||
ownReceiver.setChatCategory(category);
|
||||
ownReceiver.setAirPlaneReflectInfo(
|
||||
new AirPlaneReflectionInfo()
|
||||
);
|
||||
|
||||
return ownReceiver;
|
||||
}
|
||||
|
||||
ChatMember lookup = new ChatMember();
|
||||
lookup.setCallSign(receiverCallSign);
|
||||
lookup.setChatCategory(category);
|
||||
|
||||
ChatMember receiverObj = this.client.findActiveChatMember(lookup);
|
||||
ChatMember receiverObj =
|
||||
this.client.findActiveChatMember(lookup);
|
||||
|
||||
if (receiverObj != null) {
|
||||
return receiverObj;
|
||||
}
|
||||
|
||||
ChatMember fallbackReceiver = new ChatMember();
|
||||
String myCall = this.client.getChatPreferences().getStn_loginCallSign();
|
||||
if (receiverCallSign.equalsIgnoreCase(myCall)) {
|
||||
fallbackReceiver.setCallSign(myCall);
|
||||
} else {
|
||||
fallbackReceiver.setCallSign(receiverCallSign + "(left)");
|
||||
}
|
||||
fallbackReceiver.setCallSign(receiverCallSign + "(left)");
|
||||
fallbackReceiver.setChatCategory(category);
|
||||
fallbackReceiver.setAirPlaneReflectInfo(new AirPlaneReflectionInfo());
|
||||
fallbackReceiver.setAirPlaneReflectInfo(
|
||||
new AirPlaneReflectionInfo()
|
||||
);
|
||||
|
||||
return fallbackReceiver;
|
||||
}
|
||||
|
||||
|
||||
@@ -166,7 +166,15 @@ public final class ScoreService {
|
||||
scoreByCallRaw.put(callRaw, score);
|
||||
preferredCategoryByCallRaw.put(callRaw, representative.getChatCategory());
|
||||
|
||||
topAll.add(new TopCandidate(callRaw, representative.getCallSign(), representative.getChatCategory(), score));
|
||||
if (Double.isFinite(score) && score > 0.0) {
|
||||
topAll.add(new TopCandidate(
|
||||
callRaw,
|
||||
representative.getCallSign(),
|
||||
representative.getChatCategory(),
|
||||
score
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 3) Build Top-N
|
||||
@@ -227,12 +235,11 @@ public final class ScoreService {
|
||||
ChatMember chosen = null;
|
||||
|
||||
if (preferredCat != null) {
|
||||
for (ChatMember v : variants) {
|
||||
if (v != null && v.getChatCategory() == preferredCat) {
|
||||
chosen = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
chosen = variants.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(v -> isSameChatCategory(v.getChatCategory(), preferredCat))
|
||||
.max(Comparator.comparingLong(ChatMember::getActivityTimeLastInEpoch))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
if (chosen == null) {
|
||||
@@ -247,6 +254,14 @@ public final class ScoreService {
|
||||
|
||||
return representative;
|
||||
}
|
||||
|
||||
private static boolean isSameChatCategory(ChatCategory left, ChatCategory right) {
|
||||
return left != null
|
||||
&& right != null
|
||||
&& left.getCategoryNumber() == right.getCategoryNumber();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Projects the immutable score snapshot back into ChatMember display fields so
|
||||
* the normal station table can sort/filter by score without knowing the score
|
||||
|
||||
@@ -2,6 +2,7 @@ package kst4contest.controller;
|
||||
|
||||
import kst4contest.logic.SignalDetector;
|
||||
import kst4contest.model.ChatPreferences;
|
||||
import kst4contest.model.ChatMember;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
@@ -21,7 +22,7 @@ import java.util.regex.Pattern;
|
||||
public final class StationMetricsService {
|
||||
|
||||
/** /cq <CALL> ... */
|
||||
private static final Pattern OUTBOUND_CQ_PATTERN = Pattern.compile("(?i)^\\s*/cq\\s+([A-Z0-9/]+)\\b.*");
|
||||
private static final Pattern OUTBOUND_CQ_PATTERN = Pattern.compile("(?i)^\\s*/cq\\s+([A-Z0-9/-]+)\\b.*");
|
||||
|
||||
/** Rolling window timestamps for momentum scoring. */
|
||||
private static final int MAX_STORED_INBOUND_TIMESTAMPS = 32;
|
||||
@@ -195,7 +196,7 @@ public final class StationMetricsService {
|
||||
|
||||
private static String normalizeCallRaw(String s) {
|
||||
if (s == null) return null;
|
||||
return s.trim().toUpperCase();
|
||||
return ChatMember.normalizeCallSignToBaseCallSign(s);
|
||||
}
|
||||
|
||||
private static final class StationMetrics {
|
||||
|
||||
@@ -50,7 +50,7 @@ public class ChatPreferences {
|
||||
* Reading must stay backwards compatible: missing/unknown tags should fall back to defaults.
|
||||
*/
|
||||
// private static final int CONFIG_VERSION = 2;
|
||||
public static final int CONFIG_VERSION = 4;
|
||||
public static final int CONFIG_VERSION = 5;
|
||||
|
||||
// Prefer writing tag names that mirror variable names (human readable). Keep legacy tags for compatibility.
|
||||
private static final String TAG_CONFIG_VERSION = "configVersion";
|
||||
@@ -339,6 +339,7 @@ public class ChatPreferences {
|
||||
|
||||
private double[] GUIstationMapStageSceneSizeHW = new double[] { 1000, 800 };
|
||||
private double[] GUIstationMapStagePositionXY = new double[] { Double.NaN, Double.NaN };
|
||||
private boolean GUIstationMapPathAnalysisVisible = true;
|
||||
|
||||
|
||||
/*********************************************************************************
|
||||
@@ -635,6 +636,14 @@ public class ChatPreferences {
|
||||
this.GUIstationMapStagePositionXY = GUIstationMapStagePositionXY;
|
||||
}
|
||||
|
||||
public boolean isGUIstationMapPathAnalysisVisible() {
|
||||
return GUIstationMapPathAnalysisVisible;
|
||||
}
|
||||
|
||||
public void setGUIstationMapPathAnalysisVisible(boolean GUIstationMapPathAnalysisVisible) {
|
||||
this.GUIstationMapPathAnalysisVisible = GUIstationMapPathAnalysisVisible;
|
||||
}
|
||||
|
||||
public boolean isGuiOptions_defaultFilterNothing() {
|
||||
return guiOptions_defaultFilterNothing;
|
||||
}
|
||||
@@ -2048,6 +2057,12 @@ public class ChatPreferences {
|
||||
);
|
||||
guiOptions.appendChild(GUIstationMapStagePositionXY);
|
||||
|
||||
Element GUIstationMapPathAnalysisVisible = doc.createElement("GUIstationMapPathAnalysisVisible");
|
||||
GUIstationMapPathAnalysisVisible.setTextContent(
|
||||
String.valueOf(this.isGUIstationMapPathAnalysisVisible())
|
||||
);
|
||||
guiOptions.appendChild(GUIstationMapPathAnalysisVisible);
|
||||
|
||||
/****************************************************************************************
|
||||
****************************** now write this XML! *************************************
|
||||
****************************************************************************************/
|
||||
@@ -2423,8 +2438,11 @@ public class ChatPreferences {
|
||||
notify_noReplyPenaltyMinutes = noReply;
|
||||
}
|
||||
|
||||
Integer momentum = getInt(notificationsEl, 666, "notify_momentumWindowSeconds");
|
||||
if (momentum != null) {
|
||||
Integer momentum = getInt(
|
||||
notificationsEl,
|
||||
notify_momentumWindowSeconds,
|
||||
"notify_momentumWindowSeconds"
|
||||
); if (momentum != null) {
|
||||
notify_momentumWindowSeconds = momentum;
|
||||
}
|
||||
|
||||
@@ -2780,6 +2798,17 @@ public class ChatPreferences {
|
||||
this.getGUIstationMapStagePositionXY()
|
||||
);
|
||||
|
||||
/*
|
||||
* Files written before config version 5 do not contain this value.
|
||||
* Keep the default true in that case so existing users discover the
|
||||
* path-analysis feature before choosing to hide it themselves.
|
||||
*/
|
||||
this.setGUIstationMapPathAnalysisVisible(getBoolean(
|
||||
element,
|
||||
this.isGUIstationMapPathAnalysisVisible(),
|
||||
"GUIstationMapPathAnalysisVisible"
|
||||
));
|
||||
|
||||
// Splitpane divider positions
|
||||
String s1 = getText(element, null, "GUIselectedCallSignSplitPane_dividerposition");
|
||||
if (s1 != null) {
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package kst4contest.test;
|
||||
|
||||
import kst4contest.model.ChatPreferences;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class ChatPreferencesStationMapVisibilityTest {
|
||||
|
||||
@TempDir
|
||||
Path temporaryDirectory;
|
||||
|
||||
@Test
|
||||
void pathAnalysisIsVisibleByDefault() {
|
||||
ChatPreferences preferences = new ChatPreferences();
|
||||
|
||||
assertTrue(preferences.isGUIstationMapPathAnalysisVisible());
|
||||
}
|
||||
|
||||
@Test
|
||||
void hiddenPathAnalysisStateSurvivesXmlRoundTrip() throws IOException {
|
||||
Path preferencesFile = temporaryDirectory.resolve("preferences.xml");
|
||||
|
||||
ChatPreferences writtenPreferences = new ChatPreferences();
|
||||
writtenPreferences.setStoreAndRestorePreferencesFileName(
|
||||
preferencesFile.toString());
|
||||
writtenPreferences.setGUIstationMapPathAnalysisVisible(false);
|
||||
writtenPreferences.writePreferencesToXmlFile();
|
||||
|
||||
String writtenXml = Files.readString(preferencesFile);
|
||||
assertTrue(writtenXml.contains(
|
||||
"<GUIstationMapPathAnalysisVisible>false"
|
||||
+ "</GUIstationMapPathAnalysisVisible>"));
|
||||
|
||||
ChatPreferences restoredPreferences = new ChatPreferences();
|
||||
restoredPreferences.setStoreAndRestorePreferencesFileName(
|
||||
preferencesFile.toString());
|
||||
restoredPreferences.readPreferencesFromXmlFile();
|
||||
|
||||
assertFalse(restoredPreferences.isGUIstationMapPathAnalysisVisible());
|
||||
}
|
||||
|
||||
@Test
|
||||
void legacyXmlWithoutVisibilitySettingKeepsAnalysisDiscoverable()
|
||||
throws IOException {
|
||||
|
||||
Path legacyPreferencesFile =
|
||||
temporaryDirectory.resolve("legacy-preferences.xml");
|
||||
|
||||
Files.writeString(legacyPreferencesFile, """
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<praktiKST>
|
||||
<configVersion>4</configVersion>
|
||||
<guiOptions>
|
||||
<GUIstationMapStageSceneSizeHW>1000.0;800.0</GUIstationMapStageSceneSizeHW>
|
||||
</guiOptions>
|
||||
</praktiKST>
|
||||
""");
|
||||
|
||||
ChatPreferences restoredPreferences = new ChatPreferences();
|
||||
restoredPreferences.setStoreAndRestorePreferencesFileName(
|
||||
legacyPreferencesFile.toString());
|
||||
restoredPreferences.readPreferencesFromXmlFile();
|
||||
|
||||
assertTrue(restoredPreferences.isGUIstationMapPathAnalysisVisible());
|
||||
}
|
||||
}
|
||||
@@ -2431,24 +2431,32 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two ChatMember objects by their logical identity.
|
||||
* Compares two ChatMember objects by their active chat identity.
|
||||
*
|
||||
* JavaFX may replace item instances during refreshes, so object identity alone is
|
||||
* not enough. For selection stability we compare callsign/raw callsign and chat
|
||||
* category number.
|
||||
* <p>JavaFX may replace item instances during list refreshes, so object
|
||||
* identity alone is not sufficient. The complete callsign and the chat
|
||||
* category identify one active ON4KST login.</p>
|
||||
*
|
||||
* <p>The raw/base callsign must not be used here. Otherwise callsigns such as
|
||||
* {@code 9A0BB-2} and {@code 9A0BB-70} would still be treated as the same
|
||||
* selection inside one chat category.</p>
|
||||
*/
|
||||
private boolean isSameLogicalChatMember(ChatMember a, ChatMember b) {
|
||||
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a == null || b == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String aCall = a.getCallSignRaw() != null ? a.getCallSignRaw() : a.getCallSign();
|
||||
String bCall = b.getCallSignRaw() != null ? b.getCallSignRaw() : b.getCallSign();
|
||||
String aCallSign = a.getCallSign();
|
||||
String bCallSign = b.getCallSign();
|
||||
|
||||
if (aCall == null || bCall == null || !aCall.equalsIgnoreCase(bCall)) {
|
||||
if (aCallSign == null
|
||||
|| bCallSign == null
|
||||
|| !aCallSign.equalsIgnoreCase(bCallSign)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2458,11 +2466,13 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL
|
||||
if (aCategory == bCategory) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aCategory == null || bCategory == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return aCategory.getCategoryNumber() == bCategory.getCategoryNumber();
|
||||
return aCategory.getCategoryNumber()
|
||||
== bCategory.getCategoryNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4281,32 +4291,24 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL
|
||||
}
|
||||
|
||||
|
||||
private ChatMember resolveChatMemberForTopCandidate(kst4contest.controller.ScoreService.TopCandidate c) {
|
||||
private ChatMember resolveChatMemberForTopCandidate(
|
||||
kst4contest.controller.ScoreService.TopCandidate c
|
||||
) {
|
||||
|
||||
String callRaw = c.getCallSignRaw();
|
||||
ChatCategory preferredCategory = c.getPreferredChatCategory();
|
||||
|
||||
// 1) Prefer exact (callRaw + category) match
|
||||
synchronized (chatcontroller.getLst_chatMemberList()) {
|
||||
for (ChatMember m : chatcontroller.getLst_chatMemberList()) {
|
||||
if (m == null) continue;
|
||||
if (m.getCallSignRaw() == null) continue;
|
||||
if (!m.getCallSignRaw().equalsIgnoreCase(callRaw)) continue;
|
||||
|
||||
if (preferredCategory != null && preferredCategory.equals(m.getChatCategory())) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Fallback: any variant with the same callsignRaw
|
||||
for (ChatMember m : chatcontroller.getLst_chatMemberList()) {
|
||||
if (m == null) continue;
|
||||
if (m.getCallSignRaw() == null) continue;
|
||||
if (m.getCallSignRaw().equalsIgnoreCase(callRaw)) return m;
|
||||
}
|
||||
if (c == null
|
||||
|| c.getDisplayCallSign() == null
|
||||
|| c.getPreferredChatCategory() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
/*
|
||||
* Resolve the concrete active login by full callsign and category. Falling
|
||||
* back to callSignRaw could select a different suffix in the same category.
|
||||
*/
|
||||
return chatcontroller.findActiveChatMember(
|
||||
c.getDisplayCallSign(),
|
||||
c.getPreferredChatCategory()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -11359,15 +11361,19 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL
|
||||
vbxButtons.getChildren().addAll(btnOptionspnlConnect, btn_preferences_saveAsDefault, btnOptionsPnlApply,
|
||||
btnOptionspnlDisconnect, btnOptionspnlDisconnectOnly);
|
||||
|
||||
AnchorPane anchorPaneOkAndSave = new AnchorPane();
|
||||
AnchorPane.setRightAnchor(vbxButtons, 10d);
|
||||
AnchorPane.setBottomAnchor(vbxButtons, 10d);
|
||||
// AnchorPane anchorPaneOkAndSave = new AnchorPane();
|
||||
// AnchorPane.setRightAnchor(vbxButtons, 10d);
|
||||
// AnchorPane.setBottomAnchor(vbxButtons, 10d);
|
||||
//
|
||||
// anchorPaneOkAndSave.getChildren().addAll(vbxButtons);
|
||||
|
||||
anchorPaneOkAndSave.getChildren().addAll(vbxButtons);
|
||||
|
||||
optionsPanel.setBottom(anchorPaneOkAndSave);
|
||||
// optionsPanel.setBottom(anchorPaneOkAndSave);
|
||||
// optionsPanel.setAlignment(vbxButtons, Pos.CENTER);;
|
||||
|
||||
|
||||
vbxButtons.setAlignment(Pos.CENTER_LEFT);
|
||||
optionsPanel.setBottom(vbxButtons);
|
||||
|
||||
// VBox vBox = new VBox(tabPaneOptions);
|
||||
settingsScene = new Scene(optionsPanel, chatcontroller.getChatPreferences().getGUIsettingsStageSceneSizeHW()[0], chatcontroller.getChatPreferences().getGUIsettingsStageSceneSizeHW()[1]);
|
||||
settingsScene.getStylesheets().add(ApplicationConstants.STYLECSSFILE_DEFAULT_DAYLIGHT);
|
||||
|
||||
@@ -28,6 +28,8 @@ import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.ColumnConstraints;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.layout.HBox;
|
||||
|
||||
/**
|
||||
* Standalone station map window.
|
||||
@@ -49,6 +51,9 @@ public final class StationMapView {
|
||||
*/
|
||||
private static final boolean MAP_DEBUG_LOGGING = false;
|
||||
|
||||
private static final double MINIMUM_HEIGHT_WITH_PATH_ANALYSIS = 650.0;
|
||||
private static final double MINIMUM_HEIGHT_WITHOUT_PATH_ANALYSIS = 420.0;
|
||||
|
||||
private final PathProfileChart detailPathProfileChart = new PathProfileChart();
|
||||
private final Label detailPathModeValue = new Label("-");
|
||||
|
||||
@@ -76,6 +81,12 @@ public final class StationMapView {
|
||||
private VBox detailPane;
|
||||
|
||||
private final Label statusLabel = new Label("Station map not initialized yet.");
|
||||
|
||||
private final Label pathAnalysisHiddenHintLabel = new Label("Path analysis is hidden.");
|
||||
private final Button pathAnalysisVisibilityButton = new Button();
|
||||
private final Tooltip pathAnalysisVisibilityTooltip = new Tooltip();
|
||||
|
||||
|
||||
private final Label detailCallsignValue = new Label("-");
|
||||
private final Label detailLocatorValue = new Label("-");
|
||||
private final Label detailQrbValue = new Label("-");
|
||||
@@ -138,8 +149,12 @@ public final class StationMapView {
|
||||
private PathAnalysisResult lastPathAnalysisResult = PathAnalysisResult.waitingForSelection("");
|
||||
|
||||
private VBox mapAndProfilePane;
|
||||
private VBox profileSection;
|
||||
private VBox pathAnalysisSection;
|
||||
private ScrollPane detailScrollPane;
|
||||
|
||||
|
||||
|
||||
private final Label detailPathLosValue = new Label("-");
|
||||
private final Label detailPathWorstClearanceValue = new Label("-");
|
||||
|
||||
@@ -287,6 +302,14 @@ public final class StationMapView {
|
||||
}
|
||||
});
|
||||
|
||||
pathAnalysisVisibilityButton.setMinWidth(Region.USE_PREF_SIZE);
|
||||
pathAnalysisVisibilityButton.setTooltip(pathAnalysisVisibilityTooltip);
|
||||
pathAnalysisVisibilityButton.setOnAction(event ->
|
||||
setPathAnalysisVisible(!profileSection.isVisible(), true));
|
||||
|
||||
pathAnalysisHiddenHintLabel.setMinWidth(Region.USE_PREF_SIZE);
|
||||
pathAnalysisHiddenHintLabel.setStyle("-fx-font-style: italic; -fx-opacity: 0.85;");
|
||||
|
||||
webView.setFocusTraversable(true);
|
||||
webView.setPickOnBounds(true);
|
||||
|
||||
@@ -323,7 +346,8 @@ public final class StationMapView {
|
||||
webView.widthProperty().addListener((obs, oldValue, newValue) -> requestMapInvalidateSize());
|
||||
webView.heightProperty().addListener((obs, oldValue, newValue) -> requestMapInvalidateSize());
|
||||
|
||||
VBox profileSection = createProfileSection();
|
||||
profileSection = createProfileSection();
|
||||
|
||||
|
||||
mapAndProfilePane = new VBox(6, webView, profileSection);
|
||||
mapAndProfilePane.setPadding(new Insets(0));
|
||||
@@ -349,10 +373,9 @@ public final class StationMapView {
|
||||
mapAndProfilePane.widthProperty().subtract(20)
|
||||
);
|
||||
|
||||
detailPane = new VBox(10,
|
||||
createSelectedStationSection(),
|
||||
createPathAnalysisSection()
|
||||
);
|
||||
pathAnalysisSection = createPathAnalysisSection();
|
||||
detailPane = new VBox(10, createSelectedStationSection(), pathAnalysisSection);
|
||||
|
||||
detailPane.setPadding(new Insets(10));
|
||||
|
||||
detailPane.setMinWidth(0);
|
||||
@@ -364,8 +387,14 @@ public final class StationMapView {
|
||||
detailScrollPane.setFitToWidth(true);
|
||||
detailScrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
||||
detailScrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
|
||||
detailScrollPane.setMinWidth(300);
|
||||
/*
|
||||
* Allow the details pane to be reduced far enough to leave more room for the
|
||||
* map. At its minimum width, a callsign with up to ten characters remains
|
||||
* readable.
|
||||
*/
|
||||
detailScrollPane.setMinWidth(210);
|
||||
detailScrollPane.setPrefWidth(350);
|
||||
|
||||
detailScrollPane.setMaxWidth(Double.MAX_VALUE);
|
||||
|
||||
detailScrollPane.setFitToWidth(true);
|
||||
@@ -378,8 +407,7 @@ public final class StationMapView {
|
||||
SplitPane.setResizableWithParent(detailScrollPane, true);
|
||||
|
||||
rootPane = new BorderPane();
|
||||
rootPane.setTop(statusLabel);
|
||||
BorderPane.setMargin(statusLabel, new Insets(8));
|
||||
rootPane.setTop(createMapHeader());
|
||||
rootPane.setCenter(mainSplitPane);
|
||||
|
||||
double[] size = chatPreferences.getGUIstationMapStageSceneSizeHW();
|
||||
@@ -390,7 +418,12 @@ public final class StationMapView {
|
||||
scene = new Scene(rootPane, initialWidth, initialHeight);
|
||||
|
||||
stage.setMinWidth(900);
|
||||
stage.setMinHeight(650);
|
||||
stage.setMinHeight(resolveMinimumStationMapHeight(
|
||||
chatPreferences.isGUIstationMapPathAnalysisVisible()));
|
||||
|
||||
stage.setScene(scene);
|
||||
setPathAnalysisVisible(chatPreferences.isGUIstationMapPathAnalysisVisible(), false);
|
||||
applyThemeFromPreferences();
|
||||
|
||||
stage.setScene(scene);
|
||||
applyThemeFromPreferences();
|
||||
@@ -446,6 +479,91 @@ public final class StationMapView {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an always-visible header for the map status and analysis controls.
|
||||
*
|
||||
* Keeping the control outside the sections that it hides is important: users
|
||||
* must always have an obvious way to restore a previously hidden analysis.
|
||||
*/
|
||||
private HBox createMapHeader() {
|
||||
// The status may be shortened before the show/hide control is ever clipped.
|
||||
statusLabel.setMinWidth(0);
|
||||
statusLabel.setMaxWidth(Double.MAX_VALUE);
|
||||
statusLabel.setTextOverrun(OverrunStyle.ELLIPSIS);
|
||||
|
||||
HBox header = new HBox(
|
||||
10,
|
||||
statusLabel,
|
||||
pathAnalysisHiddenHintLabel,
|
||||
pathAnalysisVisibilityButton
|
||||
);
|
||||
header.setAlignment(Pos.CENTER_LEFT);
|
||||
header.setPadding(new Insets(8));
|
||||
HBox.setHgrow(statusLabel, Priority.ALWAYS);
|
||||
return header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows or hides both parts of the path analysis as one logical feature.
|
||||
*
|
||||
* Both visible and managed must be changed. A node that is merely invisible
|
||||
* would still reserve layout space and the map would not grow into that area.
|
||||
* The current analysis result remains attached to the controls and is
|
||||
* immediately available again when the user restores the sections.
|
||||
*
|
||||
* @param visible true to show the profile and detailed analysis
|
||||
* @param persist true when the change was explicitly requested by the user
|
||||
*/
|
||||
private void setPathAnalysisVisible(boolean visible, boolean persist) {
|
||||
profileSection.setVisible(visible);
|
||||
profileSection.setManaged(visible);
|
||||
|
||||
pathAnalysisSection.setVisible(visible);
|
||||
pathAnalysisSection.setManaged(visible);
|
||||
|
||||
pathAnalysisHiddenHintLabel.setVisible(!visible);
|
||||
pathAnalysisHiddenHintLabel.setManaged(!visible);
|
||||
|
||||
pathAnalysisVisibilityButton.setText(
|
||||
visible ? "Hide path analysis" : "Show path analysis");
|
||||
pathAnalysisVisibilityButton.setAccessibleText(
|
||||
visible ? "Hide path analysis" : "Show path analysis");
|
||||
pathAnalysisVisibilityButton.setStyle(
|
||||
visible ? "" : "-fx-font-weight: bold;");
|
||||
|
||||
pathAnalysisVisibilityTooltip.setText(visible
|
||||
? "Hide the path profile and detailed path analysis. You can show them again at any time."
|
||||
: "Show the path profile and detailed path analysis.");
|
||||
|
||||
pathAnalysisVisibilityButton.setAccessibleHelp(
|
||||
pathAnalysisVisibilityTooltip.getText());
|
||||
|
||||
if (!visible) {
|
||||
/*
|
||||
* Do not leave a profile hover marker on the map after its chart was
|
||||
* hidden.
|
||||
*/
|
||||
showProfileHoverPointOnMap(null);
|
||||
}
|
||||
|
||||
stage.setMinHeight(resolveMinimumStationMapHeight(visible));
|
||||
|
||||
if (persist) {
|
||||
chatPreferences.setGUIstationMapPathAnalysisVisible(visible);
|
||||
}
|
||||
|
||||
if (rootPane != null) {
|
||||
rootPane.requestLayout();
|
||||
Platform.runLater(this::requestMapInvalidateSize);
|
||||
}
|
||||
}
|
||||
|
||||
private double resolveMinimumStationMapHeight(boolean pathAnalysisVisible) {
|
||||
return pathAnalysisVisible
|
||||
? MINIMUM_HEIGHT_WITH_PATH_ANALYSIS
|
||||
: MINIMUM_HEIGHT_WITHOUT_PATH_ANALYSIS;
|
||||
}
|
||||
|
||||
private VBox createSelectedStationSection() {
|
||||
GridPane detailGrid = new GridPane();
|
||||
detailGrid.setHgap(8);
|
||||
@@ -494,13 +612,18 @@ public final class StationMapView {
|
||||
gridPane.getColumnConstraints().clear();
|
||||
|
||||
ColumnConstraints labelColumn = new ColumnConstraints();
|
||||
labelColumn.setMinWidth(105);
|
||||
labelColumn.setMinWidth(70);
|
||||
labelColumn.setPrefWidth(115);
|
||||
labelColumn.setMaxWidth(130);
|
||||
labelColumn.setHgrow(Priority.NEVER);
|
||||
|
||||
ColumnConstraints valueColumn = new ColumnConstraints();
|
||||
valueColumn.setMinWidth(180);
|
||||
|
||||
/*
|
||||
* Reserve enough space for a callsign with up to ten characters, while still
|
||||
* allowing the details pane to become considerably narrower.
|
||||
*/
|
||||
valueColumn.setMinWidth(85);
|
||||
valueColumn.setHgrow(Priority.ALWAYS);
|
||||
|
||||
gridPane.getColumnConstraints().addAll(labelColumn, valueColumn);
|
||||
@@ -1530,8 +1653,11 @@ public final class StationMapView {
|
||||
return 768.0;
|
||||
}
|
||||
|
||||
double minimumHeight = resolveMinimumStationMapHeight(
|
||||
chatPreferences.isGUIstationMapPathAnalysisVisible());
|
||||
|
||||
// Avoid restoring very large old test sizes after the layout changed.
|
||||
if (storedSize[1] < 650.0 || storedSize[1] > 1100.0) {
|
||||
if (storedSize[1] < minimumHeight || storedSize[1] > 1100.0) {
|
||||
return 768.0;
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -2379,4 +2379,7 @@ OZ1DLD/P;Bent;JO45SK;StringProperty [value: 144.285]; wkd true; wkd144 true; wkd
|
||||
SM6VTZ;Chris 2/70/23/3;JO58UJ;StringProperty [value: 144.135]; wkd true; wkd144 true; wkd432false; wkd1240false; wkd2300false; wkd3400false; wkd5600false; wkd10Gfalse ; 2: 144/432 MHz
|
||||
OZ7KJ;Skive Club;JO46ML;StringProperty [value: 144.225]; wkd true; wkd144 true; wkd432false; wkd1240false; wkd2300false; wkd3400false; wkd5600false; wkd10Gfalse ; 2: 144/432 MHz
|
||||
OV3T;Thomas;JO46CM;StringProperty [value: null]; wkd true; wkd144 true; wkd432false; wkd1240false; wkd2300false; wkd3400false; wkd5600false; wkd10Gfalse ; 2: 144/432 MHz
|
||||
OZ6TY;Henning;JO55XE;StringProperty [value: 144.196]; wkd true; wkd144 true; wkd432false; wkd1240false; wkd2300false; wkd3400false; wkd5600false; wkd10Gfalse ; 2: 144/432 MHz
|
||||
OZ6TY;Henning;JO55XE;StringProperty [value: 144.196]; wkd true; wkd144 true; wkd432false; wkd1240false; wkd2300false; wkd3400false; wkd5600false; wkd10Gfalse ; 2: 144/432 MHz
|
||||
DF7KF;Dithmar;JO30FK;StringProperty [value: null]; wkd true; wkd144 true; wkd432false; wkd1240false; wkd2300false; wkd3400false; wkd5600false; wkd10Gfalse ; 2: 144/432 MHz
|
||||
DH1NFJ;Jochen;JO50QL;StringProperty [value: null]; wkd true; wkd144 false; wkd432true; wkd1240false; wkd2300false; wkd3400false; wkd5600false; wkd10Gfalse ; 3: Microwave
|
||||
PA2RU;René;JO32LT;StringProperty [value: null]; wkd true; wkd144 false; wkd432false; wkd1240true; wkd2300false; wkd3400false; wkd5600false; wkd10Gfalse ; 2: 144/432 MHz
|
||||
+10
-8
@@ -97,15 +97,17 @@ function rewriteManualLinks(content, lang) {
|
||||
return `[${label}](/manual/${linkLang}/${slug.toLowerCase()}/)`;
|
||||
})
|
||||
|
||||
// Markdown-Links auf de-/en-Dateien ohne .md
|
||||
.replace(/\]\((en|de)-([^)#]+)\)/g, (match, linkLang, slug) => {
|
||||
return `](/manual/${linkLang}/${slug.toLowerCase()}/)`;
|
||||
})
|
||||
// Markdown links to German or English manual pages.
|
||||
// The source may contain an optional ".md" suffix and an optional anchor.
|
||||
// Both forms must be converted to the corresponding website manual URL.
|
||||
.replace(
|
||||
/\]\((en|de)-([^#)]+?)(?:\.md)?(?:#([^)]+))?\)/g,
|
||||
(match, linkLang, slug, anchor) => {
|
||||
const fragment = anchor ? `#${anchor}` : "";
|
||||
|
||||
// Markdown-Links auf de-/en-Dateien mit .md
|
||||
.replace(/\]\((en|de)-([^)#]+)\.md\)/g, (match, linkLang, slug) => {
|
||||
return `](/manual/${linkLang}/${slug.toLowerCase()}/)`;
|
||||
});
|
||||
return `](/manual/${linkLang}/${slug.toLowerCase()}/${fragment})`;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = function (eleventyConfig) {
|
||||
|
||||
@@ -3,8 +3,8 @@ title: Priority Score System
|
||||
icon: 🎯
|
||||
category: Contest Workflow
|
||||
since: "1.40"
|
||||
summary: Rank active stations from known context such as direction, activity, band, QRG, AP and sked information.
|
||||
description: The Priority Score System combines available contest information to populate a separate list of currently relevant candidates.
|
||||
summary: Rank active base callsigns using known band, direction, activity, AirScout, reply and sked information.
|
||||
description: KST4Contest excludes stations with no known remaining band opportunity and orders the other active candidates using the context already available to the client.
|
||||
tagsList:
|
||||
- ON4KST
|
||||
- VHF
|
||||
@@ -18,12 +18,41 @@ related:
|
||||
- sked-reminder
|
||||
---
|
||||
|
||||
## Why it matters
|
||||
## The problem behind the score
|
||||
|
||||
During active VHF, UHF and microwave contests, relevant stations can disappear quickly in busy ON4KST chat traffic.
|
||||
An ON4KST user list shows who is logged in. During a contest, the more useful question is which station should be examined next.
|
||||
|
||||
The Priority Score System helps operators focus on stations that are more likely to be useful during contest operation.
|
||||
Answering that question manually means repeatedly combining Worked status, possible bands, distance, antenna direction, recent activity, AP opportunities and scheduled contacts. This remains manageable with a short list. It becomes less reliable after several hours of contest operation, especially when multiple bands and chat categories are involved.
|
||||
|
||||
## Built for contest decisions
|
||||
## How candidates are selected
|
||||
|
||||
KST4Contest is not just a chat viewer. It evaluates contest-relevant context and helps turn chat activity into better operating decisions.
|
||||
KST4Contest first checks whether a known common and unworked band opportunity remains. Locally enabled bands, recent QRG detections, band designators in station names, Worked information and manual NOT-QRV marks are evaluated together.
|
||||
|
||||
A known incompatibility or an already completed set of possible bands produces a score of `0` and removes the station from the priority list. Missing band information alone does not. Unknown is not the same as impossible.
|
||||
|
||||
The remaining stations are ranked using several independent hints, including:
|
||||
|
||||
- distance and the configured maximum QRB,
|
||||
- the current antenna direction and beamwidth,
|
||||
- recent chat activity and reaction behaviour,
|
||||
- available AirScout aircraft,
|
||||
- open band opportunities, and
|
||||
- the timing of scheduled contacts.
|
||||
|
||||
An imminent sked receives a deliberately strong boost. Failed attempts and unanswered calls reduce the score.
|
||||
|
||||
## One station, several chat logins
|
||||
|
||||
Suffixes and chat categories remain separate message targets. Worked, band, NOT-QRV and score information is shared through the normalised base callsign.
|
||||
|
||||
This prevents a station using several band-specific logins from occupying several positions in the priority list while still allowing KST4Contest to address the correct complete callsign in the correct category.
|
||||
|
||||

|
||||
|
||||
## A decision aid, not a propagation forecast
|
||||
|
||||
The score is a relative operating priority. It is not a success probability, a signal estimate or a guarantee that the remote station is ready for a QSO.
|
||||
|
||||
Its value depends on the information available to KST4Contest, and that information may be incomplete, outdated or ambiguous. The final decision remains with the operator.
|
||||
|
||||
[Read the complete calculation and its limitations in the manual.](/manual/en/features/#priority-score-and-priority-list-from-v140)
|
||||
Reference in New Issue
Block a user