[feat](trx-rs): add VDES hard-decision FEC stage
Improve the VDES decoder with sync/rotation metadata and a first hard-decision rate-1/2 Viterbi stage after deinterleaving, then surface the extra lock state in the VDES frontend. Also fix the strict clippy findings in AIS, frontend bookmarks, and the server audio stack signature. Co-authored-by: OpenAI Codex <codex@openai.com> Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
This commit is contained in:
@@ -79,8 +79,23 @@ function renderVdesRow(msg) {
|
||||
const title = msg.vessel_name || "VDES Burst";
|
||||
const label = msg.callsign || "VDES";
|
||||
const info = msg.destination || "";
|
||||
const linkText = Number.isFinite(msg.link_id) ? `LID ${msg.link_id}` : "";
|
||||
const syncText = Number.isFinite(msg.sync_score) ? `Sync ${(Number(msg.sync_score) * 100).toFixed(0)}%` : "";
|
||||
const phaseText = Number.isFinite(msg.phase_rotation) ? `R${Number(msg.phase_rotation)}` : "";
|
||||
const fecText = msg.fec_state || "";
|
||||
const rawHex = vdesHexPreview(msg.raw_bytes);
|
||||
row.dataset.filterText = [title, label, info, rawHex, msg.message_type, msg.bit_len]
|
||||
row.dataset.filterText = [
|
||||
title,
|
||||
label,
|
||||
info,
|
||||
linkText,
|
||||
syncText,
|
||||
phaseText,
|
||||
fecText,
|
||||
rawHex,
|
||||
msg.message_type,
|
||||
msg.bit_len,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ")
|
||||
.toUpperCase();
|
||||
@@ -89,12 +104,16 @@ function renderVdesRow(msg) {
|
||||
`<span class="vdes-time">${ts}</span>` +
|
||||
`<span class="vdes-call">${escapeMapHtml(title)}</span>` +
|
||||
`<span class="vdes-badge">${escapeMapHtml(label)}</span>` +
|
||||
(linkText ? `<span class="vdes-badge">${escapeMapHtml(linkText)}</span>` : "") +
|
||||
(syncText ? `<span class="vdes-badge">${escapeMapHtml(syncText)}</span>` : "") +
|
||||
(phaseText ? `<span class="vdes-badge">${escapeMapHtml(phaseText)}</span>` : "") +
|
||||
`<span class="vdes-badge">T${escapeMapHtml(String(msg.message_type ?? "--"))}</span>` +
|
||||
`</div>` +
|
||||
`<div class="vdes-row-meta">` +
|
||||
`<span>${escapeMapHtml(currentVdesCenterText())}</span>` +
|
||||
`<span>${escapeMapHtml(`${msg.bit_len || 0} bits`)}</span>` +
|
||||
(info ? `<span>${escapeMapHtml(info)}</span>` : "") +
|
||||
(fecText ? `<span>${escapeMapHtml(fecText)}</span>` : "") +
|
||||
`<span>${escapeMapHtml(vdesAgeText(msg._tsMs))}</span>` +
|
||||
`</div>` +
|
||||
`<div class="vdes-row-detail">` +
|
||||
@@ -123,6 +142,9 @@ function updateVdesBar() {
|
||||
const title = escapeMapHtml(msg.vessel_name || "Burst");
|
||||
const detail = [
|
||||
`${msg.bit_len || 0} bits`,
|
||||
Number.isFinite(msg.link_id) ? `LID ${Number(msg.link_id)}` : null,
|
||||
Number.isFinite(msg.sync_score) ? `sync ${(Number(msg.sync_score) * 100).toFixed(0)}%` : null,
|
||||
Number.isFinite(msg.phase_rotation) ? `rot ${Number(msg.phase_rotation)}` : null,
|
||||
msg.destination ? escapeMapHtml(msg.destination) : null,
|
||||
escapeMapHtml(vdesAgeText(msg._tsMs)),
|
||||
]
|
||||
@@ -193,6 +215,11 @@ window.onServerVdes = function(msg) {
|
||||
vessel_name: msg.vessel_name,
|
||||
callsign: msg.callsign,
|
||||
destination: msg.destination,
|
||||
link_id: msg.link_id,
|
||||
sync_score: msg.sync_score,
|
||||
sync_errors: msg.sync_errors,
|
||||
phase_rotation: msg.phase_rotation,
|
||||
fec_state: msg.fec_state,
|
||||
ts_ms: msg.ts_ms,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -95,7 +95,7 @@ impl BookmarkStore {
|
||||
/// Returns true if any bookmark (other than `exclude_id`) has `freq_hz`.
|
||||
pub fn freq_taken(&self, freq_hz: u64, exclude_id: Option<&str>) -> bool {
|
||||
self.list().into_iter().any(|bm| {
|
||||
bm.freq_hz == freq_hz && exclude_id.map_or(true, |ex| bm.id != ex)
|
||||
bm.freq_hz == freq_hz && exclude_id.is_none_or(|ex| bm.id != ex)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user