Compare commits
11 Commits
f93f3acbb0
...
update_wik
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
071ea800ae | ||
| e01cc3ca11 | |||
| aaa5c1088a | |||
| 178783aa8c | |||
| 68d171e793 | |||
| e4501e848a | |||
| b16dd1303a | |||
| e5b30c3049 | |||
| 318f3720b8 | |||
| db031bb5e3 | |||
| d635ee3fef |
258
.github/latex-manual/manual-template.tex
vendored
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
%% ============================================================
|
||||||
|
%% KST4Contest – pandoc LaTeX manual template
|
||||||
|
%% PDF engine: XeLaTeX
|
||||||
|
%% Usage: pandoc --template=manual-template.tex --pdf-engine=xelatex
|
||||||
|
%% ============================================================
|
||||||
|
\documentclass[11pt,a4paper]{article}
|
||||||
|
|
||||||
|
%% ─── Font / encoding ──────────────────────────────────────────────────────
|
||||||
|
\usepackage{fontspec}
|
||||||
|
% Latin Modern handles all Western European characters (umlauts etc.)
|
||||||
|
\defaultfontfeatures{Ligatures=TeX,Scale=MatchLowercase}
|
||||||
|
|
||||||
|
%% ─── Language ─────────────────────────────────────────────────────────────
|
||||||
|
\usepackage{polyglossia}
|
||||||
|
$if(polyglossia-lang)$
|
||||||
|
\setmainlanguage{$polyglossia-lang$}
|
||||||
|
$else$
|
||||||
|
\setmainlanguage{english}
|
||||||
|
$endif$
|
||||||
|
|
||||||
|
%% ─── Page layout ──────────────────────────────────────────────────────────
|
||||||
|
\usepackage[a4paper, top=2.5cm, bottom=2.5cm, left=2.5cm, right=2.5cm]{geometry}
|
||||||
|
|
||||||
|
%% ─── Text decorations (strikethrough via ~~...~~ in Markdown → \st{}) ────
|
||||||
|
\usepackage{soul}
|
||||||
|
|
||||||
|
%% ─── Colors ───────────────────────────────────────────────────────────────
|
||||||
|
\usepackage[dvipsnames,svgnames,x11names]{xcolor}
|
||||||
|
\definecolor{brand-green}{RGB}{7,166,54}
|
||||||
|
\definecolor{link-blue}{RGB}{0,86,163}
|
||||||
|
\definecolor{code-bg}{RGB}{245,247,250}
|
||||||
|
\definecolor{code-border}{RGB}{180,200,225}
|
||||||
|
\definecolor{blockquote-line}{RGB}{7,166,54}
|
||||||
|
|
||||||
|
%% ─── Hyperlinks ───────────────────────────────────────────────────────────
|
||||||
|
\usepackage{hyperref}
|
||||||
|
\hypersetup{
|
||||||
|
colorlinks = true,
|
||||||
|
linkcolor = link-blue,
|
||||||
|
urlcolor = link-blue,
|
||||||
|
filecolor = link-blue,
|
||||||
|
citecolor = link-blue,
|
||||||
|
pdftitle = {$title$},
|
||||||
|
pdfauthor = {DO5AMF (Marc Fröhlich), DN9APW (Philipp Wagner)},
|
||||||
|
pdfsubject = {KST4Contest User Manual},
|
||||||
|
pdfkeywords = {KST4Contest, pratiKST, VHF, Contest, Ham Radio},
|
||||||
|
bookmarks = true,
|
||||||
|
bookmarksnumbered = true,
|
||||||
|
bookmarksopen = true,
|
||||||
|
bookmarksopenlevel = 2,
|
||||||
|
pdfpagemode = UseOutlines,
|
||||||
|
}
|
||||||
|
|
||||||
|
%% ─── Graphics ─────────────────────────────────────────────────────────────
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\graphicspath{{./}{./github_docs/}}
|
||||||
|
\makeatletter
|
||||||
|
\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
|
||||||
|
\def\maxheight{\ifdim\Gin@nat@height>0.65\textheight 0.65\textheight\else\Gin@nat@height\fi}
|
||||||
|
\makeatother
|
||||||
|
\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
|
||||||
|
|
||||||
|
%% ─── Tables ───────────────────────────────────────────────────────────────
|
||||||
|
\usepackage{longtable}
|
||||||
|
\usepackage{booktabs}
|
||||||
|
\usepackage{array}
|
||||||
|
\usepackage{calc}
|
||||||
|
\usepackage{multirow}
|
||||||
|
\setlength{\tabcolsep}{8pt}
|
||||||
|
\renewcommand{\arraystretch}{1.35}
|
||||||
|
% Pandoc pipe-table helpers
|
||||||
|
\newcolumntype{L}[1]{>{\raggedright\arraybackslash}p{#1}}
|
||||||
|
\newcolumntype{C}[1]{>{\centering\arraybackslash}p{#1}}
|
||||||
|
\newcolumntype{R}[1]{>{\raggedleft\arraybackslash}p{#1}}
|
||||||
|
|
||||||
|
%% ─── Lists ────────────────────────────────────────────────────────────────
|
||||||
|
\providecommand{\tightlist}{%
|
||||||
|
\setlength{\itemsep}{2pt}\setlength{\parskip}{0pt}}
|
||||||
|
|
||||||
|
%% ─── Code blocks (--listings flag) ───────────────────────────────────
|
||||||
|
\usepackage{listings}
|
||||||
|
\lstset{
|
||||||
|
basicstyle = \ttfamily\small,
|
||||||
|
backgroundcolor = \color{code-bg},
|
||||||
|
frame = single,
|
||||||
|
framesep = 4pt,
|
||||||
|
rulecolor = \color{code-border},
|
||||||
|
breaklines = true,
|
||||||
|
breakatwhitespace= false,
|
||||||
|
showstringspaces = false,
|
||||||
|
extendedchars = true,
|
||||||
|
xleftmargin = 6pt,
|
||||||
|
xrightmargin = 6pt,
|
||||||
|
aboveskip = 8pt,
|
||||||
|
belowskip = 8pt,
|
||||||
|
literate = {→}{{\ensuremath{\rightarrow}}}1
|
||||||
|
{←}{{\ensuremath{\leftarrow}}}1
|
||||||
|
{↔}{{\ensuremath{\leftrightarrow}}}1,
|
||||||
|
}
|
||||||
|
|
||||||
|
%% ─── Blockquotes ──────────────────────────────────────────────────────────
|
||||||
|
\usepackage{mdframed}
|
||||||
|
\newmdenv[
|
||||||
|
topline = false,
|
||||||
|
rightline = false,
|
||||||
|
bottomline = false,
|
||||||
|
leftline = true,
|
||||||
|
linewidth = 3pt,
|
||||||
|
linecolor = blockquote-line,
|
||||||
|
backgroundcolor = code-bg,
|
||||||
|
leftmargin = 0pt,
|
||||||
|
rightmargin = 0pt,
|
||||||
|
innerleftmargin = 12pt,
|
||||||
|
innerrightmargin = 8pt,
|
||||||
|
innertopmargin = 6pt,
|
||||||
|
innerbottommargin= 6pt,
|
||||||
|
skipabove = 8pt,
|
||||||
|
skipbelow = 8pt,
|
||||||
|
]{blockquotebox}
|
||||||
|
|
||||||
|
\renewenvironment{quote}
|
||||||
|
{\begin{blockquotebox}\small\itshape}
|
||||||
|
{\end{blockquotebox}}
|
||||||
|
|
||||||
|
%% ─── Section styling ──────────────────────────────────────────────────────
|
||||||
|
\usepackage{titlesec}
|
||||||
|
|
||||||
|
\titleformat{\section}
|
||||||
|
{\Large\bfseries\color{brand-green}}
|
||||||
|
{}
|
||||||
|
{0em}
|
||||||
|
{}
|
||||||
|
[\color{brand-green}\titlerule]
|
||||||
|
\titlespacing{\section}{0pt}{20pt}{10pt}
|
||||||
|
|
||||||
|
\titleformat{\subsection}
|
||||||
|
{\large\bfseries\color{brand-green}}
|
||||||
|
{}
|
||||||
|
{0em}
|
||||||
|
{}
|
||||||
|
\titlespacing{\subsection}{0pt}{14pt}{6pt}
|
||||||
|
|
||||||
|
\titleformat{\subsubsection}
|
||||||
|
{\normalsize\bfseries}
|
||||||
|
{}
|
||||||
|
{0em}
|
||||||
|
{}
|
||||||
|
\titlespacing{\subsubsection}{0pt}{10pt}{4pt}
|
||||||
|
|
||||||
|
% Level 4 (####): displayed as a named block heading in dark-grey
|
||||||
|
\titleformat{\paragraph}
|
||||||
|
{\normalsize\bfseries\color{brand-green}}
|
||||||
|
{}
|
||||||
|
{0em}
|
||||||
|
{}
|
||||||
|
\titlespacing{\paragraph}{0pt}{8pt}{2pt}
|
||||||
|
|
||||||
|
% Level 5 (#####): slightly smaller, italic, lighter grey
|
||||||
|
\titleformat{\subparagraph}
|
||||||
|
{\small\bfseries\itshape\color{brand-green!85!black}}
|
||||||
|
{}
|
||||||
|
{0em}
|
||||||
|
{}
|
||||||
|
\titlespacing{\subparagraph}{0pt}{6pt}{1pt}
|
||||||
|
|
||||||
|
% Reserve two additional section levels for future use (###### and deeper).
|
||||||
|
% Pandoc currently maps up to \subparagraph for standard Markdown headings.
|
||||||
|
\titleclass{\subsubsubsection}{straight}[\subparagraph]
|
||||||
|
\newcounter{subsubsubsection}[subparagraph]
|
||||||
|
\renewcommand\thesubsubsubsection{\thesubparagraph.\arabic{subsubsubsection}}
|
||||||
|
\titleformat{\subsubsubsection}
|
||||||
|
{\small\bfseries\color{brand-green!75!black}}
|
||||||
|
{}
|
||||||
|
{0em}
|
||||||
|
{}
|
||||||
|
\titlespacing{\subsubsubsection}{0pt}{5pt}{1pt}
|
||||||
|
|
||||||
|
\titleclass{\subsubsubsubsection}{straight}[\subsubsubsection]
|
||||||
|
\newcounter{subsubsubsubsection}[subsubsubsection]
|
||||||
|
\renewcommand\thesubsubsubsubsection{\thesubsubsubsection.\arabic{subsubsubsubsection}}
|
||||||
|
\titleformat{\subsubsubsubsection}
|
||||||
|
{\small\itshape\color{brand-green!65!black}}
|
||||||
|
{}
|
||||||
|
{0em}
|
||||||
|
{}
|
||||||
|
\titlespacing{\subsubsubsubsection}{0pt}{4pt}{1pt}
|
||||||
|
|
||||||
|
\setcounter{secnumdepth}{6}
|
||||||
|
\setcounter{tocdepth}{6}
|
||||||
|
|
||||||
|
%% ─── Header / Footer ──────────────────────────────────────────────────────
|
||||||
|
\usepackage{fancyhdr}
|
||||||
|
\pagestyle{fancy}
|
||||||
|
\fancyhf{}
|
||||||
|
\fancyhead[L]{\small\color{brand-green}\textbf{KST4Contest}}
|
||||||
|
\fancyhead[R]{\small\color{brand-green}$if(version)$$version$$endif$}
|
||||||
|
\fancyfoot[L]{\small\color{gray}DO5AMF \textbar\ DN9APW}
|
||||||
|
\fancyfoot[C]{\small\color{gray}\thepage}
|
||||||
|
\fancyfoot[R]{\small\color{gray}$title$}
|
||||||
|
\renewcommand{\headrulewidth}{0.4pt}
|
||||||
|
\renewcommand{\footrulewidth}{0.3pt}
|
||||||
|
\renewcommand{\headrule}{\color{brand-green}\hrule width\headwidth height\headrulewidth}
|
||||||
|
|
||||||
|
%% ─── Paragraph spacing ────────────────────────────────────────────────────
|
||||||
|
\usepackage{parskip}
|
||||||
|
\setlength{\parskip}{6pt}
|
||||||
|
\setlength{\parindent}{0pt}
|
||||||
|
|
||||||
|
%% ─── TOC styling ──────────────────────────────────────────────────────────
|
||||||
|
\usepackage{tocloft}
|
||||||
|
\renewcommand{\cfttoctitlefont}{\Large\bfseries\color{brand-green}}
|
||||||
|
\renewcommand{\cftsecfont}{\bfseries\color{brand-green}}
|
||||||
|
\renewcommand{\cftsecpagefont}{\bfseries\color{brand-green}}
|
||||||
|
\renewcommand{\cftsubsecfont}{\color{brand-green}}
|
||||||
|
\renewcommand{\cftsubsecpagefont}{\color{brand-green}}
|
||||||
|
\renewcommand{\cftsubsubsecfont}{\color{brand-green!85!black}}
|
||||||
|
\renewcommand{\cftsubsubsecpagefont}{\color{brand-green!85!black}}
|
||||||
|
\renewcommand{\cftparafont}{\color{brand-green!75!black}}
|
||||||
|
\renewcommand{\cftparapagefont}{\color{brand-green!75!black}}
|
||||||
|
\renewcommand{\cftsubparafont}{\color{brand-green!65!black}}
|
||||||
|
\renewcommand{\cftsubparapagefont}{\color{brand-green!65!black}}
|
||||||
|
\setlength{\cftbeforesecskip}{4pt}
|
||||||
|
|
||||||
|
%% ─── Misc ─────────────────────────────────────────────────────────────────
|
||||||
|
\usepackage{amsmath}
|
||||||
|
\usepackage{microtype}
|
||||||
|
% Pandoc helper macros
|
||||||
|
\newcommand{\passthrough}[1]{#1}
|
||||||
|
|
||||||
|
%% ══════════════════════════════════════════════════════════════════════════
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
%% ─── Title page ───────────────────────────────────────────────────────────
|
||||||
|
\begin{titlepage}
|
||||||
|
\pagecolor{brand-green}
|
||||||
|
\centering
|
||||||
|
\vspace*{3.5cm}
|
||||||
|
{\fontsize{52}{62}\selectfont\bfseries\color{white}KST4Contest}\\[0.4cm]
|
||||||
|
{\fontsize{22}{28}\selectfont\color{white!75!brand-green}pratiKST (ON4KST Chat Client)}\\[2.8cm]
|
||||||
|
\color{white!40!brand-green}\rule{10cm}{0.6pt}\\[1.8cm]
|
||||||
|
{\LARGE\bfseries\color{white}$title$}\\[1cm]
|
||||||
|
$if(version)${\large\color{white!80!brand-green}Version:\space$version$}\\[0.6cm]$endif$
|
||||||
|
\vfill
|
||||||
|
{\large\color{white}DO5AMF · Marc Fröhlich · DM5M · DN9APW · Philipp Wagner}\\[0.4cm]
|
||||||
|
{\color{white!70!brand-green}\today}\\[2cm]
|
||||||
|
\end{titlepage}
|
||||||
|
|
||||||
|
\pagecolor{white}
|
||||||
|
\newpage
|
||||||
|
|
||||||
|
%% ─── Table of Contents ────────────────────────────────────────────────────
|
||||||
|
\tableofcontents
|
||||||
|
\newpage
|
||||||
|
|
||||||
|
%% ─── Main content ─────────────────────────────────────────────────────────
|
||||||
|
$body$
|
||||||
|
|
||||||
|
\end{document}
|
||||||
156
.github/latex-manual/strip-wiki-links.lua
vendored
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
--[[
|
||||||
|
strip-wiki-links.lua – pandoc Lua filter for KST4Contest documentation
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
1. Removes language-switch blockquotes (GitHub Wiki navigation) that
|
||||||
|
are not relevant in the printed PDF manual.
|
||||||
|
2. Converts internal GitHub-wiki-style links to in-document anchors
|
||||||
|
so links jump within the generated PDF.
|
||||||
|
3. Replaces flag emoji and other symbols that XeLaTeX cannot render with
|
||||||
|
plain-text equivalents.
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local PAGE_ANCHOR_MAP = {
|
||||||
|
["de-Home"] = "kst4contest-wiki",
|
||||||
|
["de-Installation"] = "installation",
|
||||||
|
["de-Konfiguration"] = "konfiguration",
|
||||||
|
["de-Funktionen"] = "funktionen",
|
||||||
|
["de-Benutzeroberflaeche"] = "benutzeroberflache",
|
||||||
|
["de-Makros-und-Variablen"] = "makros-und-variablen",
|
||||||
|
["de-Log-Synchronisation"] = "log-synchronisation",
|
||||||
|
["de-AirScout-Integration"] = "airscout-integration",
|
||||||
|
["de-DX-Cluster-Server"] = "integrierter-dx-cluster-server",
|
||||||
|
["de-Changelog"] = "changelog",
|
||||||
|
|
||||||
|
["en-Home"] = "kst4contest-wiki",
|
||||||
|
["en-Installation"] = "installation",
|
||||||
|
["en-Configuration"] = "configuration",
|
||||||
|
["en-Features"] = "features",
|
||||||
|
["en-User-Interface"] = "user-interface",
|
||||||
|
["en-Macros-and-Variables"] = "macros-and-variables",
|
||||||
|
["en-Log-Sync"] = "log-synchronisation",
|
||||||
|
["en-AirScout-Integration"] = "airscout-integration",
|
||||||
|
["en-DX-Cluster-Server"] = "built-in-dx-cluster-server",
|
||||||
|
["en-Changelog"] = "changelog",
|
||||||
|
|
||||||
|
["Installation"] = "installation",
|
||||||
|
["Konfiguration"] = "konfiguration",
|
||||||
|
["Funktionen"] = "funktionen",
|
||||||
|
["Benutzeroberflaeche"] = "benutzeroberflache",
|
||||||
|
["Makros-und-Variablen"] = "makros-und-variablen",
|
||||||
|
["Log-Synchronisation"] = "log-synchronisation",
|
||||||
|
["AirScout-Integration"] = "airscout-integration",
|
||||||
|
["DX-Cluster-Server"] = "integrierter-dx-cluster-server",
|
||||||
|
["Changelog"] = "changelog",
|
||||||
|
|
||||||
|
["Configuration"] = "configuration",
|
||||||
|
["Features"] = "features",
|
||||||
|
["User-Interface"] = "user-interface",
|
||||||
|
["Macros-and-Variables"] = "macros-and-variables",
|
||||||
|
["Log-Sync"] = "log-synchronisation",
|
||||||
|
}
|
||||||
|
|
||||||
|
local function normalize_anchor(text)
|
||||||
|
local s = text:lower()
|
||||||
|
s = s:gsub("%%20", "-")
|
||||||
|
s = s:gsub("ä", "a"):gsub("ö", "o"):gsub("ü", "u"):gsub("ß", "ss")
|
||||||
|
s = s:gsub("[^%w%s%-_]", "")
|
||||||
|
s = s:gsub("[_%s]+", "-")
|
||||||
|
s = s:gsub("%-+", "-")
|
||||||
|
s = s:gsub("^%-", ""):gsub("%-$", "")
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
local function normalize_page_key(page)
|
||||||
|
local key = page:gsub("^%./", ""):gsub("^/", "")
|
||||||
|
key = key:gsub("^github_docs/", "")
|
||||||
|
key = key:gsub("%.md$", "")
|
||||||
|
return key
|
||||||
|
end
|
||||||
|
|
||||||
|
local function resolve_page_anchor(page)
|
||||||
|
local key = normalize_page_key(page)
|
||||||
|
return PAGE_ANCHOR_MAP[key] or normalize_anchor(key)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function convert_url_token(token)
|
||||||
|
local url, trailing = token:match("^(https?://%S-)([%.%,%;%:%!%?]?)$")
|
||||||
|
if not url then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local link = pandoc.Link({pandoc.Str(url)}, url)
|
||||||
|
if trailing ~= "" then
|
||||||
|
return {link, pandoc.Str(trailing)}
|
||||||
|
end
|
||||||
|
return link
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Map of emoji / special Unicode sequences → plain-text replacements.
|
||||||
|
-- Add more entries here as needed.
|
||||||
|
local EMOJI_MAP = {
|
||||||
|
-- Flag sequences
|
||||||
|
["\xF0\x9F\x87\xAC\xF0\x9F\x87\xA7"] = "[EN]", -- 🇬🇧
|
||||||
|
["\xF0\x9F\x87\xA9\xF0\x9F\x87\xAA"] = "[DE]", -- 🇩🇪
|
||||||
|
-- Status symbols
|
||||||
|
["\xE2\x9C\x85"] = "[OK]", -- ✅
|
||||||
|
["\xE2\x9D\x8C"] = "[--]", -- ❌
|
||||||
|
-- Misc symbols used in tables / text
|
||||||
|
["\xF0\x9F\x94\xB4"] = "[red]", -- 🔴
|
||||||
|
["\xF0\x9F\x9F\xA1"] = "[yellow]", -- 🟡
|
||||||
|
["\xF0\x9F\x9F\xA2"] = "[green]", -- 🟢
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Replace emoji in a plain string.
|
||||||
|
local function replace_emoji(text)
|
||||||
|
for pattern, replacement in pairs(EMOJI_MAP) do
|
||||||
|
text = text:gsub(pattern, replacement)
|
||||||
|
end
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Filter: remove language-switch blockquotes from PDF output.
|
||||||
|
-- These blockquotes appear in every wiki page for GitHub navigation
|
||||||
|
-- but are not needed in the printed manual.
|
||||||
|
function BlockQuote(el)
|
||||||
|
local text = pandoc.utils.stringify(el)
|
||||||
|
if text:find("Du liest gerade die deutsche Version") or
|
||||||
|
text:find("You are reading the English version") then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
return el
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Filter: convert internal wiki links to in-PDF anchor links.
|
||||||
|
function Link(el)
|
||||||
|
local target = el.target
|
||||||
|
-- Keep external URLs unchanged.
|
||||||
|
if target:match("^https?://") or target:match("^mailto:") then
|
||||||
|
return el
|
||||||
|
end
|
||||||
|
|
||||||
|
if target:match("^#") then
|
||||||
|
local fragment = target:gsub("^#", "")
|
||||||
|
return pandoc.Link(el.content, "#" .. normalize_anchor(fragment), el.title, el.attr)
|
||||||
|
end
|
||||||
|
|
||||||
|
local page, fragment = target:match("^([^#]+)#(.+)$")
|
||||||
|
if page and fragment then
|
||||||
|
return pandoc.Link(el.content, "#" .. normalize_anchor(fragment), el.title, el.attr)
|
||||||
|
end
|
||||||
|
|
||||||
|
return pandoc.Link(el.content, "#" .. resolve_page_anchor(target), el.title, el.attr)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Filter: replace emoji sequences in plain Str elements.
|
||||||
|
function Str(el)
|
||||||
|
local linkified = convert_url_token(el.text)
|
||||||
|
if linkified then
|
||||||
|
return linkified
|
||||||
|
end
|
||||||
|
|
||||||
|
local replaced = replace_emoji(el.text)
|
||||||
|
if replaced ~= el.text then
|
||||||
|
return pandoc.Str(replaced)
|
||||||
|
end
|
||||||
|
return el
|
||||||
|
end
|
||||||
107
.github/workflows/docs-pdf.yml
vendored
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
name: Build Documentation PDF
|
||||||
|
|
||||||
|
# Runs when documentation changes are pushed to main, or on manual trigger.
|
||||||
|
# Also triggered as a dependency from the tagged-release workflow.
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- github_docs/**
|
||||||
|
- .github/latex-manual/**
|
||||||
|
- .github/workflows/docs-pdf.yml
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-docs-pdf:
|
||||||
|
name: Build Documentation PDF
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4.1.7
|
||||||
|
|
||||||
|
- name: Resolve version string
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
|
||||||
|
VERSION="${{ github.ref_name }}"
|
||||||
|
else
|
||||||
|
VERSION="$(grep -m1 '<version>' pom.xml | sed 's/.*<version>\(.*\)<\/version>.*/\1/')-${GITHUB_SHA::7}"
|
||||||
|
fi
|
||||||
|
echo "DOC_VERSION=$VERSION" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Install pandoc and LaTeX toolchain
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
pandoc \
|
||||||
|
texlive-xetex \
|
||||||
|
texlive-fonts-recommended \
|
||||||
|
texlive-latex-extra \
|
||||||
|
texlive-plain-generic
|
||||||
|
|
||||||
|
- name: Build English PDF manual
|
||||||
|
run: |
|
||||||
|
mkdir -p dist
|
||||||
|
pandoc \
|
||||||
|
--from=markdown-yaml_metadata_block \
|
||||||
|
--template=.github/latex-manual/manual-template.tex \
|
||||||
|
--pdf-engine=xelatex \
|
||||||
|
--lua-filter=.github/latex-manual/strip-wiki-links.lua \
|
||||||
|
--resource-path=.:github_docs \
|
||||||
|
--listings \
|
||||||
|
--toc \
|
||||||
|
--toc-depth=6 \
|
||||||
|
-V title="User Manual" \
|
||||||
|
-V polyglossia-lang=english \
|
||||||
|
-V version="${DOC_VERSION}" \
|
||||||
|
-o dist/KST4Contest-${DOC_VERSION}-manual-en.pdf \
|
||||||
|
github_docs/en-Home.md \
|
||||||
|
github_docs/en-Installation.md \
|
||||||
|
github_docs/en-Configuration.md \
|
||||||
|
github_docs/en-Features.md \
|
||||||
|
github_docs/en-User-Interface.md \
|
||||||
|
github_docs/en-Macros-and-Variables.md \
|
||||||
|
github_docs/en-Log-Sync.md \
|
||||||
|
github_docs/en-AirScout-Integration.md \
|
||||||
|
github_docs/en-DX-Cluster-Server.md \
|
||||||
|
github_docs/en-Changelog.md
|
||||||
|
|
||||||
|
- name: Build German PDF manual
|
||||||
|
run: |
|
||||||
|
pandoc \
|
||||||
|
--from=markdown-yaml_metadata_block \
|
||||||
|
--template=.github/latex-manual/manual-template.tex \
|
||||||
|
--pdf-engine=xelatex \
|
||||||
|
--lua-filter=.github/latex-manual/strip-wiki-links.lua \
|
||||||
|
--resource-path=.:github_docs \
|
||||||
|
--listings \
|
||||||
|
--toc \
|
||||||
|
--toc-depth=6 \
|
||||||
|
-V title="Benutzerhandbuch" \
|
||||||
|
-V polyglossia-lang=german \
|
||||||
|
-V version="${DOC_VERSION}" \
|
||||||
|
-o dist/KST4Contest-${DOC_VERSION}-manual-de.pdf \
|
||||||
|
github_docs/de-Home.md \
|
||||||
|
github_docs/de-Installation.md \
|
||||||
|
github_docs/de-Konfiguration.md \
|
||||||
|
github_docs/de-Funktionen.md \
|
||||||
|
github_docs/de-Benutzeroberflaeche.md \
|
||||||
|
github_docs/de-Makros-und-Variablen.md \
|
||||||
|
github_docs/de-Log-Synchronisation.md \
|
||||||
|
github_docs/de-AirScout-Integration.md \
|
||||||
|
github_docs/de-DX-Cluster-Server.md \
|
||||||
|
github_docs/de-Changelog.md
|
||||||
|
|
||||||
|
- name: Upload PDF artifacts
|
||||||
|
uses: actions/upload-artifact@v4.3.4
|
||||||
|
with:
|
||||||
|
name: docs-pdf
|
||||||
|
path: dist/KST4Contest-*-manual-*.pdf
|
||||||
|
retention-days: 30
|
||||||
67
.github/workflows/nightly-artifacts.yml
vendored
@@ -4,6 +4,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- test-mac
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "20 2 * * *"
|
- cron: "20 2 * * *"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -152,3 +153,69 @@ jobs:
|
|||||||
name: linux-appimage
|
name: linux-appimage
|
||||||
path: dist/praktiKST-*-linux-x86_64.AppImage
|
path: dist/praktiKST-*-linux-x86_64.AppImage
|
||||||
retention-days: 14
|
retention-days: 14
|
||||||
|
|
||||||
|
build-macos-dmg:
|
||||||
|
name: Build macOS DMG (${{ matrix.os }})
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [macos-latest, macos-15-intel]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4.1.7
|
||||||
|
|
||||||
|
- name: Resolve nightly version info
|
||||||
|
run: |
|
||||||
|
VERSION=$(grep -m1 '<version>' pom.xml | sed 's/.*<version>\(.*\)<\/version>.*/\1/')
|
||||||
|
SHORT_SHA="${GITHUB_SHA::7}"
|
||||||
|
ARCH=$(uname -m)
|
||||||
|
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
|
||||||
|
echo "SHORT_SHA=$SHORT_SHA" >> "$GITHUB_ENV"
|
||||||
|
echo "ASSET_BASENAME=praktiKST-${VERSION}-${SHORT_SHA}" >> "$GITHUB_ENV"
|
||||||
|
echo "ARCH=$ARCH" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Set up Java 17
|
||||||
|
uses: actions/setup-java@v4.1.0
|
||||||
|
with:
|
||||||
|
distribution: temurin
|
||||||
|
java-version: "17"
|
||||||
|
|
||||||
|
- name: Ensure mvnw is executable
|
||||||
|
run: chmod +x mvnw
|
||||||
|
|
||||||
|
- name: Build JAR and copy runtime dependencies
|
||||||
|
run: |
|
||||||
|
./mvnw -B -DskipTests package dependency:copy-dependencies -DincludeScope=runtime -DoutputDirectory=target/dist-libs
|
||||||
|
cp "$(ls -t target/praktiKST-*.jar | head -n 1)" target/dist-libs/app.jar
|
||||||
|
|
||||||
|
- name: Build macOS DMG with jpackage
|
||||||
|
run: |
|
||||||
|
mkdir -p dist
|
||||||
|
jpackage \
|
||||||
|
--type dmg \
|
||||||
|
--name praktiKST \
|
||||||
|
--input target/dist-libs \
|
||||||
|
--main-jar app.jar \
|
||||||
|
--main-class kst4contest.view.Kst4ContestApplication \
|
||||||
|
--module-path target/dist-libs \
|
||||||
|
--add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql \
|
||||||
|
--dest dist
|
||||||
|
|
||||||
|
env:
|
||||||
|
MACOSX_DEPLOYMENT_TARGET: "13.0"
|
||||||
|
|
||||||
|
- name: Rename DMG artifact
|
||||||
|
run: |
|
||||||
|
DMG=$(ls dist/*.dmg | head -n 1)
|
||||||
|
if [ -z "$DMG" ]; then
|
||||||
|
echo "No DMG produced by jpackage" && exit 1
|
||||||
|
fi
|
||||||
|
mv "$DMG" "dist/${ASSET_BASENAME}-macos-${ARCH}.dmg"
|
||||||
|
|
||||||
|
- name: Upload macOS artifact
|
||||||
|
uses: actions/upload-artifact@v4.3.4
|
||||||
|
with:
|
||||||
|
name: macos-dmg-${{ matrix.os }}
|
||||||
|
path: dist/praktiKST-*-macos-*.dmg
|
||||||
|
retention-days: 14
|
||||||
|
|||||||
159
.github/workflows/tagged-release.yml
vendored
@@ -134,26 +134,174 @@ jobs:
|
|||||||
name: linux-appimage
|
name: linux-appimage
|
||||||
path: dist/praktiKST-${{ github.ref_name }}-linux-x86_64.AppImage
|
path: dist/praktiKST-${{ github.ref_name }}-linux-x86_64.AppImage
|
||||||
|
|
||||||
|
build-macos-dmg:
|
||||||
|
name: Build macOS DMG (${{ matrix.os }})
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [macos-latest, macos-15-intel]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4.1.7
|
||||||
|
|
||||||
|
- name: Set up Java 17
|
||||||
|
uses: actions/setup-java@v4.1.0
|
||||||
|
with:
|
||||||
|
distribution: temurin
|
||||||
|
java-version: "17"
|
||||||
|
|
||||||
|
- name: Ensure mvnw is executable
|
||||||
|
run: chmod +x mvnw
|
||||||
|
|
||||||
|
- name: Build JAR and copy runtime dependencies
|
||||||
|
run: |
|
||||||
|
./mvnw -B -DskipTests package dependency:copy-dependencies -DincludeScope=runtime -DoutputDirectory=target/dist-libs
|
||||||
|
cp "$(ls -t target/praktiKST-*.jar | head -n 1)" target/dist-libs/app.jar
|
||||||
|
|
||||||
|
- name: Build macOS DMG with jpackage
|
||||||
|
run: |
|
||||||
|
mkdir -p dist
|
||||||
|
jpackage \
|
||||||
|
--type dmg \
|
||||||
|
--name praktiKST \
|
||||||
|
--input target/dist-libs \
|
||||||
|
--main-jar app.jar \
|
||||||
|
--main-class kst4contest.view.Kst4ContestApplication \
|
||||||
|
--module-path target/dist-libs \
|
||||||
|
--add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql \
|
||||||
|
--dest dist
|
||||||
|
|
||||||
|
env:
|
||||||
|
MACOSX_DEPLOYMENT_TARGET: "13.0"
|
||||||
|
|
||||||
|
- name: Rename DMG artifact
|
||||||
|
run: |
|
||||||
|
ARCH=$(uname -m)
|
||||||
|
DMG=$(ls dist/*.dmg | head -n 1)
|
||||||
|
if [ -z "$DMG" ]; then
|
||||||
|
echo "No DMG produced by jpackage" && exit 1
|
||||||
|
fi
|
||||||
|
mv "$DMG" "dist/praktiKST-${{ github.ref_name }}-macos-${ARCH}.dmg"
|
||||||
|
|
||||||
|
- name: Upload macOS artifact
|
||||||
|
uses: actions/upload-artifact@v4.3.4
|
||||||
|
with:
|
||||||
|
name: macos-dmg-${{ matrix.os }}
|
||||||
|
path: dist/praktiKST-${{ github.ref_name }}-macos-*.dmg
|
||||||
|
|
||||||
|
build-docs-pdf:
|
||||||
|
name: Build Documentation PDF
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4.1.7
|
||||||
|
|
||||||
|
- name: Install pandoc and LaTeX toolchain
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y --no-install-recommends \
|
||||||
|
pandoc \
|
||||||
|
texlive-xetex \
|
||||||
|
texlive-fonts-recommended \
|
||||||
|
texlive-latex-extra \
|
||||||
|
texlive-plain-generic
|
||||||
|
|
||||||
|
- name: Build English PDF manual
|
||||||
|
run: |
|
||||||
|
mkdir -p dist
|
||||||
|
pandoc \
|
||||||
|
--from=markdown-yaml_metadata_block \
|
||||||
|
--template=.github/latex-manual/manual-template.tex \
|
||||||
|
--pdf-engine=xelatex \
|
||||||
|
--lua-filter=.github/latex-manual/strip-wiki-links.lua \
|
||||||
|
--resource-path=.:github_docs \
|
||||||
|
--listings \
|
||||||
|
--toc \
|
||||||
|
--toc-depth=3 \
|
||||||
|
-V title="User Manual" \
|
||||||
|
-V polyglossia-lang=english \
|
||||||
|
-V version="${{ github.ref_name }}" \
|
||||||
|
-o dist/KST4Contest-${{ github.ref_name }}-manual-en.pdf \
|
||||||
|
github_docs/en-Home.md \
|
||||||
|
github_docs/en-Installation.md \
|
||||||
|
github_docs/en-Configuration.md \
|
||||||
|
github_docs/en-Features.md \
|
||||||
|
github_docs/en-User-Interface.md \
|
||||||
|
github_docs/en-Macros-and-Variables.md \
|
||||||
|
github_docs/en-Log-Sync.md \
|
||||||
|
github_docs/en-AirScout-Integration.md \
|
||||||
|
github_docs/en-DX-Cluster-Server.md \
|
||||||
|
github_docs/en-Changelog.md
|
||||||
|
|
||||||
|
- name: Build German PDF manual
|
||||||
|
run: |
|
||||||
|
pandoc \
|
||||||
|
--from=markdown-yaml_metadata_block \
|
||||||
|
--template=.github/latex-manual/manual-template.tex \
|
||||||
|
--pdf-engine=xelatex \
|
||||||
|
--lua-filter=.github/latex-manual/strip-wiki-links.lua \
|
||||||
|
--resource-path=.:github_docs \
|
||||||
|
--listings \
|
||||||
|
--toc \
|
||||||
|
--toc-depth=3 \
|
||||||
|
-V title="Benutzerhandbuch" \
|
||||||
|
-V polyglossia-lang=german \
|
||||||
|
-V version="${{ github.ref_name }}" \
|
||||||
|
-o dist/KST4Contest-${{ github.ref_name }}-manual-de.pdf \
|
||||||
|
github_docs/de-Home.md \
|
||||||
|
github_docs/de-Installation.md \
|
||||||
|
github_docs/de-Konfiguration.md \
|
||||||
|
github_docs/de-Funktionen.md \
|
||||||
|
github_docs/de-Benutzeroberflaeche.md \
|
||||||
|
github_docs/de-Makros-und-Variablen.md \
|
||||||
|
github_docs/de-Log-Synchronisation.md \
|
||||||
|
github_docs/de-AirScout-Integration.md \
|
||||||
|
github_docs/de-DX-Cluster-Server.md \
|
||||||
|
github_docs/de-Changelog.md
|
||||||
|
|
||||||
|
- name: Upload PDF artifacts
|
||||||
|
uses: actions/upload-artifact@v4.3.4
|
||||||
|
with:
|
||||||
|
name: docs-pdf
|
||||||
|
path: dist/KST4Contest-${{ github.ref_name }}-manual-*.pdf
|
||||||
|
|
||||||
release-tag:
|
release-tag:
|
||||||
name: Publish Tagged Release
|
name: Publish Tagged Release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs:
|
needs:
|
||||||
- build-windows-zip
|
- build-windows-zip
|
||||||
- build-linux-appimage
|
- build-linux-appimage
|
||||||
|
- build-macos-dmg
|
||||||
|
- build-docs-pdf
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Download Windows artifact
|
- name: Download Windows artifact
|
||||||
uses: actions/download-artifact@v4.1.1
|
uses: actions/download-artifact@v4.1.3
|
||||||
with:
|
with:
|
||||||
name: windows-zip
|
name: windows-zip
|
||||||
path: release-assets/windows
|
path: release-assets/windows
|
||||||
|
|
||||||
- name: Download Linux artifact
|
- name: Download Linux artifact
|
||||||
uses: actions/download-artifact@v4.1.1
|
uses: actions/download-artifact@v4.1.3
|
||||||
with:
|
with:
|
||||||
name: linux-appimage
|
name: linux-appimage
|
||||||
path: release-assets/linux
|
path: release-assets/linux
|
||||||
|
|
||||||
|
- name: Download macOS artifacts
|
||||||
|
uses: actions/download-artifact@v4.1.3
|
||||||
|
with:
|
||||||
|
pattern: macos-dmg-*
|
||||||
|
merge-multiple: true
|
||||||
|
path: release-assets/macos
|
||||||
|
|
||||||
|
- name: Download PDF manuals
|
||||||
|
uses: actions/download-artifact@v4.1.3
|
||||||
|
with:
|
||||||
|
name: docs-pdf
|
||||||
|
path: release-assets/docs
|
||||||
|
|
||||||
- name: Create tagged release
|
- name: Create tagged release
|
||||||
uses: ncipollo/release-action@v1
|
uses: ncipollo/release-action@v1
|
||||||
with:
|
with:
|
||||||
@@ -165,4 +313,9 @@ jobs:
|
|||||||
replacesArtifacts: false
|
replacesArtifacts: false
|
||||||
makeLatest: ${{ !startsWith(github.ref_name, 'beta-') }}
|
makeLatest: ${{ !startsWith(github.ref_name, 'beta-') }}
|
||||||
generateReleaseNotes: true
|
generateReleaseNotes: true
|
||||||
artifacts: release-assets/windows/praktiKST-${{ github.ref_name }}-windows-x64.zip,release-assets/linux/praktiKST-${{ github.ref_name }}-linux-x86_64.AppImage
|
artifacts: >-
|
||||||
|
release-assets/windows/praktiKST-${{ github.ref_name }}-windows-x64.zip,
|
||||||
|
release-assets/linux/praktiKST-${{ github.ref_name }}-linux-x86_64.AppImage,
|
||||||
|
release-assets/macos/praktiKST-${{ github.ref_name }}-macos-*.dmg,
|
||||||
|
release-assets/docs/KST4Contest-${{ github.ref_name }}-manual-en.pdf,
|
||||||
|
release-assets/docs/KST4Contest-${{ github.ref_name }}-manual-de.pdf
|
||||||
|
|||||||
3
.gitignore
vendored
@@ -30,5 +30,8 @@ target/
|
|||||||
#builds
|
#builds
|
||||||
build/
|
build/
|
||||||
|
|
||||||
|
#pdf output directory
|
||||||
|
dist/
|
||||||
|
|
||||||
#zip files for local backups
|
#zip files for local backups
|
||||||
*.zip
|
*.zip
|
||||||
40
README.md
@@ -1,2 +1,38 @@
|
|||||||
# kst4contest
|
# KST4Contest
|
||||||
java based on4kst chatclient
|
|
||||||
|
KST4Contest (also known as pratiKST) is a Java-based chat client for ON4KST, focused on VHF/UHF/SHF contest operation.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
The full user documentation is maintained in the project wiki:
|
||||||
|
|
||||||
|
- https://github.com/praktimarc/kst4contest/wiki
|
||||||
|
|
||||||
|
Direct entry points:
|
||||||
|
|
||||||
|
- German start page: https://github.com/praktimarc/kst4contest/wiki/de-Home
|
||||||
|
- English start page: https://github.com/praktimarc/kst4contest/wiki/en-Home
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Compile locally with Maven Wrapper:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./mvnw -B -DskipTests compile
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Source code is under `src/`.
|
||||||
|
- Documentation markdown pages for wiki/PDF are under `github_docs/`.
|
||||||
|
|
||||||
|
## Status of the latest CI:
|
||||||
|
Wiki Publishing:
|
||||||
|
|
||||||
|
[](https://github.com/praktimarc/kst4contest/actions/workflows/github-wiki.yml)
|
||||||
|
|
||||||
|
[](https://github.com/praktimarc/kst4contest/actions/workflows/docs-pdf.yml)
|
||||||
|
|
||||||
|
Builds:
|
||||||
|
|
||||||
|
[](https://github.com/praktimarc/kst4contest/actions/workflows/nightly-artifacts.yml)
|
||||||
@@ -48,6 +48,6 @@ Entwickelt von **DO5AMF (Marc Fröhlich)**, Operator bei DM5M.
|
|||||||
|
|
||||||
## Schnellinfo / Quick Info
|
## Schnellinfo / Quick Info
|
||||||
|
|
||||||
- **Download**: https://do5amf.funkerportal.de/
|
- **Download**: https://github.com/praktimarc/kst4contest/releases
|
||||||
- **GitHub**: https://github.com/praktimarc/kst4contest
|
- **GitHub**: https://github.com/praktimarc/kst4contest
|
||||||
- **Kontakt / Contact**: praktimarc+kst4contest@gmail.com
|
- **Kontakt / Contact**: praktimarc+kst4contest@gmail.com
|
||||||
|
|||||||
BIN
github_docs/as_plane_feed_1.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
github_docs/as_plane_feed_2.png
Normal file
|
After Width: | Height: | Size: 143 KiB |
BIN
github_docs/as_plane_feed_3.png
Normal file
|
After Width: | Height: | Size: 148 KiB |
BIN
github_docs/as_plane_feed_4.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
github_docs/client_settings_window_logsync.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
github_docs/client_settings_window_station.png
Normal file
|
After Width: | Height: | Size: 109 KiB |
@@ -32,6 +32,10 @@ Für diesen Dienst ist ein Account erforderlich. Bitte eine Spende für Thomas i
|
|||||||
|
|
||||||
1. AirScout starten.
|
1. AirScout starten.
|
||||||
2. In den AirScout-Einstellungen den OV3T-Feed-Account eintragen (Benutzername, Passwort, URL).
|
2. In den AirScout-Einstellungen den OV3T-Feed-Account eintragen (Benutzername, Passwort, URL).
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
3. Verbindung testen.
|
3. Verbindung testen.
|
||||||
|
|
||||||
### Schritt 2: UDP-Kommunikation für KST4Contest aktivieren
|
### Schritt 2: UDP-Kommunikation für KST4Contest aktivieren
|
||||||
@@ -47,6 +51,10 @@ In den KST4Contest-Preferences → **AirScout Settings**:
|
|||||||
- AirScout-Kommunikation aktivieren
|
- AirScout-Kommunikation aktivieren
|
||||||
- IP und Port auf Standardwerte lassen (sofern nicht geändert)
|
- IP und Port auf Standardwerte lassen (sofern nicht geändert)
|
||||||
|
|
||||||
|
{ width=85% }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Kommunikation zwischen KST4Contest und AirScout (ab v1.263)
|
## Kommunikation zwischen KST4Contest und AirScout (ab v1.263)
|
||||||
|
|||||||
@@ -6,6 +6,85 @@ Versionsverlauf von KST4Contest / PraktiKST.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
letzter Changelog bitte aus GitHub entnehmen. Der bisherige Changelog
|
||||||
|
|
||||||
|
## v1.40 (2026-02-16)
|
||||||
|
**Großes Feature-Release: Score-System, AP-Timeline, Win-Test, PSTRotator**
|
||||||
|
|
||||||
|
**Neu:**
|
||||||
|
- **Chatmember Score-System**: Jeder Chatmember erhält automatisch eine Prioritätsbewertung anhand von Antennenrichtung, Aktivitätszeit, Nachrichtenanzahl, aktiven Bändern, Frequenzen, Sked-Richtung und anderen Faktoren. Die Top-Kandidaten werden in einer eigenen Liste hervorgehoben.
|
||||||
|
- **AP-Timeline**: Für jeden möglichen AP-Ankunftsminuten-Slot werden bis zu 4 hochbewertete Stationen angezeigt, die erreichbar wären. Bevorzugt werden APs mit dem höchsten Potenzial, nicht die schnellste Ankunft. Stationen, auf die die eigene Antenne nicht zeigt, werden transparent dargestellt.
|
||||||
|
- **Win-Test-Unterstützung** (ab v1.31 als Beta, jetzt vollständig konfigurierbar): Log-Synchronisation, Frequenzauswertung und **Sked-Übergabe via UDP** vollständig integriert. In den Preferences aktivier-/deaktivierbar.
|
||||||
|
- **PSTRotator-Interface** (ab v1.31 als Beta, jetzt vollständig konfigurierbar): Aktualisierung der Rotatorposition direkt aus KST4Contest. In den Preferences aktivier-/deaktivierbar.
|
||||||
|
- **QSO-Sniffer**: Nachrichten von konfigurierbaren Rufzeichen-Listen werden automatisch in das PM-Fenster weitergeleitet.
|
||||||
|
- **Band-Alert bei gearbeiteten Stationen**: Wenn eine Station geloggt wird, erscheint ein Hinweis, wenn diese Station ein weiteres Band aktiv hat, auf dem man selbst ebenfalls QRV ist.
|
||||||
|
- **Sked-Erinnerungs-ALERT**: Pro Chatmember kann ein Sked-Alarm mit automatischen Nachrichten in konfigurierbaren Intervallen (2+1 / 5+2+1 / 10+5+2+1 Minuten vor dem Sked) eingerichtet werden, plus akustische und optische Benachrichtigung.
|
||||||
|
- **Chat-Historie beim Start laden**: Beim Verbindungsaufbau wird die Serverhistorie geladen, um aktive Chatmember und letzte Nachrichten sofort sichtbar zu machen.
|
||||||
|
- **Skedfail-Button**: Im FurtherInfo-Panel kann ein Sked-Misserfolg für einen Chatmember markiert werden, was dessen Score senkt.
|
||||||
|
|
||||||
|
**Geändert:**
|
||||||
|
- AP-Notizen in DX-Cluster-Spots integriert.
|
||||||
|
- Scrolling der Chatmember-Tabelle folgt automatisch der aktuellen Nachrichtenauswahl.
|
||||||
|
- Generic Auto-Antwort und QRG-Auto-Antwort senden max. einmal pro 45 Sekunden pro Rufzeichen (verhindert Spam-Schleifen).
|
||||||
|
- Speicherbare Einstellungen erweitert: ServerDNS/Port, PSTRotator-Interface, Win-Test-Interface, Callsign-Sniffer, Dark-Mode-Standard.
|
||||||
|
- Datum in der Chat-Tabelle entfernt (nur Uhrzeit verbleibt – spart Platz).
|
||||||
|
|
||||||
|
**Behoben:**
|
||||||
|
- Benutzerliste wird jetzt bei jedem Neu-Login automatisch sortiert.
|
||||||
|
- Posonpill-Nachrichten beenden jetzt nur genau eine Client-Instanz (nicht alle und nicht wtKST).
|
||||||
|
- wtKST: Absturz bei KST4Contest-Trennung behoben.
|
||||||
|
- Mehrere Probleme mit Rufzeichen-Suffixen wie `/p`, `-2` etc. behoben.
|
||||||
|
- `QTFDefault` wurde nicht korrekt gespeichert → behoben.
|
||||||
|
- AirScout-Watchlist (ASWATCHLIST) wurde nicht korrekt aktualisiert → behoben.
|
||||||
|
- Dark Mode: QRG-Felder wurden nicht vollständig angezeigt → behoben.
|
||||||
|
- Versionsnummer-Anzeige korrigiert.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v1.31 (2025-12-13)
|
||||||
|
**Win-Test + PSTRotator Beta, QSO-Sniffer, DNS-Hotfix**
|
||||||
|
|
||||||
|
**Neu:**
|
||||||
|
- **Win-Test-Unterstützung** (Beta, noch nicht deaktivierbar): Log-Synchronisation und Frequenzauswertung.
|
||||||
|
- **PSTRotator-Unterstützung** (Beta, noch nicht deaktivierbar).
|
||||||
|
- **QSO-Sniffer**: Nachrichten von konfigurierbaren Rufzeichen werden ins PM-Fenster weitergeleitet.
|
||||||
|
|
||||||
|
**Geändert:**
|
||||||
|
- **DNS-Server geändert**: Von `www.on4kst.info` auf `www.on4kst.org` (Hotfix). Der DNS-Server ist ab sofort in den Preferences änderbar.
|
||||||
|
|
||||||
|
**Behoben:**
|
||||||
|
- Endlosschleife im Fehlerfall friert den Client ein → behoben.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v1.266 (2025-10-03)
|
||||||
|
**AirScout-Fix für Rufzeichen mit Suffix**
|
||||||
|
|
||||||
|
**Behoben:**
|
||||||
|
- AirScout-Interface funktionierte nicht, wenn das Login-Rufzeichen einen Suffix enthielt (z. B. `9A1W-2`). AirScout kann mit diesem Format nicht umgehen – es wird jetzt nur noch das Basis-Rufzeichen ohne Suffix an AirScout übergeben.
|
||||||
|
|
||||||
|
*(Fehler gemeldet und getestet von 9A2HM / Kreso – herzlichen Dank!)*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v1.265 (2025-09-28)
|
||||||
|
**Richtungs-Buttons bleiben aktiviert eingefärbt**
|
||||||
|
|
||||||
|
**Behoben:**
|
||||||
|
- Richtungs-Buttons (N / NE / E usw.) behalten jetzt ihre Farbe, wenn sie aktiviert sind, sodass der Aktivierungsstatus auf einen Blick erkennbar ist.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v1.264 (2025-08-02)
|
||||||
|
**Simplelogfile: Rufzeichen-Erkennung verbessert**
|
||||||
|
|
||||||
|
**Behoben:**
|
||||||
|
- Rufzeichen wie `S53CC`, `S51A` usw. wurden in der SimpleLogFile-Auswertung nicht als gearbeitet markiert → Erkennungsmuster verbessert.
|
||||||
|
|
||||||
|
*(Fehler gemeldet von Boris, S53CC – danke!)*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## v1.263 (2025-06-08)
|
## v1.263 (2025-06-08)
|
||||||
**AirScout-Kommunikation und Login-Name**
|
**AirScout-Kommunikation und Login-Name**
|
||||||
|
|
||||||
@@ -151,6 +230,6 @@ Erste öffentlich veröffentlichte Version. Grundfunktionen:
|
|||||||
## Geplante Features
|
## Geplante Features
|
||||||
|
|
||||||
- `MYQTF`-Variable (eigene Antennenrichtung als Text)
|
- `MYQTF`-Variable (eigene Antennenrichtung als Text)
|
||||||
- Lebensdauer für den Worked-Status (automatisches Zurücksetzen)
|
- ~~Lebensdauer für den Worked-Status (automatisches Zurücksetzen)~~ ✅ **Umgesetzt in v1.40** (3-Tage-Lebensdauer, kein manuelles Zurücksetzen mehr nötig)
|
||||||
- Filterung des „Cluster & QSO der anderen"-Fensters auf eigenes QTF
|
- Filterung des „Cluster & QSO der anderen"-Fensters auf eigenes QTF
|
||||||
- Weitere Topografie-basierte Berechnungen für die Richtungswarnung
|
- Weitere Topografie-basierte Berechnungen für die Richtungswarnung
|
||||||
|
|||||||
@@ -135,22 +135,86 @@ Für ausgewählte Stationen in der Benutzerliste gibt es direkte Buttons, um das
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Sked-Erinnerungen (Sked Reminder Service)
|
## Sked-Erinnerungen mit ALERT (ab v1.40)
|
||||||
|
|
||||||
Für vereinbarte Skeds können automatische Erinnerungs-PMs konfiguriert werden, die X Minuten vor dem vereinbarten Zeitpunkt gesendet werden. Die Erinnerungen werden aus dem FurtherInfo-Panel heraus aktiviert.
|
Für jeden Chatmember kann ein Sked-Erinnerungsdienst mit automatischen Nachrichten aktiviert werden. Konfigurierbare Intervallmuster:
|
||||||
|
|
||||||
|
- **2+1 Minuten**: Nachrichten bei 2 min und 1 min vor dem Sked.
|
||||||
|
- **5+2+1 Minuten**: Nachrichten bei 5, 2 und 1 min vor dem Sked.
|
||||||
|
- **10+5+2+1 Minuten**: Nachrichten bei 10, 5, 2 und 1 min vor dem Sked.
|
||||||
|
|
||||||
|
Zusätzlich zu den Nachrichten an die Gegenstation gibt es eine **akustische und optische Benachrichtigung** für den eigenen Operator, sodass kein Sked vergessen wird.
|
||||||
|
|
||||||
|
Aktivierung: FurtherInfo-Panel der entsprechenden Station.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Prioritätsliste / Score-Service
|
## QSO-Sniffer (ab v1.31)
|
||||||
|
|
||||||
KST4Contest berechnet automatisch eine **Prioritätsliste** der interessantesten Gesprächspartner, basierend auf:
|
Der QSO-Sniffer überwacht den Chat auf Nachrichten von einer konfigurierbaren Rufzeichen-Liste und leitet diese automatisch in das **PM-Fenster** weiter. So gehen keine relevanten Nachrichten im allgemeinen Chat-Rauschen unter.
|
||||||
|
|
||||||
- Richtungserkennung
|
Konfiguration: [Konfiguration – Sniffer-Einstellungen](de-Konfiguration#sniffer-einstellungen-ab-v131)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Win-Test-Integration (ab v1.31, vollständig ab v1.40)
|
||||||
|
|
||||||
|
KST4Contest unterstützt [Win-Test](https://www.win-test.com/) vollständig als Logprogramm:
|
||||||
|
|
||||||
|
- **Log-Synchronisation**: Gearbeitete Stationen werden automatisch aus Win-Test übernommen und in der Benutzerliste markiert.
|
||||||
|
- **Frequenz-Auswertung**: Die aktuelle TRX-Frequenz wird aus Win-Test-UDP-Paketen ausgewertet und befüllt die `MYQRG`-Variable.
|
||||||
|
- **Sked-Übergabe (SKED Push via UDP)**: Vereinbarte Skeds aus KST4Contest können direkt an Win-Test übertragen werden, sodass das Rufzeichen der Gegenstation im Win-Test-Sked-Fenster erscheint.
|
||||||
|
|
||||||
|
Details zur Konfiguration: [Konfiguration – Win-Test-Netzwerk-Listener](de-Konfiguration#win-test-netzwerk-listener)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PSTRotator-Interface (ab v1.31, vollständig ab v1.40)
|
||||||
|
|
||||||
|
KST4Contest kann die Antennenrichtung direkt über **PSTRotator** steuern. Wenn in der Benutzerliste eine Station ausgewählt wird, kann der Rotator automatisch auf den QTF zur ausgewählten Station gedreht werden.
|
||||||
|
|
||||||
|
Konfiguration: [Konfiguration – PSTRotator-Einstellungen](de-Konfiguration#pstrotator-einstellungen-ab-v131)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Band-Alert bei neuen QSOs (ab v1.40)
|
||||||
|
|
||||||
|
Wenn eine Station geloggt wird, prüft KST4Contest automatisch, ob diese Station im Chat weitere aktive Bänder angezeigt hat, auf denen man selbst ebenfalls QRV ist. Falls ja, erscheint ein **Hinweis-Alert**, damit keine Multi-Band-Möglichkeit übersehen wird.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Worked-Tag-Lebensdauer (ab v1.40)
|
||||||
|
|
||||||
|
Gearbeitete Stationen werden nach **3 Tagen** automatisch aus der Datenbank entfernt. Ein manuelles Zurücksetzen der Worked-Datenbank vor jedem Contest ist damit nicht mehr zwingend notwendig – die Datenbank hält sich selbst aktuell.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Chatmember Score-System / Prioritätsliste (ab v1.40)
|
||||||
|
|
||||||
|
KST4Contest berechnet automatisch eine **Prioritätsbewertung** für jeden aktiven Chatmember. Der Score setzt sich zusammen aus:
|
||||||
|
|
||||||
|
- Antennenrichtung der Gegenstation (zeigt sie auf mich?)
|
||||||
- QRB (Entfernung)
|
- QRB (Entfernung)
|
||||||
|
- Aktivitätszeit und Nachrichtenanzahl
|
||||||
|
- Aktive Bänder und Frequenzen
|
||||||
- AP-Verfügbarkeit (AirScout)
|
- AP-Verfügbarkeit (AirScout)
|
||||||
- Worked-Status
|
- Sked-Richtung
|
||||||
|
- Sked-Erfolgsrate und Skedfail-Markierungen
|
||||||
|
|
||||||
Die Top-Kandidaten werden in einer eigenen Liste angezeigt und helfen, im Contest-Stress die wichtigsten Stationen nicht zu übersehen.
|
Die Top-Kandidaten werden in einer eigenen Prioritätsliste hervorgehoben und helfen, im Contest-Stress die wichtigsten Stationen nicht zu übersehen.
|
||||||
|
|
||||||
|
Stationen, bei denen ein Sked gescheitert ist, können über den **Skedfail-Button** im FurtherInfo-Panel markiert werden – das senkt ihren Score vorübergehend.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AP-Timeline (ab v1.40)
|
||||||
|
|
||||||
|
Eine visuelle Zeitleiste zeigt für jeden möglichen AP-Ankunftsminuten-Slot bis zu 4 hochbewertete Stationen, die per Aircraft Scatter erreichbar wären. Priorisierungskriterien:
|
||||||
|
|
||||||
|
- Bevorzugt werden APs mit dem **höchsten Reflexionspotenzial** (nicht unbedingt die schnellste Ankunft).
|
||||||
|
- Stationen, auf die die eigene Antenne nicht zeigt, werden **transparent** dargestellt.
|
||||||
|
|
||||||
|
So kann der Contest-Operator auf einem Blick sehen, welche Stationen wann und über welche Flugzeuge erreichbar sein werden.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ Der ON4KST-Chat ist der De-facto-Standard für Skeds auf den 144-MHz-und-höher-
|
|||||||
|
|
||||||
- **E-Mail**: praktimarc+kst4contest@gmail.com *(nur für kst4contest-Themen)*
|
- **E-Mail**: praktimarc+kst4contest@gmail.com *(nur für kst4contest-Themen)*
|
||||||
- **GitHub**: https://github.com/praktimarc/kst4contest
|
- **GitHub**: https://github.com/praktimarc/kst4contest
|
||||||
- **Download**: https://do5amf.funkerportal.de/
|
- **Download**: https://github.com/praktimarc/kst4contest/releases/latest
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,7 @@
|
|||||||
|
|
||||||
## Voraussetzungen
|
## Voraussetzungen
|
||||||
|
|
||||||
### Java
|
Es wird eine Mindestauflösung von 1200px mal 720px empfohlen
|
||||||
|
|
||||||
KST4Contest ist eine Java-Anwendung. Es wird eine aktuelle **Java Runtime Environment (JRE)** benötigt. Die empfohlene Version ist Java 17 oder höher.
|
|
||||||
|
|
||||||
### ON4KST-Account
|
### ON4KST-Account
|
||||||
|
|
||||||
@@ -34,21 +32,42 @@ Bei starkem Chat-Verkehr (5–6 Nachrichten pro Sekunde im Contest) gehen öffen
|
|||||||
|
|
||||||
## Download
|
## Download
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
Die aktuelle Version kann als ZIP-Datei heruntergeladen werden:
|
Die aktuelle Version kann als ZIP-Datei heruntergeladen werden:
|
||||||
|
|
||||||
**https://do5amf.funkerportal.de/**
|
**https://github.com/praktimarc/kst4contest/releases/latest**
|
||||||
|
|
||||||
|
Der Dateiname hat das Format `praktiKST-v<Versionsnummer>-windows-x64.zip `.
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
Die aktuelle Version kann als AppImage heruntergeladen werden:
|
||||||
|
|
||||||
|
**https://github.com/praktimarc/kst4contest/releases/latest**
|
||||||
|
|
||||||
|
Der Dateiname hat das Format `praktiKST-v<Versionsnummer>-linux-x86_64.AppImage`.
|
||||||
|
|
||||||
Der Dateiname hat das Format `kst4Contest_v<Versionsnummer>.zip`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
1. ZIP-Datei herunterladen.
|
1. ZIP-Datei herunterladen.
|
||||||
2. ZIP-Datei in einen gewünschten Ordner entpacken.
|
2. ZIP-Datei in einen gewünschten Ordner entpacken.
|
||||||
3. `praktiKST.exe` (Windows) bzw. das entsprechende Start-Skript ausführen.
|
3. `praktiKST.exe` ausführen.
|
||||||
|
|
||||||
Die Einstellungen werden unter `%USERPROFILE%\.praktikst\preferences.xml` (Windows) gespeichert.
|
Die Einstellungen werden unter `%USERPROFILE%\.praktikst\preferences.xml` gespeichert.
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
1. AppImage herunterladen.
|
||||||
|
2. AppImage in gewünschten Ordner entpacken.
|
||||||
|
3. AppImage ausführbar machen (geht im Terminal mit `chmod +x praktiKST-v<Versionsnummer>-linux-x86_64.AppImage`)
|
||||||
|
4. AppImage ausführen.
|
||||||
|
|
||||||
|
Die Einstellungen werden unter `~/.praktikst/preferences.xml` gespeichert.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -59,8 +78,12 @@ KST4Contest enthält einen **automatischen Update-Hinweis-Dienst**: Sobald eine
|
|||||||
- einem Changelog,
|
- einem Changelog,
|
||||||
- dem Download-Link zur neuen Version.
|
- dem Download-Link zur neuen Version.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
### Update-Prozess
|
### Update-Prozess
|
||||||
|
|
||||||
|
#### Windows
|
||||||
|
|
||||||
Derzeit gibt es nur einen Weg zum Aktualisieren:
|
Derzeit gibt es nur einen Weg zum Aktualisieren:
|
||||||
|
|
||||||
1. Den alten Ordner löschen.
|
1. Den alten Ordner löschen.
|
||||||
@@ -68,6 +91,14 @@ Derzeit gibt es nur einen Weg zum Aktualisieren:
|
|||||||
|
|
||||||
Die Einstellungsdatei (`preferences.xml`) bleibt erhalten, da sie im Benutzerordner gespeichert ist – nicht im Programmordner.
|
Die Einstellungsdatei (`preferences.xml`) bleibt erhalten, da sie im Benutzerordner gespeichert ist – nicht im Programmordner.
|
||||||
|
|
||||||
|
#### Linux
|
||||||
|
|
||||||
|
Derzeit folgendermaßen:
|
||||||
|
1. neues AppImage herunterladen
|
||||||
|
2. neues AppImage ausführbar makieren
|
||||||
|
3. (optional) altes AppImage löschen.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Bekannte Probleme beim Start
|
## Bekannte Probleme beim Start
|
||||||
|
|||||||
@@ -4,12 +4,21 @@
|
|||||||
|
|
||||||
Nach dem ersten Start öffnet sich das **Einstellungsfenster** – dieses ist der zentrale Ausgangspunkt für alle Konfigurationen. Es empfiehlt sich, das Einstellungsfenster während des Betriebs geöffnet zu lassen (z. B. um den Beacon schnell ein- und auszuschalten).
|
Nach dem ersten Start öffnet sich das **Einstellungsfenster** – dieses ist der zentrale Ausgangspunkt für alle Konfigurationen. Es empfiehlt sich, das Einstellungsfenster während des Betriebs geöffnet zu lassen (z. B. um den Beacon schnell ein- und auszuschalten).
|
||||||
|
|
||||||
> **Wichtig**: Nach jeder Änderung unbedingt **„Save Settings"** klicken! Die Einstellungen werden in `~/.praktikst/preferences.xml` gespeichert. Ab v1.21 werden auch Fenstergrößen und Divider-Positionen beim Speichern gesichert.
|
> **Wichtig**: Nach jeder Änderung unbedingt **„Save Settings"** klicken! Die Einstellungen werden unter Linux in `~/.praktikst/preferences.xml` und unter Windows in `%USERPROFILE%\.praktikst\preferences.xml` (bzw. `C:\Users\<Benutzername>\.praktikst\preferences.xml`) gespeichert. Ab v1.21 werden auch Fenstergrößen und Divider-Positionen beim Speichern gesichert.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Station Settings (Stationseinstellungen)
|
## Station Settings (Stationseinstellungen)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Login und Chat-Kategorien
|
||||||
|
|
||||||
|
Hier werden die Zugangsdaten für den ON4KST-Chat eingetragen (Rufzeichen und Passwort).
|
||||||
|
Zudem wird die **primäre Chat-Kategorie** (z. B. IARU Region 1 VHF/Microwave) ausgewählt.
|
||||||
|
|
||||||
|
Mit der Option für einen **zweiten Chat** (Multi-Channel-Login) kann man sich gleichzeitig in eine weitere Kategorie (z. B. UHF/SHF) einloggen. Beide Chats werden dann parallel überwacht. Hier kann optional auch ein abweichender Login-Name für den zweiten Chat vergeben werden (nützlich für Opposite Station Multi-Callsign Logging).
|
||||||
|
|
||||||
### Rufzeichen und Locator
|
### Rufzeichen und Locator
|
||||||
|
|
||||||
Eigenes Rufzeichen und Maidenhead-Locator (6-stellig, z. B. `JN49IJ`) eintragen. Diese Werte werden für Distanz- und Richtungsberechnungen benötigt.
|
Eigenes Rufzeichen und Maidenhead-Locator (6-stellig, z. B. `JN49IJ`) eintragen. Diese Werte werden für Distanz- und Richtungsberechnungen benötigt.
|
||||||
@@ -30,9 +39,20 @@ Maximale Entfernung (in km), für die Richtungs-Warnungen ausgelöst werden soll
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Server-Einstellungen (ab v1.31)
|
||||||
|
|
||||||
|
Der Chat-Server-DNS und -Port sind in den Preferences konfigurierbar:
|
||||||
|
|
||||||
|
- **Server-DNS**: Standard `www.on4kst.org` (ab v1.31 geändert von `www.on4kst.info`).
|
||||||
|
- **Port**: Standardport des ON4KST-Servers.
|
||||||
|
|
||||||
|
Eine Änderung ist nur notwendig, wenn der Server umzieht oder ein alternativer Endpunkt genutzt wird.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Log-Sync-Einstellungen
|
## Log-Sync-Einstellungen
|
||||||
|
|
||||||
Zwei Methoden stehen zur Verfügung, um gearbeitete Stationen automatisch zu markieren. Details: [Log-Synchronisation](de-Log-Synchronisation).
|
Drei Methoden stehen zur Verfügung, um gearbeitete Stationen automatisch zu markieren. Details: [Log-Synchronisation](de-Log-Synchronisation).
|
||||||
|
|
||||||
### Universal File Based Callsign Interpreter (Simplelogfile)
|
### Universal File Based Callsign Interpreter (Simplelogfile)
|
||||||
|
|
||||||
@@ -40,7 +60,11 @@ Interpretiert beliebige Log-Dateien per Regex nach Rufzeichen-Mustern. Keine Ban
|
|||||||
|
|
||||||
### Netzwerk-Listener für QSO-UDP-Broadcast
|
### Netzwerk-Listener für QSO-UDP-Broadcast
|
||||||
|
|
||||||
**Empfohlene Methode.** KST4Contest hört auf UDP-Pakete, die das Logprogramm beim Speichern eines QSOs an die Broadcast-Adresse sendet. Die Stationen werden mit Bandinformation markiert. UDP-Port: Standard **12060**.
|
**Empfohlene Methode.** KST4Contest hört auf UDP-Pakete, die das Logprogramm beim Speichern eines QSOs an die Broadcast-Adresse sendet. Die Stationen werden mit Bandinformation markiert. UDP-Port: Standard **12060**. (Wird z. B. von UCXLog, N1MM+, QARTest, DXLog.net genutzt).
|
||||||
|
|
||||||
|
### Win-Test Network-Listener (Zusätzlicher UDP-Listener)
|
||||||
|
|
||||||
|
Dedizierter Netzwerk-Erkenner für Win-Test. KST4Contest empfängt und verarbeitet Win-Test-spezifische UDP-Pakete (inkl. Sked-Übergabe) auf dem dafür konfigurierten Port.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -109,14 +133,55 @@ Neuer Einstellungsbereich mit folgenden Optionen:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Win-Test-Netzwerk-Listener (ab v1.31)
|
||||||
|
|
||||||
|
Dedizierter Empfänger für Win-Test-spezifische UDP-Pakete. Ermöglicht:
|
||||||
|
|
||||||
|
- **Log-Synchronisation**: Gearbeitete Stationen werden aus Win-Test übernommen und in der Benutzerliste markiert.
|
||||||
|
- **Frequenz-Auswertung**: Die aktuelle TRX-Frequenz aus Win-Test befüllt die `MYQRG`-Variable.
|
||||||
|
- **Sked-Übergabe (SKED Push)**: Skeds aus KST4Contest werden via UDP direkt an Win-Test übergeben. Der UDP-Broadcast-Standardport von Win-Test (9871) wird verwendet.
|
||||||
|
|
||||||
|
Einstellungen:
|
||||||
|
- **Aktivieren/Deaktivieren**: Checkbox in den Preferences (ab v1.40).
|
||||||
|
- **Port**: Konfigurierbarer UDP-Port für den Win-Test-Listener.
|
||||||
|
- **Sked-UDP-Adresse und Port**: Zieladresse und Port für die SKED-Übergabe an Win-Test.
|
||||||
|
|
||||||
|
> **Hinweis**: Der Win-Test-Listener ist ein **zusätzlicher** Listener – der Standard-QSO-UDP-Broadcast-Listener auf Port 12060 bleibt davon unabhängig.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PSTRotator-Einstellungen (ab v1.31)
|
||||||
|
|
||||||
|
KST4Contest kann die Antennenrichtung über PSTRotator steuern.
|
||||||
|
|
||||||
|
Einstellungen:
|
||||||
|
- **Aktivieren/Deaktivieren**: Checkbox in den Preferences (ab v1.40).
|
||||||
|
- **IP-Adresse**: IP-Adresse des PSTRotator-Rechners (Standard: `127.0.0.1` bei Betrieb auf demselben PC).
|
||||||
|
- **Port**: Kommunikationsport von PSTRotator.
|
||||||
|
|
||||||
|
> **Hinweis**: Nach einem Klick auf den Richtungs-Button wartet KST4Contest kurz auf die Rotatorantwort. Bei langsamen Rotoren (z. B. SPID) kann es zu einer kleinen Verzögerung kommen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sniffer-Einstellungen (ab v1.31)
|
||||||
|
|
||||||
|
Der QSO-Sniffer filtert Chat-Nachrichten von konfigurierbaren Rufzeichen und leitet sie ins PM-Fenster weiter.
|
||||||
|
|
||||||
|
Einstellungen:
|
||||||
|
- **Rufzeichen-Liste**: Kommagetrennte Liste von Rufzeichen, deren Nachrichten immer in das PM-Fenster weitergeleitet werden sollen.
|
||||||
|
|
||||||
|
Anwendungsfall: Wichtige Stationen (z. B. DX-Peditionen oder feste Verbündete im Contest) im Auge behalten, ohne den Haupt-Chat ständig zu beobachten.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Worked Station Database Settings (Gearbeitete-Stationen-Datenbank)
|
## Worked Station Database Settings (Gearbeitete-Stationen-Datenbank)
|
||||||
|
|
||||||
Vor jedem Contest die interne Worked-Datenbank zurücksetzen! Enthält:
|
Die interne Worked-Datenbank enthält:
|
||||||
|
|
||||||
- Worked-Status aller Stationen (pro Band)
|
- Worked-Status aller Stationen (pro Band)
|
||||||
- NOT-QRV-Tags (seit v1.2)
|
- NOT-QRV-Tags (seit v1.2)
|
||||||
|
|
||||||
Schaltfläche **„Reinitialize"** unter der Tabelle verwenden. Eine geplante Funktion ist eine automatische Ablaufzeit für den Worked-Status.
|
**Ab v1.40**: Einträge haben eine automatische Lebensdauer von **3 Tagen** – ein manuelles Zurücksetzen vor jedem Contest ist nicht mehr zwingend notwendig. Für ein vollständiges Reset kann trotzdem die Schaltfläche **„Reinitialize"** verwendet werden.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -130,6 +195,6 @@ Umschaltbar über das Menü: **Window → Use Dark Mode**. Die Farben können ü
|
|||||||
|
|
||||||
Nach **jeder** Änderung **„Save Settings"** klicken! Ohne Speichern gehen alle Änderungen beim nächsten Start verloren.
|
Nach **jeder** Änderung **„Save Settings"** klicken! Ohne Speichern gehen alle Änderungen beim nächsten Start verloren.
|
||||||
|
|
||||||
- Speicherort: `~/.praktikst/preferences.xml`
|
- Speicherort: unter Linux `~/.praktikst/preferences.xml` und unter Windows `%USERPROFILE%\.praktikst\preferences.xml` (bzw. `C:\Users\<Benutzername>\.praktikst\preferences.xml`)
|
||||||
- Ab v1.21: Fenstergrößen und Divider-Positionen werden ebenfalls gespeichert.
|
- Ab v1.21: Fenstergrößen und Divider-Positionen werden ebenfalls gespeichert.
|
||||||
- Bei Problemen: Konfigurationsdatei löschen → KST4Contest erstellt eine neue mit Standardwerten.
|
- Bei Problemen: Konfigurationsdatei löschen → KST4Contest erstellt eine neue mit Standardwerten.
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ KST4Contest markiert gearbeitete Stationen automatisch in der Chat-Benutzerliste
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Methode 1: Universal File Based Callsign Interpreter (Simplelogfile)
|
## Methode 1: Universal File Based Callsign Interpreter (Simplelogfile)
|
||||||
|
|
||||||
KST4Contest liest eine Log-Datei und sucht mittels regulärem Ausdruck nach Rufzeichen-Mustern. Dabei werden auch binäre Logdateien unterstützt – unlesbarer Binärinhalt wird einfach ignoriert.
|
KST4Contest liest eine Log-Datei und sucht mittels regulärem Ausdruck nach Rufzeichen-Mustern. Dabei werden auch binäre Logdateien unterstützt – unlesbarer Binärinhalt wird einfach ignoriert.
|
||||||
@@ -33,6 +35,8 @@ Das Logprogramm sendet beim Speichern eines QSOs ein UDP-Paket an die Broadcast-
|
|||||||
|
|
||||||
### UCXLog (DL7UCX)
|
### UCXLog (DL7UCX)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
UCXLog sendet QSO-UDP-Pakete und Transceiver-Frequenzpakete.
|
UCXLog sendet QSO-UDP-Pakete und Transceiver-Frequenzpakete.
|
||||||
|
|
||||||
**Einstellungen in UCXLog:**
|
**Einstellungen in UCXLog:**
|
||||||
@@ -46,6 +50,8 @@ Hinweis für Multi-Setup (2 Computer, 2 Radios, eine KST4Contest-Instanz): Beide
|
|||||||
|
|
||||||
### QARTest (IK3QAR)
|
### QARTest (IK3QAR)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
**Besonderheit**: QARTest kann das **vollständige Log** an KST4Contest senden (Schaltfläche „Invia log completo" in den QARTest-Einstellungen). Damit werden auch QSOs erfasst, die vor dem Start von KST4Contest geloggt wurden.
|
**Besonderheit**: QARTest kann das **vollständige Log** an KST4Contest senden (Schaltfläche „Invia log completo" in den QARTest-Einstellungen). Damit werden auch QSOs erfasst, die vor dem Start von KST4Contest geloggt wurden.
|
||||||
|
|
||||||
**Einstellungen in QARTest:**
|
**Einstellungen in QARTest:**
|
||||||
@@ -68,14 +74,33 @@ Für den integrierten DX-Cluster-Server: N1MM+ als DX-Cluster-Client konfigurier
|
|||||||
|
|
||||||
### DXLog.net
|
### DXLog.net
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
**Einstellungen in DXLog.net:**
|
**Einstellungen in DXLog.net:**
|
||||||
- UDP-Broadcast aktivieren
|
- UDP-Broadcast aktivieren
|
||||||
- IP des KST4Contest-Computers eintragen (grün markierte Felder)
|
- IP des KST4Contest-Computers eintragen (grün markierte Felder)
|
||||||
- Port: 12060
|
- Port: 12060
|
||||||
|
|
||||||
### WinTest
|
### Win-Test
|
||||||
|
|
||||||
WinTest wird ebenfalls unterstützt. KST4Contest empfängt WinTest-UDP-Pakete über einen dedizierten Listener. Die Konfiguration erfolgt analog zu den anderen Programmen.
|
Win-Test wird mit einem dedizierten UDP-Netzwerk-Listener unterstützt, der das native Win-Test Netzwerkprotokoll versteht.
|
||||||
|
|
||||||
|
**Vorteile der Win-Test Integration:**
|
||||||
|
- Automatische QSO-Synchronisation zur Markierung gearbeiteter Stationen.
|
||||||
|
- **Sked-Übergabe (ADDSKED):** Über den Button "Create sked" im Stationsinfo-Panel wird nicht nur in KST4Contest ein Sked angelegt, sondern dieses auch *direkt per UDP an das Win-Test Netzwerk als ADDSKED-Paket gesendet*.
|
||||||
|
- Es kann zwischen den Sked-Modi "AUTO", "SSB" oder "CW" gewählt werden.
|
||||||
|
|
||||||
|
**Notwendige Einstellungen in KST4Contest:**
|
||||||
|
- `UDP-Port for Win-Test listener` (Standard: 9871).
|
||||||
|
- `Receive Win-Test network based UDP log messages` aktivieren.
|
||||||
|
- `Win-Test sked transmission (push via ADDSKED to Win-Test network)` aktivieren.
|
||||||
|
- `KST station name in Win-Test network (src of SKED packets)`: Legt fest, unter welchem Stationsnamen KST4Contest im WT-Netzwerk auftritt (z.B. "KST").
|
||||||
|
- `Win-Test station name filter`: Wenn hier ein Name eingetragen wird (z.B. "STN1"), werden nur QSOs von dieser bestimmten Win-Test Instanz verarbeitet. Leer lassen, um alle zu akzeptieren.
|
||||||
|
- `Win-Test network broadcast address`: Wird idR automatisch erkannt und ist erforderlich, um die Sked-Pakete ins Netzwerk zu senden.
|
||||||
|
|
||||||
|
**Einstellungen in Win-Test:**
|
||||||
|
- Das Netzwerk in Win-Test muss aktiv sein.
|
||||||
|
- Win-Test muss so konfiguriert sein, dass es seine Broadcasts an den entsprechenden Port (Standard 9871) sendet bzw. empfängt.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -83,6 +108,8 @@ WinTest wird ebenfalls unterstützt. KST4Contest empfängt WinTest-UDP-Pakete ü
|
|||||||
|
|
||||||
Neben der QSO-Synchronisation übertragen UCXLog und andere Programme auch die **aktuelle Transceiverfrequenz** via UDP. KST4Contest verarbeitet diese Information und stellt sie als Variable `MYQRG` bereit.
|
Neben der QSO-Synchronisation übertragen UCXLog und andere Programme auch die **aktuelle Transceiverfrequenz** via UDP. KST4Contest verarbeitet diese Information und stellt sie als Variable `MYQRG` bereit.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
**Ergebnis**: Die eigene QRG muss im Chat nie mehr manuell eingegeben werden – ein Klick auf den MYQRG-Button oder die Verwendung der Variable im Beacon genügt.
|
**Ergebnis**: Die eigene QRG muss im Chat nie mehr manuell eingegeben werden – ein Klick auf den MYQRG-Button oder die Verwendung der Variable im Beacon genügt.
|
||||||
|
|
||||||
> **Hinweis für Multi-Setup**: Bei zwei Logprogrammen an zwei Computern sollte nur **eines** die Frequenzpakete senden. KST4Contest kann nicht zwischen den Quellen unterscheiden und verarbeitet alle eingehenden Pakete.
|
> **Hinweis für Multi-Setup**: Bei zwei Logprogrammen an zwei Computern sollte nur **eines** die Frequenzpakete senden. KST4Contest kann nicht zwischen den Quellen unterscheiden und verarbeitet alle eingehenden Pakete.
|
||||||
|
|||||||
BIN
github_docs/dxlog_net_logsync.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
@@ -32,6 +32,10 @@ An account is required for this service. Please consider donating to Thomas –
|
|||||||
|
|
||||||
1. Start AirScout.
|
1. Start AirScout.
|
||||||
2. Enter your OV3T feed account details (username, password, URL) in the AirScout settings.
|
2. Enter your OV3T feed account details (username, password, URL) in the AirScout settings.
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
3. Test the connection.
|
3. Test the connection.
|
||||||
|
|
||||||
### Step 2: Enable UDP Communication for KST4Contest
|
### Step 2: Enable UDP Communication for KST4Contest
|
||||||
@@ -47,6 +51,10 @@ In KST4Contest Preferences → **AirScout Settings**:
|
|||||||
- Enable AirScout communication
|
- Enable AirScout communication
|
||||||
- Leave IP and port at their default values (unless changed)
|
- Leave IP and port at their default values (unless changed)
|
||||||
|
|
||||||
|
{ width=85% }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Communication Between KST4Contest and AirScout (from v1.263)
|
## Communication Between KST4Contest and AirScout (from v1.263)
|
||||||
|
|||||||
@@ -6,6 +6,85 @@ Version history of KST4Contest / PraktiKST.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
For the latest changelog, please refer to GitHub. The previous changelog is below.
|
||||||
|
|
||||||
|
## v1.40 (2026-02-16)
|
||||||
|
**Major Feature Release: Score System, AP Timeline, Win-Test, PSTRotator**
|
||||||
|
|
||||||
|
**New:**
|
||||||
|
- **Chatmember Score System**: Every chat member is automatically scored based on antenna direction, activity time, message count, active bands, frequencies, sked direction (degrees), and other factors. Top candidates are highlighted in a dedicated list.
|
||||||
|
- **AP Timeline**: For each minute of possible aircraft arrival, up to 4 highly-scored stations are shown that should be workable. Aircraft with the highest potential are preferred over the fastest arrival. Chat members whose antenna is not pointing towards you are shown transparently.
|
||||||
|
- **Win-Test Support** (Beta since v1.31, now fully configurable): Log synchronisation, frequency parsing and **sked handover via UDP** fully integrated. Can be enabled/disabled in Preferences.
|
||||||
|
- **PSTRotator Interface** (Beta since v1.31, now fully configurable): Rotator position updates directly from KST4Contest. Can be enabled/disabled in Preferences.
|
||||||
|
- **QSO Sniffer**: Messages from configurable callsign lists are automatically forwarded to the PM window.
|
||||||
|
- **Band Alert for logged stations**: When a station is logged, a hint appears if that station has another active band that you are also QRV on.
|
||||||
|
- **Sked Reminder ALERT**: A sked alarm with automatic messages in configurable intervals (2+1 / 5+2+1 / 10+5+2+1 minutes before the sked) can be set up for each chat member, plus acoustic and visual notification.
|
||||||
|
- **Load chat history on startup**: Chat server history is loaded on connect to immediately see active members and recent messages.
|
||||||
|
- **Skedfail button**: In the FurtherInfo panel, a sked failure can be marked for a chat member, which lowers their priority score.
|
||||||
|
|
||||||
|
**Changed:**
|
||||||
|
- AP notes added to internal DX cluster spots.
|
||||||
|
- Chat member table scrolling follows the current message selection automatically.
|
||||||
|
- Generic auto-reply and QRG auto-reply now fire a maximum of once every 45 seconds per callsign (prevents spam and message ping-pong).
|
||||||
|
- New saveable settings: ServerDNS/Port, PSTRotator interface, Win-Test interface, callsign sniffer, Dark Mode on by default.
|
||||||
|
- Date column removed from chat table (time only – saves space).
|
||||||
|
|
||||||
|
**Fixed:**
|
||||||
|
- User list now automatically sorted on every new member sign-on.
|
||||||
|
- Posonpill messages now terminate exactly one client instance (no longer affects all instances or wtKST).
|
||||||
|
- wtKST: crash on KST4Contest disconnection fixed.
|
||||||
|
- Multiple issues with callsign suffixes like `/p`, `-2`, etc. fixed throughout.
|
||||||
|
- `QTFDefault` was not saved correctly → fixed.
|
||||||
|
- AirScout watchlist (ASWATCHLIST) was not being updated → fixed.
|
||||||
|
- Dark Mode: QRG fields not displayed at full size → fixed.
|
||||||
|
- Version number display corrected.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v1.31 (2025-12-13)
|
||||||
|
**Win-Test + PSTRotator Beta, QSO Sniffer, DNS Hotfix**
|
||||||
|
|
||||||
|
**New:**
|
||||||
|
- **Win-Test support** (Beta, not yet deactivatable): Log synchronisation and frequency parsing.
|
||||||
|
- **PSTRotator support** (Beta, not yet deactivatable).
|
||||||
|
- **QSO Sniffer**: Messages from configurable callsigns are forwarded to the PM window.
|
||||||
|
|
||||||
|
**Changed:**
|
||||||
|
- **DNS server changed**: From `www.on4kst.info` to `www.on4kst.org` (hotfix). The DNS server is now configurable in Preferences.
|
||||||
|
|
||||||
|
**Fixed:**
|
||||||
|
- Endless loop in error case freezes the client → fixed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v1.266 (2025-10-03)
|
||||||
|
**AirScout Fix for Callsigns with Suffix**
|
||||||
|
|
||||||
|
**Fixed:**
|
||||||
|
- AirScout interface did not work when the login callsign contained a suffix (e.g. `9A1W-2`). AirScout cannot handle this format – only the base callsign without suffix is now passed to AirScout.
|
||||||
|
|
||||||
|
*(Bug reported and tested by 9A2HM / Kreso – many thanks!)*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v1.265 (2025-09-28)
|
||||||
|
**Direction Buttons Stay Coloured When Active**
|
||||||
|
|
||||||
|
**Fixed:**
|
||||||
|
- Direction buttons (N / NE / E etc.) now keep their highlight colour when activated, making the active state immediately visible.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v1.264 (2025-08-02)
|
||||||
|
**Simplelogfile: Improved Callsign Recognition**
|
||||||
|
|
||||||
|
**Fixed:**
|
||||||
|
- Callsigns like `S53CC`, `S51A`, etc. were not being marked as worked in the SimpleLogFile interpreter → recognition pattern improved.
|
||||||
|
|
||||||
|
*(Bug reported by Boris, S53CC – thank you!)*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## v1.263 (2025-06-08)
|
## v1.263 (2025-06-08)
|
||||||
**AirScout Communication and Login Name**
|
**AirScout Communication and Login Name**
|
||||||
|
|
||||||
@@ -151,6 +230,6 @@ First publicly released version. Core features:
|
|||||||
## Planned Features
|
## Planned Features
|
||||||
|
|
||||||
- `MYQTF` variable (own antenna direction as text)
|
- `MYQTF` variable (own antenna direction as text)
|
||||||
- Lifetime for worked status (automatic reset)
|
- ~~Lifetime for worked status (automatic reset)~~ ✅ **Implemented in v1.40** (3-day lifetime, no manual reset needed anymore)
|
||||||
- Filtering the "Cluster & QSO of others" window to own QTF
|
- Filtering the "Cluster & QSO of others" window to own QTF
|
||||||
- Further topography-based calculations for direction warnings
|
- Further topography-based calculations for direction warnings
|
||||||
|
|||||||
@@ -4,49 +4,73 @@
|
|||||||
|
|
||||||
After the first start, the **settings window** opens – this is the central starting point for all configuration. It is recommended to keep the settings window open during operation (e.g. to quickly toggle the beacon on and off).
|
After the first start, the **settings window** opens – this is the central starting point for all configuration. It is recommended to keep the settings window open during operation (e.g. to quickly toggle the beacon on and off).
|
||||||
|
|
||||||
> **Important**: Always click **"Save Settings"** after any change! Settings are stored in `~/.praktikst/preferences.xml`. From v1.21 onwards, window sizes and divider positions are also saved when you click Save.
|
> **Important**: Always click **"Save Settings"** after any change! Settings are stored in `~/.praktikst/preferences.xml` on Linux and in `%USERPROFILE%\.praktikst\preferences.xml` (or `C:\Users\<Username>\.praktikst\preferences.xml`) on Windows. From v1.21 onwards, window sizes and divider positions are also saved when you click Save.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Station Settings
|
## Station Settings
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Login and Chat Categories
|
||||||
|
|
||||||
|
Enter your ON4KST chat credentials here (callsign and password).
|
||||||
|
Also, select the **primary chat category** (e.g., IARU Region 1 VHF/Microwave).
|
||||||
|
|
||||||
|
With the option for a **second chat** (Multi-Channel Login), you can log in to another category simultaneously (e.g., UHF/SHF). Both chats will then be monitored in parallel. You can optionally specify a different login name for the second chat (useful for Opposite Station Multi-Callsign Logging).
|
||||||
|
|
||||||
### Callsign and Locator
|
### Callsign and Locator
|
||||||
|
|
||||||
Enter your callsign and Maidenhead locator (6 characters, e.g. `JN49IJ`). These values are used for distance and direction calculations.
|
Enter your own callsign and Maidenhead locator (6 characters, e.g., `JN49IJ`). These values are needed for distance and direction calculations.
|
||||||
|
|
||||||
### Active Bands
|
### Active Bands
|
||||||
|
|
||||||
Use the **"my station uses band"** checkboxes to select which bands you are active on. Only selected bands will show buttons and table rows in the user interface. A restart is required after changing these settings.
|
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.
|
||||||
|
|
||||||
### Antenna Beamwidth
|
### Antenna Beamwidth
|
||||||
|
|
||||||
Enter a realistic value for your antenna's beamwidth (in degrees). This value is used for the [Sked Direction Highlighting](Features#sked-direction-highlighting). A test value of 50° has proven useful; DM5M uses Quads with 69°.
|
Enter a realistic value for your antenna's beamwidth (in degrees). This value is used for the [Sked Direction Highlighting](Features#sked-direction-highlighting). A test value of 50° has proven effective; DM5M uses quads with 69°.
|
||||||
|
|
||||||
> **Do not** enter fantasy values – the direction calculations will become meaningless.
|
> **Do not** enter fantasy values – the direction calculations will become useless.
|
||||||
|
|
||||||
### Default Maximum QRB
|
### Default Maximum QRB
|
||||||
|
|
||||||
Maximum distance (in km) for which direction warnings should be triggered. A realistic value for DM5M is 900 km. Stations beyond this distance are ignored for highlighting purposes.
|
Maximum distance (in km) for which direction warnings should be triggered. A realistic value for DM5M is 900 km. Stations farther away are ignored for highlighting purposes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Server Settings (from v1.31)
|
||||||
|
|
||||||
|
The chat server DNS and port are configurable in the Preferences:
|
||||||
|
|
||||||
|
- **Server DNS**: Default `www.on4kst.org` (changed from `www.on4kst.info` in v1.31 hotfix).
|
||||||
|
- **Port**: Default port of the ON4KST server.
|
||||||
|
|
||||||
|
A change is only needed if the server moves or an alternative endpoint is used.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Log Sync Settings
|
## Log Sync Settings
|
||||||
|
|
||||||
Two methods are available for automatically marking worked stations. Details: [Log Synchronisation](en-Log-Sync).
|
Three methods are available for automatically marking worked stations. Details: [Log Synchronisation](en-Log-Sync).
|
||||||
|
|
||||||
### Universal File Based Callsign Interpreter (Simplelogfile)
|
### Universal File Based Callsign Interpreter (Simplelogfile)
|
||||||
|
|
||||||
Interprets any log file using regex to find callsign patterns. No band information available. Suitable as a fallback or for unsupported logging programs.
|
Interprets any log file using regex for callsign patterns. No band information is available. Suitable as a fallback or for log programs that are not directly supported.
|
||||||
|
|
||||||
### Network Listener for Logger's QSO UDP Broadcast
|
### Network Listener for Logger's QSO UDP Broadcast
|
||||||
|
|
||||||
**Recommended method.** KST4Contest listens for UDP packets sent by the logging software when saving a QSO. Stations are marked including band information. UDP port: default **12060**.
|
**Recommended method.** KST4Contest listens for UDP packets sent by the logging software to the broadcast address when a QSO is saved. Stations are marked with band information. UDP port: default **12060**. (Used by UCXLog, N1MM+, QARTest, DXLog.net, etc.).
|
||||||
|
|
||||||
|
### Win-Test Network Listener (Additional UDP Listener)
|
||||||
|
|
||||||
|
A dedicated network listener for Win-Test. KST4Contest receives and processes Win-Test-specific UDP packets (including sked handovers) on the configured port.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## TRX Sync Settings
|
## TRX Sync Settings
|
||||||
|
|
||||||
Receives the current transceiver frequency from the logging software via UDP. Makes the `MYQRG` variable available automatically. Useful for:
|
Receives the current transceiver frequency from the logging software via UDP. This enables the automatic population of the `MYQRG` variable. Useful for:
|
||||||
|
|
||||||
- Quickly inserting your own QRG into chat messages.
|
- Quickly inserting your own QRG into chat messages.
|
||||||
- Automatic CQ beacon with current frequency.
|
- Automatic CQ beacon with current frequency.
|
||||||
@@ -67,13 +91,13 @@ Three notification types are available:
|
|||||||
|
|
||||||
1. **Simple sounds**: TADA sound for incoming messages, tick for sked direction detection, etc.
|
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.
|
2. **CW announcement**: The callsign of a station sending a private message is output as a CW signal.
|
||||||
3. **Phonetic announcement**: The callsign is spoken phonetically.
|
3. **Phonetic announcement**: The callsign is pronounced phonetically.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Shortcut Settings
|
## Shortcut Settings
|
||||||
|
|
||||||
Configure quick-access buttons that appear directly in the main window. Clicking a button inserts the configured text into the send field. All [variables](Macros-and-Variables#variables) can be used.
|
Configuration of quick-access buttons that appear directly in the main window. Clicking a button inserts the configured text into the send field. All [variables](Macros-and-Variables#variables) can be used.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -93,9 +117,9 @@ If a callsign is selected in the user list, the snippet is addressed as a direct
|
|||||||
|
|
||||||
## Beacon Settings
|
## Beacon Settings
|
||||||
|
|
||||||
Configure an automatic interval message in the public chat channel. Recommended: use the `MYQRG` variable in the text so the current frequency is always up to date. Interval and text are freely configurable.
|
Configuration of an automatic interval beacon in the public chat channel. Recommended: use the `MYQRG` variable in the text so the current frequency is always up to date. Interval and text are freely configurable.
|
||||||
|
|
||||||
> **Tip**: Enable the beacon while calling CQ and quickly disable it in the settings window when not calling.
|
> **Tip**: Enable the beacon when calling CQ and quickly disable it in the settings window when not calling.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -104,32 +128,73 @@ Configure an automatic interval message in the public chat channel. Recommended:
|
|||||||
New settings section with the following options:
|
New settings section with the following options:
|
||||||
|
|
||||||
- **Auto-reply to all incoming messages**: Configurable automatic reply to private messages.
|
- **Auto-reply to all incoming messages**: Configurable automatic reply to private messages.
|
||||||
- **Auto-reply with CQ QRG**: When someone asks for your frequency, KST4Contest automatically replies with the `MYQRG` variable content.
|
- **Auto-reply with own CQ QRG**: When someone asks for your QRG, KST4Contest automatically replies with the content of the `MYQRG` variable.
|
||||||
- **Default filter for the userinfo window**: Pre-configured message filter for the station info panel *(for Gianluca :-) )*.
|
- **Default filter for the userinfo window**: Pre-configured message filter for the station info window *(for Gianluca :-) )*.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Win-Test Network Listener (from v1.31)
|
||||||
|
|
||||||
|
A dedicated listener for Win-Test-specific UDP packets. Enables:
|
||||||
|
|
||||||
|
- **Log synchronisation**: Worked stations are retrieved from Win-Test and marked in the user list.
|
||||||
|
- **Frequency parsing**: The current TRX frequency from Win-Test populates the `MYQRG` variable.
|
||||||
|
- **Sked handover (SKED push)**: Skeds from KST4Contest are passed directly to Win-Test via UDP. Win-Test's default UDP broadcast port (9871) is used.
|
||||||
|
|
||||||
|
Settings:
|
||||||
|
- **Enable/Disable**: Checkbox in Preferences (from v1.40).
|
||||||
|
- **Port**: Configurable UDP port for the Win-Test listener.
|
||||||
|
- **Sked UDP address and port**: Target address and port for SKED handover to Win-Test.
|
||||||
|
|
||||||
|
> **Note**: The Win-Test listener is an **additional** listener – the standard QSO UDP broadcast listener on port 12060 remains independent.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PSTRotator Settings (from v1.31)
|
||||||
|
|
||||||
|
KST4Contest can control antenna direction via PSTRotator.
|
||||||
|
|
||||||
|
Settings:
|
||||||
|
- **Enable/Disable**: Checkbox in Preferences (from v1.40).
|
||||||
|
- **IP address**: IP address of the PSTRotator computer (default: `127.0.0.1` when running on the same PC).
|
||||||
|
- **Port**: Communication port of PSTRotator.
|
||||||
|
|
||||||
|
> **Note**: After clicking a direction button, KST4Contest waits briefly for the rotator response. With slow rotors (e.g. SPID) there may be a small delay.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sniffer Settings (from v1.31)
|
||||||
|
|
||||||
|
The QSO sniffer filters chat messages from configurable callsigns and forwards them to the PM window.
|
||||||
|
|
||||||
|
Settings:
|
||||||
|
- **Callsign list**: Comma-separated list of callsigns whose messages are always forwarded to the PM window.
|
||||||
|
|
||||||
|
Use case: Keep track of important stations (e.g. DX expeditions or trusted contest allies) without constantly monitoring the main chat.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Worked Station Database Settings
|
## Worked Station Database Settings
|
||||||
|
|
||||||
Reset the internal worked database before each contest! Contains:
|
The internal worked database contains:
|
||||||
|
|
||||||
- Worked status for all stations (per band)
|
- Worked status of all stations (per band)
|
||||||
- NOT-QRV tags (since v1.2)
|
- NOT-QRV tags (since v1.2)
|
||||||
|
|
||||||
Use the **"Reinitialize"** button below the table. A planned feature is an automatic expiry time for the worked status.
|
**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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Dark Mode (from v1.26)
|
## Dark Mode (from v1.26)
|
||||||
|
|
||||||
Toggle via the menu: **Window → Use Dark Mode**. Colours can be individually customised via CSS.
|
Toggle via the menu: **Window → Use Dark Mode**. The colors can be individually customized via CSS.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Saving Settings
|
## Saving Settings
|
||||||
|
|
||||||
Click **"Save Settings"** after **every** change! Without saving, all changes are lost on next start.
|
Click **"Save Settings"** after **every** change! Without saving, all changes will be lost on the next start.
|
||||||
|
|
||||||
- Storage location: `~/.praktikst/preferences.xml`
|
- Storage location: `~/.praktikst/preferences.xml` on Linux and `%USERPROFILE%\.praktikst\preferences.xml` (or `C:\Users\<Username>\.praktikst\preferences.xml`) on Windows
|
||||||
- From v1.21: Window sizes and divider positions are also saved.
|
- From v1.21: Window sizes and divider positions are also saved.
|
||||||
- If you encounter problems: delete the configuration file → KST4Contest creates a new one with default values.
|
- If you encounter problems: delete the configuration file → KST4Contest will create a new one with default values.
|
||||||
|
|||||||
@@ -135,22 +135,86 @@ For selected stations in the user list, there are direct buttons to open the **Q
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Sked Reminders (Sked Reminder Service)
|
## Sked Reminders with ALERT (from v1.40)
|
||||||
|
|
||||||
For agreed skeds, automatic reminder PMs can be configured, sent X minutes before the agreed time. Reminders are activated from the FurtherInfo panel.
|
A sked reminder service with automatic messages can be activated for each chat member. Configurable interval patterns:
|
||||||
|
|
||||||
|
- **2+1 minutes**: Messages at 2 min and 1 min before the sked.
|
||||||
|
- **5+2+1 minutes**: Messages at 5, 2 and 1 min before the sked.
|
||||||
|
- **10+5+2+1 minutes**: Messages at 10, 5, 2 and 1 min before the sked.
|
||||||
|
|
||||||
|
In addition to the automated messages to the remote station, there is an **acoustic and visual notification** for your own operator so no sked is ever missed.
|
||||||
|
|
||||||
|
Activate from the FurtherInfo panel of the corresponding station.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Priority List / Score Service
|
## QSO Sniffer (from v1.31)
|
||||||
|
|
||||||
KST4Contest automatically calculates a **priority list** of the most interesting contacts, based on:
|
The QSO sniffer monitors the chat for messages from a configurable callsign list and automatically forwards them to the **PM window**. This prevents relevant messages from being lost in the general chat traffic.
|
||||||
|
|
||||||
- Direction detection
|
Configuration: [Configuration – Sniffer Settings](en-Configuration#sniffer-settings-from-v131)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Win-Test Integration (from v1.31, fully configurable from v1.40)
|
||||||
|
|
||||||
|
KST4Contest fully supports [Win-Test](https://www.win-test.com/) as a logging programme:
|
||||||
|
|
||||||
|
- **Log synchronisation**: Worked stations are automatically retrieved from Win-Test and marked in the user list.
|
||||||
|
- **Frequency parsing**: The current TRX frequency is read from Win-Test UDP packets and populates the `MYQRG` variable.
|
||||||
|
- **Sked handover (SKED push via UDP)**: Agreed skeds from KST4Contest can be pushed directly to Win-Test, so the remote callsign appears in Win-Test's sked window.
|
||||||
|
|
||||||
|
Details: [Configuration – Win-Test Network Listener](en-Configuration#win-test-network-listener)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PSTRotator Interface (from v1.31, fully configurable from v1.40)
|
||||||
|
|
||||||
|
KST4Contest can control antenna direction directly via **PSTRotator**. When a station is selected in the user list, the rotator can automatically be turned to the QTF of the selected station.
|
||||||
|
|
||||||
|
Configuration: [Configuration – PSTRotator Settings](en-Configuration#pstrotator-settings-from-v131)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Band Alert for New QSOs (from v1.40)
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Worked Tag Lifetime (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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Chatmember Score System / Priority List (from v1.40)
|
||||||
|
|
||||||
|
KST4Contest automatically calculates a **priority score** for each active chat member. The score is derived from:
|
||||||
|
|
||||||
|
- Antenna direction of the remote station (is it pointing towards me?)
|
||||||
- QRB (distance)
|
- QRB (distance)
|
||||||
|
- Activity time and message count
|
||||||
|
- Active bands and frequencies
|
||||||
- AP availability (AirScout)
|
- AP availability (AirScout)
|
||||||
- Worked status
|
- Sked direction (degrees)
|
||||||
|
- Sked success rate and skedfail markings
|
||||||
|
|
||||||
The top candidates are shown in a separate list, helping you not to miss the most important stations during contest stress.
|
The top candidates are highlighted in a dedicated priority list, helping you not to miss the most important contacts during contest stress.
|
||||||
|
|
||||||
|
Stations with a failed sked can be marked using the **Skedfail button** in the FurtherInfo panel – this temporarily lowers their score.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AP Timeline (from v1.40)
|
||||||
|
|
||||||
|
A visual timeline shows up to 4 highly-scored stations per minute slot that should be workable via aircraft scatter. Prioritisation criteria:
|
||||||
|
|
||||||
|
- **Highest reflection potential** is preferred (not necessarily the fastest arrival).
|
||||||
|
- Stations towards which your antenna is not pointing are shown **transparently**.
|
||||||
|
|
||||||
|
This gives the contest operator a quick overview of which stations will be reachable via which aircraft and at what time.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ Developed by **DO5AMF (Marc Fröhlich)**, operator at DM5M.
|
|||||||
|
|
||||||
| Page | Contents |
|
| Page | Contents |
|
||||||
|---|---|
|
|---|---|
|
||||||
| [Installation](en-Installation) | Download, Java requirements, updates |
|
| [Installation](en-Installation) | Download, Java requirements, update |
|
||||||
| [Configuration](en-Configuration) | All settings in detail |
|
| [Configuration](en-Configuration) | All settings in detail |
|
||||||
| [Log Synchronisation](en-Log-Sync) | UCXLog, N1MM+, QARTest, DXLog.net, WinTest |
|
| [Log Synchronisation](en-Log-Sync) | UCXLog, N1MM+, QARTest, DXLog.net, WinTest |
|
||||||
| [AirScout Integration](en-AirScout-Integration) | Aircraft scatter detection |
|
| [AirScout Integration](en-AirScout-Integration) | Aircraft scatter detection |
|
||||||
| [DX Cluster Server](en-DX-Cluster-Server) | Built-in DX cluster for your logging software |
|
| [DX Cluster Server](en-DX-Cluster-Server) | Built-in DX cluster for your logging software |
|
||||||
| [Features](en-Features) | All features at a glance |
|
| [Features](en-Features) | All features at a glance |
|
||||||
| [Macros and Variables](en-Macros-and-Variables) | Text snippets, shortcuts, variables |
|
| [Macros and Variables](en-Macros-and-Variables) | Text snippets, shortcuts, variables |
|
||||||
| [User Interface](en-User-Interface) | UI explained and how to operate it |
|
| [User Interface](en-User-Interface) | UI explanation and operation |
|
||||||
| [Changelog](en-Changelog) | Version history |
|
| [Changelog](en-Changelog) | Version history |
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -42,7 +42,7 @@ The ON4KST Chat is the de-facto standard for skeds on the 144 MHz and higher ban
|
|||||||
|
|
||||||
- **Email**: praktimarc+kst4contest@gmail.com *(for kst4contest topics only)*
|
- **Email**: praktimarc+kst4contest@gmail.com *(for kst4contest topics only)*
|
||||||
- **GitHub**: https://github.com/praktimarc/kst4contest
|
- **GitHub**: https://github.com/praktimarc/kst4contest
|
||||||
- **Download**: https://do5amf.funkerportal.de/
|
- **Download**: https://github.com/praktimarc/kst4contest/releases/latest
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -4,23 +4,21 @@
|
|||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
### Java
|
An resolution of 1200px by 720px is recommended
|
||||||
|
|
||||||
KST4Contest is a Java application. A current **Java Runtime Environment (JRE)** is required. The recommended version is Java 17 or higher.
|
|
||||||
|
|
||||||
### ON4KST Account
|
### ON4KST Account
|
||||||
|
|
||||||
To use the chat client, you need a registered account with the ON4KST chat service:
|
To use the chat, a registered account with the ON4KST chat service is required:
|
||||||
|
|
||||||
- Register at: http://www.on4kst.info/chat/register.php
|
- Register at: http://www.on4kst.info/chat/register.php
|
||||||
|
|
||||||
### Behavioural Etiquette
|
### Chat Etiquette
|
||||||
|
|
||||||
The official language in the ON4KST Chat is **English**. Please use English even when communicating with stations from your own country. Common HAM abbreviations (agn, dir, pse, rrr, tnx, 73 …) are widely used and understood.
|
The official language in the ON4KST Chat is **English**. Please use English even when communicating with stations from your own country. Common HAM abbreviations (agn, dir, pse, rrr, tnx, 73 …) are widely used and understood.
|
||||||
|
|
||||||
### Sending Personal Messages
|
### Personal Messages
|
||||||
|
|
||||||
To send a private message to another station, always use this format:
|
To send a private message to another station, always use the following format:
|
||||||
|
|
||||||
```
|
```
|
||||||
/CQ CALLSIGN message text
|
/CQ CALLSIGN message text
|
||||||
@@ -28,45 +26,78 @@ To send a private message to another station, always use this format:
|
|||||||
|
|
||||||
Example: `/CQ DL5ASG pse sked 144.205?`
|
Example: `/CQ DL5ASG pse sked 144.205?`
|
||||||
|
|
||||||
During contest operation (5–6 messages per second in the public channel), public messages directed at a specific callsign are easily missed. KST4Contest also catches such messages if they are accidentally posted publicly (see [Features – PM Catching](Features#pm-catching)).
|
During heavy chat traffic (5–6 messages per second in a contest), public messages directed at a specific callsign are easily missed. However, KST4Contest also catches such messages if they are accidentally posted publicly (see [Features – PM Catching](Features#catching-personal-messages)).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Download
|
## Download
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
The latest version can be downloaded as a ZIP file:
|
The latest version can be downloaded as a ZIP file:
|
||||||
|
|
||||||
**https://do5amf.funkerportal.de/**
|
**https://github.com/praktimarc/kst4contest/releases/latest**
|
||||||
|
|
||||||
|
The filename has the format `praktiKST-v<version_number>-windows-x64.zip`.
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
The latest version can be downloaded as an AppImage:
|
||||||
|
|
||||||
|
**https://github.com/praktimarc/kst4contest/releases/latest**
|
||||||
|
|
||||||
|
The filename has the format `praktiKST-v<version_number>-linux-x86_64.AppImage`.
|
||||||
|
|
||||||
The filename follows the pattern `kst4Contest_v<version>.zip`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. Download the ZIP file.
|
### Windows
|
||||||
2. Unzip into a folder of your choice.
|
|
||||||
3. Run `praktiKST.exe` (Windows) or the corresponding start script.
|
|
||||||
|
|
||||||
Settings are stored at `%USERPROFILE%\.praktikst\preferences.xml` (Windows).
|
1. Download the ZIP file.
|
||||||
|
2. Unzip the ZIP file into a folder of your choice.
|
||||||
|
3. Run `praktiKST.exe`.
|
||||||
|
|
||||||
|
Settings are stored at `%USERPROFILE%\.praktikst\preferences.xml`.
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
1. Download the AppImage.
|
||||||
|
2. Unzip the AppImage into a folder of your choice.
|
||||||
|
3. Make the AppImage executable (in the terminal with `chmod +x praktiKST-v<version_number>-linux-x86_64.AppImage`)
|
||||||
|
4. Run the AppImage.
|
||||||
|
|
||||||
|
Settings are stored at `~/.praktikst/preferences.xml`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Updating
|
## Updating
|
||||||
|
|
||||||
KST4Contest includes an **automatic update notification service**: when a new version is available, a window will appear at startup showing:
|
KST4Contest includes an **automatic update notification service**: as soon as a new version is available, a window will appear at startup with:
|
||||||
- A notification that a new version is available
|
- information that a new version is available,
|
||||||
- A changelog
|
- a changelog,
|
||||||
- The download link for the latest package
|
- the download link for the new version.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
### Update Process
|
### Update Process
|
||||||
|
|
||||||
Currently the only way to update is:
|
#### Windows
|
||||||
|
|
||||||
|
Currently, there is only one way to update:
|
||||||
|
|
||||||
1. Delete the old folder.
|
1. Delete the old folder.
|
||||||
2. Unzip the new package.
|
2. Unzip the new ZIP file.
|
||||||
|
|
||||||
|
The settings file (`preferences.xml`) is preserved because it is stored in the user folder, not the program folder.
|
||||||
|
|
||||||
|
#### Linux
|
||||||
|
|
||||||
|
Currently as follows:
|
||||||
|
1. Download the new AppImage
|
||||||
|
2. Mark the new AppImage as executable
|
||||||
|
3. (optional) Delete the old AppImage.
|
||||||
|
|
||||||
Your settings file (`preferences.xml`) is preserved since it is stored in your user folder, not the program folder.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -74,10 +105,10 @@ Your settings file (`preferences.xml`) is preserved since it is stored in your u
|
|||||||
|
|
||||||
### Norton 360
|
### Norton 360
|
||||||
|
|
||||||
Norton 360 flags `praktiKST.exe` as dangerous (false positive). You need to add an exception:
|
Norton 360 classifies `praktiKST.exe` as dangerous (false positive). An exception must be created for the file:
|
||||||
|
|
||||||
1. Open Norton 360.
|
1. Open Norton 360.
|
||||||
2. Security → History → Find the relevant event.
|
2. Security → History → Find the corresponding event.
|
||||||
3. Select "Restore & Add Exception".
|
3. Select "Restore & Add Exception".
|
||||||
|
|
||||||
*(Reported by PE0WGA, Franz van Velzen – thank you!)*
|
*(Reported by PE0WGA, Franz van Velzen – thank you!)*
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ KST4Contest automatically marks worked stations in the chat user list. Two basic
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Method 1: Universal File Based Callsign Interpreter (Simplelogfile)
|
## 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 for callsign patterns using a regular expression. Binary log files are also supported – unreadable binary content is simply ignored.
|
||||||
@@ -33,6 +35,8 @@ When saving a QSO, the logging software sends a UDP packet to the broadcast addr
|
|||||||
|
|
||||||
### UCXLog (DL7UCX)
|
### UCXLog (DL7UCX)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
UCXLog sends QSO UDP packets and transceiver frequency packets.
|
UCXLog sends QSO UDP packets and transceiver frequency packets.
|
||||||
|
|
||||||
**Settings in UCXLog:**
|
**Settings in UCXLog:**
|
||||||
@@ -46,6 +50,8 @@ Note for multi-setup (2 computers, 2 radios, one KST4Contest instance): Both log
|
|||||||
|
|
||||||
### QARTest (IK3QAR)
|
### QARTest (IK3QAR)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
**Special feature**: QARTest can send the **complete log** to KST4Contest (button "Invia log completo" in the QARTest settings). This means QSOs logged before KST4Contest was started are also captured.
|
**Special feature**: QARTest can send the **complete log** to KST4Contest (button "Invia log completo" in the QARTest settings). This means QSOs logged before KST4Contest was started are also captured.
|
||||||
|
|
||||||
**Settings in QARTest:**
|
**Settings in QARTest:**
|
||||||
@@ -68,14 +74,33 @@ For the built-in DX cluster server: configure N1MM+ as a DX cluster client (serv
|
|||||||
|
|
||||||
### DXLog.net
|
### DXLog.net
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
**Settings in DXLog.net:**
|
**Settings in DXLog.net:**
|
||||||
- Enable UDP broadcast
|
- Enable UDP broadcast
|
||||||
- Enter the IP of the KST4Contest computer (green-highlighted fields)
|
- Enter the IP of the KST4Contest computer (green-highlighted fields)
|
||||||
- Port: 12060
|
- Port: 12060
|
||||||
|
|
||||||
### WinTest
|
### Win-Test
|
||||||
|
|
||||||
WinTest is also supported. KST4Contest receives WinTest UDP packets via a dedicated listener. Configuration is analogous to the other programs.
|
Win-Test is supported with a dedicated UDP network listener that understands the native Win-Test network protocol.
|
||||||
|
|
||||||
|
**Advantages of Win-Test Integration:**
|
||||||
|
- 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*.
|
||||||
|
- You can choose between "AUTO", "SSB", or "CW" sked modes.
|
||||||
|
|
||||||
|
**Required Settings in KST4Contest:**
|
||||||
|
- `UDP-Port for Win-Test listener` (Default: 9871).
|
||||||
|
- Enable `Receive Win-Test network based UDP log messages`.
|
||||||
|
- Enable `Win-Test sked transmission (push via ADDSKED to Win-Test network)`.
|
||||||
|
- `KST station name in Win-Test network (src of SKED packets)`: Defines the station name KST4Contest uses in the WT network (e.g., "KST").
|
||||||
|
- `Win-Test station name filter`: If a name is entered here (e.g., "STN1"), only QSOs from that specific Win-Test instance will be processed. Leave empty to accept all.
|
||||||
|
- `Win-Test network broadcast address`: Is usually detected automatically and is required to send sked packets to the network.
|
||||||
|
|
||||||
|
**Settings in Win-Test:**
|
||||||
|
- The network in Win-Test must be active.
|
||||||
|
- Win-Test must be configured to send/receive its broadcasts on the corresponding port (default 9871).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -83,6 +108,8 @@ WinTest is also supported. KST4Contest receives WinTest UDP packets via a dedica
|
|||||||
|
|
||||||
In addition to QSO synchronisation, UCXLog and other programs also transmit the **current transceiver frequency** via UDP. KST4Contest processes this information and makes it available as the `MYQRG` variable.
|
In addition to QSO synchronisation, UCXLog and other programs also transmit the **current transceiver frequency** via UDP. KST4Contest processes this information and makes it available as the `MYQRG` variable.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
**Result**: Your own QRG never needs to be typed manually in the chat – clicking the MYQRG button or using the variable in the beacon is sufficient.
|
**Result**: Your own QRG never needs to be typed manually in the chat – clicking the MYQRG button or using the variable in the beacon is sufficient.
|
||||||
|
|
||||||
> **Note for multi-setup**: With two logging programs on two computers, only **one** should send frequency packets. KST4Contest cannot distinguish between sources and processes all incoming packets.
|
> **Note for multi-setup**: With two logging programs on two computers, only **one** should send frequency packets. KST4Contest cannot distinguish between sources and processes all incoming packets.
|
||||||
|
|||||||
BIN
github_docs/qartest_logsync.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
github_docs/qrg_buttons.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
github_docs/ucxlog_logsync.png
Normal file
|
After Width: | Height: | Size: 250 KiB |
BIN
github_docs/update_window.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
528
src/kstsimulator.py
Normal file
@@ -0,0 +1,528 @@
|
|||||||
|
import socket
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
import traceback
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
# =====================================
|
||||||
|
# KST-Server-Simulator / DO5AMF
|
||||||
|
# Usage: change configuration below and
|
||||||
|
# run. Enter 127.0.0.1 : 23001 as a
|
||||||
|
# target in KST4Contest or another
|
||||||
|
# KST chat client.
|
||||||
|
# =====================================
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# KONFIGURATION
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
PORT = 23001
|
||||||
|
HOST = '127.0.0.1'
|
||||||
|
|
||||||
|
MSG_TO_USER_INTERVAL = 300.0
|
||||||
|
LOGIN_LOGOUT_INTERVAL = 60.0
|
||||||
|
KEEP_ALIVE_INTERVAL = 10.0
|
||||||
|
CLIENT_WARMUP_TIME = 5.0
|
||||||
|
|
||||||
|
PROB_INACTIVE = 0.10
|
||||||
|
PROB_REACTIVE = 0.20
|
||||||
|
|
||||||
|
# QSY Wahrscheinlichkeit (Wie oft wechselt ein User seine Frequenz?)
|
||||||
|
# 0.05 = 5% Chance pro Nachricht, dass er die Frequenz ändert. Sonst bleibt er stabil.
|
||||||
|
PROB_QSY = 0.05
|
||||||
|
|
||||||
|
BANDS_VHF = { "2m": (144.150, 144.400), "70cm": (432.100, 432.300) }
|
||||||
|
BANDS_UHF = { "23cm": (1296.100, 1296.300), "3cm": (10368.100, 10368.250) }
|
||||||
|
|
||||||
|
CHANNELS_SETUP = {
|
||||||
|
"2": {
|
||||||
|
"NAME": "144/432 MHz",
|
||||||
|
"NUM_USERS": 777,
|
||||||
|
"BANDS": BANDS_VHF,
|
||||||
|
"RATES": {"PUBLIC": 0.5, "DIRECTED": 3.0},
|
||||||
|
"PERMANENT": [
|
||||||
|
{"call": "DK5EW", "name": "Erwin", "loc": "JN47NX"},
|
||||||
|
{"call": "DL1TEST", "name": "TestOp", "loc": "JO50XX"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"NAME": "Microwave",
|
||||||
|
"NUM_USERS": 333,
|
||||||
|
"BANDS": BANDS_UHF,
|
||||||
|
"RATES": {"PUBLIC": 0.2, "DIRECTED": 0.5},
|
||||||
|
"PERMANENT": [
|
||||||
|
{"call": "ON4KST", "name": "Alain", "loc": "JO20HI"},
|
||||||
|
{"call": "G4CBW", "name": "MwTest", "loc": "IO83AA"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
COUNTRY_MAPPING = {
|
||||||
|
"DL": ["JO", "JN"], "DA": ["JO", "JN"], "DF": ["JO", "JN"], "DJ": ["JO", "JN"], "DK": ["JO", "JN"], "DO": ["JO", "JN"],
|
||||||
|
"F": ["JN", "IN", "JO"], "G": ["IO", "JO"], "M": ["IO", "JO"], "2E": ["IO", "JO"],
|
||||||
|
"PA": ["JO"], "ON": ["JO"], "OZ": ["JO"], "SM": ["JO", "JP"], "LA": ["JO", "JP"],
|
||||||
|
"OH": ["KP"], "SP": ["JO", "KO"], "OK": ["JO", "JN"], "OM": ["JN", "KN"],
|
||||||
|
"HA": ["JN", "KN"], "S5": ["JN"], "9A": ["JN"], "HB9": ["JN"], "OE": ["JN"],
|
||||||
|
"I": ["JN", "JM"], "IK": ["JN", "JM"], "IU": ["JN", "JM"], "EA": ["IN", "IM"],
|
||||||
|
"CT": ["IM"], "EI": ["IO"], "GM": ["IO"], "GW": ["IO"], "YO": ["KN"],
|
||||||
|
"YU": ["KN"], "LZ": ["KN"], "SV": ["KM", "KN"], "UR": ["KO", "KN"],
|
||||||
|
"LY": ["KO"], "YL": ["KO"], "ES": ["KO"]
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMES = ["Hans", "Peter", "Jo", "Alain", "Mike", "Sven", "Ole", "Jean", "Bob", "Tom", "Giovanni", "Mario", "Frank", "Steve", "Dave"]
|
||||||
|
|
||||||
|
MSG_TEMPLATES_WITH_FREQ = [
|
||||||
|
"QSY {freq}", "PSE QSY {freq}", "Calling CQ on {freq}", "I am QRV on {freq}",
|
||||||
|
"Listening on {freq}", "Can you try {freq}?", "Signals strong on {freq}",
|
||||||
|
"Scattering on {freq}", "Please go to {freq}", "Running test on {freq}",
|
||||||
|
"Any takers for {freq}?", "Back to {freq}", "QRG {freq}?", "Aircraft scatter {freq}"
|
||||||
|
]
|
||||||
|
|
||||||
|
MSG_TEMPLATES_TEXT_ONLY = [
|
||||||
|
"TNX for QSO", "73 all", "Anyone for sked?", "Good conditions",
|
||||||
|
"Nothing heard", "Rain scatter?", "Waiting for moonrise", "CQ Contest",
|
||||||
|
"QRZ?", "My locator is {loc}", "Band is open"
|
||||||
|
]
|
||||||
|
|
||||||
|
REPLY_TEMPLATES = [
|
||||||
|
"Hello {user}, 599 here", "Rgr {user}, tnx for report", "Yes {user}, QSY?",
|
||||||
|
"Sorry {user}, no copy", "Pse wait 5 min {user}", "Ok {user}, 73",
|
||||||
|
"Locator is {loc}", "Go to {freq} please", "Rgr {user}, gl"
|
||||||
|
]
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# CLIENT WRAPPER
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
class ConnectedClient:
|
||||||
|
def __init__(self, sock, addr):
|
||||||
|
self.sock = sock
|
||||||
|
self.addr = addr
|
||||||
|
self.call = f"GUEST_{random.randint(1000,9999)}"
|
||||||
|
self.channels = {"2"}
|
||||||
|
self.login_time = time.time()
|
||||||
|
self.lock = threading.Lock()
|
||||||
|
|
||||||
|
def send_safe(self, data_str):
|
||||||
|
if not data_str: return True
|
||||||
|
with self.lock:
|
||||||
|
try:
|
||||||
|
self.sock.sendall(data_str.encode('latin-1', errors='replace'))
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
try: self.sock.close()
|
||||||
|
except: pass
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# LOGIK KLASSEN
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
class MessageFactory:
|
||||||
|
@staticmethod
|
||||||
|
def get_stable_frequency(user, band_name, min_f, max_f):
|
||||||
|
"""Liefert eine stabile Frequenz für diesen User auf diesem Band"""
|
||||||
|
# Wenn noch keine Frequenz da ist ODER Zufall zuschlägt (QSY)
|
||||||
|
if band_name not in user['freqs'] or random.random() < PROB_QSY:
|
||||||
|
freq_val = round(random.uniform(min_f, max_f), 3)
|
||||||
|
user['freqs'][band_name] = f"{freq_val:.3f}"
|
||||||
|
|
||||||
|
return user['freqs'][band_name]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_chat_message(bands_config, user):
|
||||||
|
try:
|
||||||
|
# Entscheidung: Text mit Frequenz oder ohne?
|
||||||
|
if random.random() < 0.7:
|
||||||
|
# Wähle zufälliges Band aus den verfügbaren
|
||||||
|
band_name = random.choice(list(bands_config.keys()))
|
||||||
|
min_f, max_f = bands_config[band_name]
|
||||||
|
|
||||||
|
# Hole STABILE Frequenz für diesen User
|
||||||
|
freq_str = MessageFactory.get_stable_frequency(user, band_name, min_f, max_f)
|
||||||
|
|
||||||
|
return random.choice(MSG_TEMPLATES_WITH_FREQ).format(freq=freq_str)
|
||||||
|
else:
|
||||||
|
return random.choice(MSG_TEMPLATES_TEXT_ONLY).format(loc=user['loc'])
|
||||||
|
except: return "TNX 73"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_reply_msg(bands, target_call, my_loc):
|
||||||
|
try:
|
||||||
|
tmpl = random.choice(REPLY_TEMPLATES)
|
||||||
|
freq_str = "QSY?"
|
||||||
|
# Bei Replies simulieren wir oft nur "QSY?" ohne konkrete Frequenz,
|
||||||
|
# oder nutzen eine zufällige, da der Kontext fehlt.
|
||||||
|
if "{freq}" in tmpl and bands:
|
||||||
|
band_name = random.choice(list(bands.keys()))
|
||||||
|
min_f, max_f = bands[band_name]
|
||||||
|
freq_str = f"{round(random.uniform(min_f, max_f), 3):.3f}"
|
||||||
|
return tmpl.format(user=target_call, loc=my_loc, freq=freq_str)
|
||||||
|
except: return "TNX 73"
|
||||||
|
|
||||||
|
class UserFactory:
|
||||||
|
registry = {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_or_create_user(cls, channel_id, current_channel_users):
|
||||||
|
# 1. Reuse existing
|
||||||
|
candidates = [u for call, u in cls.registry.items() if call not in current_channel_users]
|
||||||
|
if candidates and random.random() < 0.5:
|
||||||
|
return random.choice(candidates)
|
||||||
|
|
||||||
|
# 2. Create new
|
||||||
|
return cls._create_new_unique_user(channel_id, current_channel_users)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _create_new_unique_user(cls, channel_id, current_channel_users):
|
||||||
|
while True:
|
||||||
|
prefix = random.choice(list(COUNTRY_MAPPING.keys()))
|
||||||
|
num = random.randint(0, 9)
|
||||||
|
suffix = "".join(random.choices("ABCDEFGHIJKLMNOPQRSTUVWXYZ", k=random.randint(1,3)))
|
||||||
|
call = f"{prefix}{num}{suffix}"
|
||||||
|
|
||||||
|
if call in current_channel_users: continue
|
||||||
|
if call in cls.registry: return cls.registry[call]
|
||||||
|
|
||||||
|
valid_grids = COUNTRY_MAPPING[prefix]
|
||||||
|
grid_prefix = random.choice(valid_grids)
|
||||||
|
sq_num = f"{random.randint(0,99):02d}"
|
||||||
|
sub = "".join(random.choices("ABCDEFGHIJKLMNOPQRSTUVWXYZ", k=2))
|
||||||
|
loc = f"{grid_prefix}{sq_num}{sub}"
|
||||||
|
|
||||||
|
name = random.choice(NAMES)
|
||||||
|
rand = random.random()
|
||||||
|
if rand < PROB_INACTIVE: role = "INACTIVE"
|
||||||
|
elif rand < (PROB_INACTIVE + PROB_REACTIVE): role = "REACTIVE"
|
||||||
|
else: role = "ACTIVE"
|
||||||
|
|
||||||
|
# Neu V31: Frequenz-Gedächtnis
|
||||||
|
user_data = {
|
||||||
|
"call": call,
|
||||||
|
"name": name,
|
||||||
|
"loc": loc,
|
||||||
|
"role": role,
|
||||||
|
"freqs": {} # Speicher für { '2m': '144.300' }
|
||||||
|
}
|
||||||
|
|
||||||
|
cls.registry[call] = user_data
|
||||||
|
return user_data
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def register_permanent(cls, user_data):
|
||||||
|
# Sicherstellen, dass auch Permanent User Freq-Memory haben
|
||||||
|
if "freqs" not in user_data:
|
||||||
|
user_data["freqs"] = {}
|
||||||
|
cls.registry[user_data['call']] = user_data
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# CHANNEL INSTANCE
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
class ChannelInstance:
|
||||||
|
def __init__(self, cid, config, server):
|
||||||
|
self.id = cid
|
||||||
|
self.config = config
|
||||||
|
self.server = server
|
||||||
|
|
||||||
|
self.users_pool = []
|
||||||
|
self.online_users = {}
|
||||||
|
self.history_chat = []
|
||||||
|
|
||||||
|
self.last_pub = time.time()
|
||||||
|
self.last_dir = time.time()
|
||||||
|
self.last_me = time.time()
|
||||||
|
self.last_login = time.time()
|
||||||
|
|
||||||
|
self.rate_pub = 1.0 / config["RATES"]["PUBLIC"]
|
||||||
|
self.rate_dir = 1.0 / config["RATES"]["DIRECTED"]
|
||||||
|
|
||||||
|
self._init_data()
|
||||||
|
|
||||||
|
def _init_data(self):
|
||||||
|
print(f"[*] Init Channel {self.id} ({self.config['NAME']})...")
|
||||||
|
|
||||||
|
for u in self.config["PERMANENT"]:
|
||||||
|
u_full = u.copy()
|
||||||
|
u_full["role"] = "ACTIVE"
|
||||||
|
UserFactory.register_permanent(u_full)
|
||||||
|
self.online_users[u['call']] = u_full
|
||||||
|
|
||||||
|
for _ in range(self.config["NUM_USERS"]):
|
||||||
|
new_u = UserFactory.get_or_create_user(self.id, self.online_users.keys())
|
||||||
|
self.users_pool.append(new_u)
|
||||||
|
|
||||||
|
fill = int(self.config["NUM_USERS"] * 0.9)
|
||||||
|
for i in range(fill):
|
||||||
|
u = self.users_pool[i]
|
||||||
|
if u['call'] not in self.online_users:
|
||||||
|
self.online_users[u['call']] = u
|
||||||
|
|
||||||
|
print(f"[*] Channel {self.id} ready: {len(self.online_users)} Users.")
|
||||||
|
self._prefill_history()
|
||||||
|
|
||||||
|
def _prefill_history(self):
|
||||||
|
actives = [u for u in self.online_users.values() if u['role'] == "ACTIVE"]
|
||||||
|
if not actives: return
|
||||||
|
start = datetime.now() - timedelta(minutes=15)
|
||||||
|
for i in range(30):
|
||||||
|
msg_time = start + timedelta(seconds=i*30)
|
||||||
|
ts = str(int(msg_time.timestamp()))
|
||||||
|
sender = random.choice(actives)
|
||||||
|
if i % 2 == 0:
|
||||||
|
text = MessageFactory.get_chat_message(self.config["BANDS"], sender)
|
||||||
|
frame = f"CH|{self.id}|{ts}|{sender['call']}|{sender['name']}|0|{text}|0|\r\n"
|
||||||
|
else:
|
||||||
|
target = random.choice(list(self.online_users.values()))
|
||||||
|
text = MessageFactory.get_reply_msg(self.config["BANDS"], target['call'], sender['loc'])
|
||||||
|
frame = f"CH|{self.id}|{ts}|{sender['call']}|{sender['name']}|0|{text}|{target['call']}|\r\n"
|
||||||
|
self.history_chat.append(frame)
|
||||||
|
|
||||||
|
def tick(self, now):
|
||||||
|
actives = [u for u in self.online_users.values() if u['role'] == "ACTIVE"]
|
||||||
|
if not actives: return
|
||||||
|
|
||||||
|
# PUBLIC
|
||||||
|
if now - self.last_pub > self.rate_pub:
|
||||||
|
self.last_pub = now
|
||||||
|
u = random.choice(actives)
|
||||||
|
# V31: Nutzt jetzt get_chat_message, das das Freq-Memory abfragt
|
||||||
|
text = MessageFactory.get_chat_message(self.config["BANDS"], u)
|
||||||
|
ts = str(int(now))
|
||||||
|
frame = f"CH|{self.id}|{ts}|{u['call']}|{u['name']}|0|{text}|0|\r\n"
|
||||||
|
self._add_hist(frame)
|
||||||
|
self.server.broadcast_to_channel(self.id, frame)
|
||||||
|
|
||||||
|
# DIRECTED
|
||||||
|
if now - self.last_dir > self.rate_dir:
|
||||||
|
self.last_dir = now
|
||||||
|
if len(actives) > 5:
|
||||||
|
u1 = random.choice(actives)
|
||||||
|
u2 = random.choice(list(self.online_users.values()))
|
||||||
|
if u1 != u2:
|
||||||
|
if random.random() < 0.5:
|
||||||
|
# Auch hier Frequenzstabilität beachten
|
||||||
|
text = MessageFactory.get_chat_message(self.config["BANDS"], u1)
|
||||||
|
else:
|
||||||
|
text = MessageFactory.get_reply_msg(self.config["BANDS"], u2['call'], u1['loc'])
|
||||||
|
ts = str(int(now))
|
||||||
|
frame = f"CH|{self.id}|{ts}|{u1['call']}|{u1['name']}|0|{text}|{u2['call']}|\r\n"
|
||||||
|
self.server.broadcast_to_channel(self.id, frame)
|
||||||
|
if u2['role'] != "INACTIVE":
|
||||||
|
threading.Thread(target=self._schedule_reply, args=(u2['call'], u1['call']), daemon=True).start()
|
||||||
|
|
||||||
|
# MSG TO YOU
|
||||||
|
if now - self.last_me > MSG_TO_USER_INTERVAL:
|
||||||
|
self.last_me = now
|
||||||
|
target_client = self.server.get_random_subscriber(self.id)
|
||||||
|
if target_client and actives:
|
||||||
|
if not target_client.call.startswith("GUEST"):
|
||||||
|
sender = random.choice(actives)
|
||||||
|
text = MessageFactory.get_chat_message(self.config["BANDS"], sender)
|
||||||
|
print(f"[SIM Ch{self.id}] MSG TO YOU ({target_client.call})")
|
||||||
|
self.process_msg(sender['call'], sender['name'], text, target_client.call)
|
||||||
|
|
||||||
|
# LOGIN/LOGOUT
|
||||||
|
if now - self.last_login > LOGIN_LOGOUT_INTERVAL:
|
||||||
|
self.last_login = now
|
||||||
|
if random.choice(['IN', 'OUT']) == 'OUT' and len(self.online_users) > 20:
|
||||||
|
cands = [c for c in self.online_users if c not in [p['call'] for p in self.config["PERMANENT"]]]
|
||||||
|
if cands:
|
||||||
|
l = random.choice(cands)
|
||||||
|
del self.online_users[l]
|
||||||
|
self.server.broadcast_to_channel(self.id, f"UR6|{self.id}|{l}|\r\n")
|
||||||
|
else:
|
||||||
|
candidates = [u for u in self.users_pool if u['call'] not in self.online_users]
|
||||||
|
if candidates:
|
||||||
|
n = random.choice(candidates)
|
||||||
|
self.online_users[n['call']] = n
|
||||||
|
self.server.broadcast_to_channel(self.id, f"UA5|{self.id}|{n['call']}|{n['name']}|{n['loc']}|2|\r\n")
|
||||||
|
|
||||||
|
def process_msg(self, sender, name, text, target):
|
||||||
|
ts = str(int(time.time()))
|
||||||
|
frame = f"CH|{self.id}|{ts}|{sender}|{name}|0|{text}|{target}|\r\n"
|
||||||
|
if target == "0": self._add_hist(frame)
|
||||||
|
self.server.broadcast_to_channel(self.id, frame)
|
||||||
|
if target in self.online_users:
|
||||||
|
threading.Thread(target=self._schedule_reply, args=(target, sender), daemon=True).start()
|
||||||
|
|
||||||
|
def _schedule_reply(self, sim_sender, real_target):
|
||||||
|
if sim_sender not in self.online_users: return
|
||||||
|
u = self.online_users[sim_sender]
|
||||||
|
if u['role'] == "INACTIVE": return
|
||||||
|
|
||||||
|
time.sleep(random.uniform(2.0, 5.0))
|
||||||
|
if sim_sender in self.online_users:
|
||||||
|
text = MessageFactory.get_reply_msg(self.config["BANDS"], real_target, u['loc'])
|
||||||
|
ts = str(int(time.time()))
|
||||||
|
|
||||||
|
if self.server.is_real_user(real_target):
|
||||||
|
print(f"[REPLY Ch{self.id}] {sim_sender} -> {real_target}")
|
||||||
|
|
||||||
|
frame = f"CH|{self.id}|{ts}|{sim_sender}|{u['name']}|0|{text}|{real_target}|\r\n"
|
||||||
|
self.server.broadcast_to_channel(self.id, frame)
|
||||||
|
|
||||||
|
def _add_hist(self, frame):
|
||||||
|
self.history_chat.append(frame)
|
||||||
|
if len(self.history_chat) > 50: self.history_chat.pop(0)
|
||||||
|
|
||||||
|
def get_full_init_blob(self):
|
||||||
|
blob = ""
|
||||||
|
for u in self.online_users.values():
|
||||||
|
blob += f"UA0|{self.id}|{u['call']}|{u['name']}|{u['loc']}|0|\r\n"
|
||||||
|
for h in self.history_chat: blob += h
|
||||||
|
blob += f"UE|{self.id}|{len(self.online_users)}|\r\n"
|
||||||
|
return blob.encode('latin-1', errors='replace')
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# SERVER
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
class KSTServerV31:
|
||||||
|
def __init__(self):
|
||||||
|
self.lock = threading.Lock()
|
||||||
|
self.running = True
|
||||||
|
self.clients = {}
|
||||||
|
self.channels = {}
|
||||||
|
|
||||||
|
for cid, cfg in CHANNELS_SETUP.items():
|
||||||
|
self.channels[cid] = ChannelInstance(cid, cfg, self)
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
threading.Thread(target=self._sim_loop, daemon=True).start()
|
||||||
|
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
try:
|
||||||
|
s.bind((HOST, PORT))
|
||||||
|
s.listen(5)
|
||||||
|
s.settimeout(1.0)
|
||||||
|
print(f"[*] ON4KST V31 (Stable Frequencies) running on {HOST}:{PORT}")
|
||||||
|
|
||||||
|
while self.running:
|
||||||
|
try:
|
||||||
|
sock, addr = s.accept()
|
||||||
|
print(f"[*] CONNECT: {addr}")
|
||||||
|
threading.Thread(target=self._handle_client, args=(sock,), daemon=True).start()
|
||||||
|
except socket.timeout: continue
|
||||||
|
except OSError: break
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\n[!] Stop.")
|
||||||
|
finally:
|
||||||
|
self.running = False
|
||||||
|
try: s.close()
|
||||||
|
except: pass
|
||||||
|
|
||||||
|
def _handle_client(self, sock):
|
||||||
|
client_obj = ConnectedClient(sock, None)
|
||||||
|
with self.lock:
|
||||||
|
self.clients[sock] = client_obj
|
||||||
|
|
||||||
|
buffer = ""
|
||||||
|
try:
|
||||||
|
while self.running:
|
||||||
|
try: data = sock.recv(2048)
|
||||||
|
except: break
|
||||||
|
if not data: break
|
||||||
|
|
||||||
|
buffer += data.decode('latin-1', errors='replace')
|
||||||
|
while '\n' in buffer:
|
||||||
|
line, buffer = buffer.split('\n', 1)
|
||||||
|
line = line.strip()
|
||||||
|
if not line: continue
|
||||||
|
|
||||||
|
parts = line.split('|')
|
||||||
|
cmd = parts[0]
|
||||||
|
|
||||||
|
if cmd == 'LOGIN' or cmd == 'LOGINC':
|
||||||
|
if len(parts) > 1:
|
||||||
|
client_obj.call = parts[1].strip().upper()
|
||||||
|
print(f"[LOGIN] {client_obj.call} (Ch 2)")
|
||||||
|
|
||||||
|
client_obj.send_safe(f"LOGSTAT|100|2|PySimV31|KEY|Conf|3|\r\n")
|
||||||
|
if cmd == 'LOGIN':
|
||||||
|
self._send_channel_init(client_obj, "2")
|
||||||
|
|
||||||
|
elif cmd == 'SDONE':
|
||||||
|
self._send_channel_init(client_obj, "2")
|
||||||
|
|
||||||
|
elif cmd.startswith('ACHAT'):
|
||||||
|
if len(parts) >= 2:
|
||||||
|
new_chan = parts[1]
|
||||||
|
if new_chan in self.channels:
|
||||||
|
client_obj.channels.add(new_chan)
|
||||||
|
print(f"[ACHAT] {client_obj.call} -> Ch {new_chan}")
|
||||||
|
self._send_channel_init(client_obj, new_chan)
|
||||||
|
|
||||||
|
elif cmd == 'MSG':
|
||||||
|
if len(parts) >= 4:
|
||||||
|
cid = parts[1]
|
||||||
|
target = parts[2]
|
||||||
|
text = parts[3]
|
||||||
|
if text.lower().startswith("/cq"):
|
||||||
|
spl = text.split(' ', 2)
|
||||||
|
if len(spl) >= 3:
|
||||||
|
target = spl[1]; text = spl[2]
|
||||||
|
if cid in self.channels:
|
||||||
|
self.channels[cid].process_msg(client_obj.call, "Me", text, target)
|
||||||
|
|
||||||
|
elif cmd == 'CK': pass
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[!] Err: {e}")
|
||||||
|
finally:
|
||||||
|
with self.lock:
|
||||||
|
if sock in self.clients: del self.clients[sock]
|
||||||
|
client_obj.close()
|
||||||
|
|
||||||
|
def _send_channel_init(self, client_obj, cid):
|
||||||
|
if cid in self.channels:
|
||||||
|
full_blob = self.channels[cid].get_full_init_blob()
|
||||||
|
client_obj.send_safe(full_blob.decode('latin-1'))
|
||||||
|
|
||||||
|
def broadcast_to_channel(self, cid, frame):
|
||||||
|
now = time.time()
|
||||||
|
with self.lock:
|
||||||
|
targets = list(self.clients.values())
|
||||||
|
|
||||||
|
for c in targets:
|
||||||
|
if cid in c.channels:
|
||||||
|
if now - c.login_time > CLIENT_WARMUP_TIME:
|
||||||
|
c.send_safe(frame)
|
||||||
|
|
||||||
|
def get_random_subscriber(self, cid):
|
||||||
|
with self.lock:
|
||||||
|
subs = [c for c in self.clients.values() if cid in c.channels and not c.call.startswith("GUEST")]
|
||||||
|
return random.choice(subs) if subs else None
|
||||||
|
|
||||||
|
def is_real_user(self, call):
|
||||||
|
with self.lock:
|
||||||
|
for c in self.clients.values():
|
||||||
|
if c.call.upper() == call.upper() and not c.call.startswith("GUEST"):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _sim_loop(self):
|
||||||
|
print("[*] Sim Loop running...")
|
||||||
|
last_ka = time.time()
|
||||||
|
while self.running:
|
||||||
|
now = time.time()
|
||||||
|
time.sleep(0.02)
|
||||||
|
|
||||||
|
for c in self.channels.values():
|
||||||
|
c.tick(now)
|
||||||
|
|
||||||
|
if now - last_ka > KEEP_ALIVE_INTERVAL:
|
||||||
|
last_ka = now
|
||||||
|
self.broadcast_global("CK|\r\n")
|
||||||
|
|
||||||
|
def broadcast_global(self, frame):
|
||||||
|
with self.lock:
|
||||||
|
targets = list(self.clients.values())
|
||||||
|
for c in targets:
|
||||||
|
c.send_safe(frame)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
KSTServerV31().start()
|
||||||
@@ -5382,7 +5382,7 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL
|
|||||||
FlowPane chatMemberTableFilterQRBHBox = new FlowPane();
|
FlowPane chatMemberTableFilterQRBHBox = new FlowPane();
|
||||||
chatMemberTableFilterQRBHBox.setAlignment(Pos.CENTER_LEFT);
|
chatMemberTableFilterQRBHBox.setAlignment(Pos.CENTER_LEFT);
|
||||||
chatMemberTableFilterQRBHBox.setHgap(2);
|
chatMemberTableFilterQRBHBox.setHgap(2);
|
||||||
chatMemberTableFilterQRBHBox.setPrefWidth(210);
|
chatMemberTableFilterQRBHBox.setPrefWidth(225);
|
||||||
|
|
||||||
TextField chatMemberTableFilterMaxQrbTF = new TextField(chatcontroller.getChatPreferences().getStn_maxQRBDefault() + "");
|
TextField chatMemberTableFilterMaxQrbTF = new TextField(chatcontroller.getChatPreferences().getStn_maxQRBDefault() + "");
|
||||||
chatMemberTableFilterMaxQrbTF.setFocusTraversable(false);
|
chatMemberTableFilterMaxQrbTF.setFocusTraversable(false);
|
||||||
@@ -5431,7 +5431,7 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL
|
|||||||
// HBox chatMemberTableFilterQTFHBox = new HBox();
|
// HBox chatMemberTableFilterQTFHBox = new HBox();
|
||||||
FlowPane chatMemberTableFilterQTFHBox = new FlowPane();
|
FlowPane chatMemberTableFilterQTFHBox = new FlowPane();
|
||||||
chatMemberTableFilterQTFHBox.setAlignment(Pos.CENTER_LEFT);
|
chatMemberTableFilterQTFHBox.setAlignment(Pos.CENTER_LEFT);
|
||||||
chatMemberTableFilterQTFHBox.setPrefWidth(490);
|
chatMemberTableFilterQTFHBox.setPrefWidth(525);
|
||||||
chatMemberTableFilterQTFHBox.setHgap(2);
|
chatMemberTableFilterQTFHBox.setHgap(2);
|
||||||
|
|
||||||
CheckBox chatMemberTableFilterQtfEnableChkbx = new CheckBox("Show only QTF:");
|
CheckBox chatMemberTableFilterQtfEnableChkbx = new CheckBox("Show only QTF:");
|
||||||
@@ -6212,7 +6212,7 @@ public class Kst4ContestApplication extends Application implements StatusUpdateL
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
settingsStage = new Stage();
|
settingsStage = new Stage();
|
||||||
settingsStage.setTitle("Change Client seetings");
|
settingsStage.setTitle("Change Client Settings");
|
||||||
|
|
||||||
BorderPane optionsPanel = new BorderPane();
|
BorderPane optionsPanel = new BorderPane();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
module praktiKST {
|
module praktiKST {
|
||||||
requires javafx.controls;
|
requires javafx.controls;
|
||||||
|
requires javafx.fxml;
|
||||||
|
requires javafx.web;
|
||||||
requires jdk.xml.dom;
|
requires jdk.xml.dom;
|
||||||
requires java.sql;
|
requires java.sql;
|
||||||
requires javafx.media;
|
requires javafx.media;
|
||||||
|
|||||||