Let the config choose protocol 2 or 3, and fall back for one session only.

The default stays v2. A reflector that refuses that version and names the other gets one session of it, then the station announces the configured protocol again.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-22 16:28:42 +02:00
co-authored by Cursor
parent 3533b97d00
commit 2c621d4b7f
21 changed files with 361 additions and 82 deletions
+35 -7
View File
@@ -1,12 +1,25 @@
html,
body {
height: 100%;
}
body {
margin: 0;
overflow: hidden;
background: #101418;
color: #f2f4f6;
font: 16px/1.4 system-ui, sans-serif;
}
main {
box-sizing: border-box;
height: 100%;
padding: 24px;
overflow: auto;
}
body.config-open main {
display: none;
}
.status {
@@ -66,14 +79,28 @@ main {
}
#config {
position: fixed;
top: 64px;
right: 0;
bottom: 0;
left: 0;
box-sizing: border-box;
height: 100%;
padding: 16px;
background: rgba(16, 20, 24, 0.45);
overflow-x: hidden;
overflow-y: auto;
background: #101418;
scrollbar-color: #8b98a3 #0c1014;
scrollbar-width: auto;
}
#config::-webkit-scrollbar {
width: 12px;
}
#config::-webkit-scrollbar-track {
background: #0c1014;
}
#config::-webkit-scrollbar-thumb {
background: #8b98a3;
border: 2px solid #0c1014;
border-radius: 6px;
}
#config[hidden] {
@@ -106,7 +133,8 @@ main {
font-size: 14px;
}
#config input {
#config input,
#config select {
box-sizing: border-box;
display: block;
width: 100%;
+35 -8
View File
@@ -5,7 +5,6 @@ const configError = document.getElementById("config-error");
const authKey = document.getElementById("authKey");
const authToggle = document.getElementById("auth-toggle");
const configHeight = 680;
let savedSize = null;
let configLoading = false;
let sizeToken = 0;
@@ -31,18 +30,39 @@ function runtime() {
return window.runtime || null;
}
function growWindow() {
function fitConfigWindow() {
const rt = runtime();
if (!rt || !rt.WindowGetSize || !rt.WindowSetSize) {
return;
}
const token = ++sizeToken;
rt.WindowGetSize().then(function (size) {
requestAnimationFrame(function () {
if (token !== sizeToken || config.hidden) {
return;
}
savedSize = size;
rt.WindowSetSize(Math.max(size.w, 420), Math.max(size.h, configHeight));
rt.WindowGetSize().then(function (size) {
if (token !== sizeToken || config.hidden || !size) {
return;
}
if (!savedSize) {
savedSize = size;
}
const needed = Math.ceil(configForm.getBoundingClientRect().height) + 32;
const width = Math.max(size.w, 420);
const applied = rt.WindowSetSize(width, needed);
const after = applied && applied.then ? applied.then(function () {
return rt.WindowGetSize();
}) : Promise.resolve(null);
return after.then(function (now) {
if (!now || token !== sizeToken || config.hidden) {
return;
}
const extra = Math.ceil(document.documentElement.scrollHeight - window.innerHeight);
if (extra > 1) {
rt.WindowSetSize(now.w, now.h + extra);
}
});
});
});
}
@@ -60,6 +80,9 @@ function restoreWindow() {
function showError(message) {
configError.hidden = !message;
configError.textContent = message || "";
if (!config.hidden) {
fitConfigWindow();
}
}
function fillForm(form) {
@@ -68,6 +91,7 @@ function fillForm(form) {
document.getElementById("callsign-field").value = form.callsign || "";
authKey.value = form.authKey || "";
document.getElementById("talkGroup").value = String(form.talkGroup || 0);
document.getElementById("protocol-field").value = form.protocol === "v3" ? "v3" : "v2";
document.getElementById("certificateDir").value = form.certificateDir || "";
document.getElementById("enableLogging").checked = !!form.enableLogging;
document.getElementById("logFile").value = form.logFile || "";
@@ -82,6 +106,7 @@ function readForm() {
callsign: document.getElementById("callsign-field").value,
authKey: authKey.value,
talkGroup: numberValue("talkGroup"),
protocol: document.getElementById("protocol-field").value,
certificateDir: document.getElementById("certificateDir").value,
enableLogging: document.getElementById("enableLogging").checked,
logFile: document.getElementById("logFile").value
@@ -111,9 +136,9 @@ function showConfig() {
return;
}
fillForm(cfg.form || {});
showError(cfg.error);
config.hidden = false;
growWindow();
document.body.classList.add("config-open");
showError(cfg.error);
}).catch(function () {}).then(function () {
configLoading = false;
});
@@ -121,7 +146,9 @@ function showConfig() {
function hideConfig() {
config.hidden = true;
showError("");
document.body.classList.remove("config-open");
configError.hidden = true;
configError.textContent = "";
restoreWindow();
}
+6
View File
@@ -31,6 +31,12 @@
</span>
</label>
<label>Talk group <input id="talkGroup" name="talkGroup" inputmode="numeric" autocomplete="off"></label>
<label>Protocol
<select id="protocol-field" name="protocol">
<option value="v2">v2</option>
<option value="v3">v3</option>
</select>
</label>
<label>Certificate directory <input id="certificateDir" name="certificateDir" autocomplete="off"></label>
<label class="check">Enable logging <input id="enableLogging" name="enableLogging" type="checkbox"></label>
<label>Log file <input id="logFile" name="logFile" autocomplete="off"></label>