[feat](trx-frontend-http): set the squelch on the spectrum, in dB
The threshold is in dB, and since the squelch fix that is the scale the spectrum axis and the S-meter are labelled in — so the control belongs on the plot, at the level it gates. A dashed line spans the spectrum at its threshold with a grip that reads it out, dragged like the bandwidth edges, green while the signal is above it and amber while it gates. Arrow keys move it a dB at a time for anyone not using a mouse. The audio row keeps a compact version: the dB, an indicator lit from the same meter the DSP compares against, Auto, and an enable toggle that no longer doubles as the level. The slider ran 0-100% over that dB range, which gave the operator a number with nothing on screen to relate it to, and zero meant "disabled", so turning the squelch off to listen threw the threshold away. Auto now says which level it picked. Two things the browser could only show once it was on the plot: the grip landed underneath the split control at the right edge, which swallowed its pointer, and dragging to the foot of the axis hid the line — and the grip with it — instead of pinning it where it could be dragged back. The fixture could not exercise any of this: /audio answered 404, which hides the audio row and the control inside it, and the status carried no filter block, which is what tells the client the rig has a squelch at all. Both now look like an SDR, and the spectrum test drives the line. Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -12,7 +12,7 @@ import assert from "node:assert/strict";
|
||||
import { chromium } from "playwright-core";
|
||||
import { startBrowser, startWebFixture } from "./web-fixture.mjs";
|
||||
|
||||
/* global document */
|
||||
/* global document, getComputedStyle */
|
||||
|
||||
const BOOKMARKS = [
|
||||
{ id: "b1", name: "40m FT8", freq_hz: 7074000, mode: "DIG", category: "Digital", comment: "", locator: "" },
|
||||
@@ -120,6 +120,67 @@ try {
|
||||
assert.equal(hits.chip, "chip", `chip is not clickable, hit ${hits.chip}`);
|
||||
assert.equal(hits.besideChip, "overview-canvas", `rail swallows events, hit ${hits.besideChip}`);
|
||||
|
||||
// Squelch: the threshold is in the dB the spectrum axis is labelled in, so the
|
||||
// line is the control. It used to be a percentage on a slider in the audio
|
||||
// row, with nothing on screen to relate the number to.
|
||||
await page.locator("summary", { hasText: "Audio controls" }).click();
|
||||
await page.locator("#sdr-squelch-toggle").click();
|
||||
// Auto parks it just above the noise, which is mid-axis and leaves room to
|
||||
// drag in either direction.
|
||||
await page.locator("#sdr-squelch-auto").click();
|
||||
await page.waitForTimeout(300);
|
||||
const squelchOn = await page.evaluate(() => {
|
||||
const line = document.getElementById("spectrum-squelch-line");
|
||||
return {
|
||||
shown: getComputedStyle(line).display !== "none",
|
||||
db: Number(document.getElementById("sdr-squelch-db").value),
|
||||
label: Number(document.getElementById("spectrum-squelch-label").textContent),
|
||||
toggle: document.getElementById("sdr-squelch-toggle").textContent,
|
||||
top: Math.round(line.getBoundingClientRect().top),
|
||||
};
|
||||
});
|
||||
assert.equal(squelchOn.shown, true, "the threshold line did not appear with the squelch on");
|
||||
assert.equal(squelchOn.toggle, "On", "the toggle did not follow the squelch state");
|
||||
assert.equal(squelchOn.label, squelchOn.db, "the line and the readout disagree on the threshold");
|
||||
|
||||
// Dragging the line down lowers the threshold and tells the server.
|
||||
const submitted = [];
|
||||
page.on("request", (request) => {
|
||||
if (request.url().includes("/set_sdr_squelch")) {
|
||||
submitted.push(Number(new URL(request.url()).searchParams.get("threshold_db")));
|
||||
}
|
||||
});
|
||||
const grip = await page.locator("#spectrum-squelch-grip").boundingBox();
|
||||
await page.mouse.move(grip.x + grip.width / 2, grip.y + grip.height / 2);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(grip.x + grip.width / 2, grip.y + grip.height / 2 + 60, { steps: 8 });
|
||||
await page.mouse.up();
|
||||
await page.waitForTimeout(400);
|
||||
const dragged = await page.evaluate(() => ({
|
||||
db: Number(document.getElementById("sdr-squelch-db").value),
|
||||
label: Number(document.getElementById("spectrum-squelch-label").textContent),
|
||||
top: Math.round(document.getElementById("spectrum-squelch-line").getBoundingClientRect().top),
|
||||
}));
|
||||
assert.ok(dragged.db < squelchOn.db,
|
||||
`dragging down left the threshold at ${dragged.db} dB (was ${squelchOn.db})`);
|
||||
assert.equal(dragged.label, dragged.db, "the line label did not follow the drag");
|
||||
assert.ok(dragged.top > squelchOn.top, "the line did not move with the drag");
|
||||
assert.ok(submitted.includes(dragged.db),
|
||||
`the server was never told about ${dragged.db} dB (saw ${JSON.stringify(submitted)})`);
|
||||
|
||||
// Turning it off leaves the threshold alone — the old control conflated the
|
||||
// two, so dropping to zero to listen threw the setting away.
|
||||
await page.locator("#sdr-squelch-toggle").click();
|
||||
await page.waitForTimeout(300);
|
||||
const squelchOff = await page.evaluate(() => ({
|
||||
db: Number(document.getElementById("sdr-squelch-db").value),
|
||||
shown: getComputedStyle(document.getElementById("spectrum-squelch-line")).display !== "none",
|
||||
dot: document.getElementById("sdr-squelch-state").dataset.state,
|
||||
}));
|
||||
assert.equal(squelchOff.db, dragged.db, "turning the squelch off discarded the threshold");
|
||||
assert.equal(squelchOff.shown, false, "the line stayed up with the squelch off");
|
||||
assert.equal(squelchOff.dot, "off", "the indicator did not follow the squelch off");
|
||||
|
||||
assert.deepEqual(runtimeErrors, []);
|
||||
} finally {
|
||||
await browser.close();
|
||||
|
||||
@@ -111,7 +111,17 @@ export async function startWebFixture({
|
||||
signal_meter: spectrum,
|
||||
},
|
||||
},
|
||||
status: { freq: { hz: 100_000_000 }, mode: "FM", tx_en: false, vfo: null, tx: null, rx: null, lock: null },
|
||||
status: { freq: { hz: 100_000_000 }, mode: "FM", tx_en: false, vfo: null, tx: null, rx: { sig: -70 }, lock: null },
|
||||
// Reported only by SDR backends, and what makes the client show the
|
||||
// squelch control at all.
|
||||
filter: spectrum
|
||||
? {
|
||||
bandwidth_hz: 12_000,
|
||||
sdr_squelch_enabled: false,
|
||||
sdr_squelch_threshold_db: -95,
|
||||
sdr_agc_enabled: false,
|
||||
}
|
||||
: null,
|
||||
band: null,
|
||||
enabled: true,
|
||||
initialized: true,
|
||||
@@ -184,8 +194,11 @@ export async function startWebFixture({
|
||||
response.end(JSON.stringify(jsonRoutes.get(url.pathname)));
|
||||
return;
|
||||
}
|
||||
// 200 means "audio is configured": the client hides the whole audio row —
|
||||
// and the squelch control with it — when this 404s.
|
||||
if (url.pathname === "/audio") {
|
||||
response.writeHead(404).end();
|
||||
response.writeHead(200, { "content-type": "application/json" });
|
||||
response.end(JSON.stringify({ sample_rate: 48_000, channels: 1 }));
|
||||
return;
|
||||
}
|
||||
if (spectrum && url.pathname === "/spectrum") {
|
||||
|
||||
Reference in New Issue
Block a user