113 lines
3.8 KiB
JavaScript
113 lines
3.8 KiB
JavaScript
// src/plugins/aprs-shared.ts
|
|
function aprsPacketCategory(packet) {
|
|
const type = (packet.type ?? "").toLowerCase();
|
|
const info = (packet.info ?? "").toLowerCase();
|
|
if (packet.lat != null && packet.lon != null || type.includes("position")) return "position";
|
|
if (type.includes("message") || info.startsWith(":")) return "message";
|
|
if (type.includes("weather") || info.startsWith("_")) return "weather";
|
|
if (type.includes("telemetry") || info.startsWith("t#")) return "telemetry";
|
|
return "other";
|
|
}
|
|
function aprsCategoryLabel(category) {
|
|
switch (category) {
|
|
case "position":
|
|
return "Position";
|
|
case "message":
|
|
return "Message";
|
|
case "weather":
|
|
return "Weather";
|
|
case "telemetry":
|
|
return "Telemetry";
|
|
default:
|
|
return "Other";
|
|
}
|
|
}
|
|
function aprsAgeText(timestampMs) {
|
|
if (typeof timestampMs !== "number" || !Number.isFinite(timestampMs)) return "just now";
|
|
const seconds = Math.round(Math.max(0, Date.now() - timestampMs) / 1e3);
|
|
if (seconds < 5) return "just now";
|
|
if (seconds < 60) return `${String(seconds)}s ago`;
|
|
const minutes = Math.round(seconds / 60);
|
|
if (minutes < 60) return `${String(minutes)}m ago`;
|
|
return `${String(Math.round(minutes / 60))}h ago`;
|
|
}
|
|
function aprsPacketSignature(packet) {
|
|
return [
|
|
packet.srcCall ?? "",
|
|
packet.destCall ?? "",
|
|
packet.path ?? "",
|
|
packet.info ?? "",
|
|
packet.type ?? "",
|
|
packet.lat?.toFixed(4) ?? "",
|
|
packet.lon?.toFixed(4) ?? ""
|
|
].join("|");
|
|
}
|
|
function collapseAprsDuplicates(packets) {
|
|
const seen = /* @__PURE__ */ new Set();
|
|
return packets.filter((packet) => {
|
|
const signature = aprsPacketSignature(packet);
|
|
if (seen.has(signature)) return false;
|
|
seen.add(signature);
|
|
return true;
|
|
});
|
|
}
|
|
function aprsHexBytes(bytes) {
|
|
if (!bytes?.length) return "--";
|
|
return bytes.map((byte) => byte.toString(16).toUpperCase().padStart(2, "0")).join(" ");
|
|
}
|
|
function renderAprsInfo(packet) {
|
|
if (packet.info_bytes?.length) {
|
|
return packet.info_bytes.map((byte) => renderAprsByte(byte)).join("");
|
|
}
|
|
return Array.from(packet.info ?? "", (character) => renderAprsCharacter(character)).join("");
|
|
}
|
|
function renderAprsByte(byte) {
|
|
return byte >= 32 && byte <= 126 ? escapeAprsCharacter(String.fromCharCode(byte)) : `<span class="aprs-byte">0x${byte.toString(16).toUpperCase().padStart(2, "0")}</span>`;
|
|
}
|
|
function renderAprsCharacter(character) {
|
|
const code = character.charCodeAt(0);
|
|
return code >= 32 && code <= 126 ? escapeAprsCharacter(character) : `<span class="aprs-byte">0x${code.toString(16).toUpperCase().padStart(2, "0")}</span>`;
|
|
}
|
|
function escapeAprsCharacter(character) {
|
|
if (character === "<") return "<";
|
|
if (character === ">") return ">";
|
|
if (character === "&") return "&";
|
|
if (character === '"') return """;
|
|
return character;
|
|
}
|
|
function renderLocalAprsSymbol(packet, escapeHtml) {
|
|
if (!packet.symbolTable || !packet.symbolCode) return "";
|
|
const symbol = escapeHtml(packet.symbolCode);
|
|
const table = packet.symbolTable === "/" ? "Primary" : "Alternate";
|
|
return `<span class="aprs-symbol aprs-symbol-local" title="${table} APRS symbol ${symbol}">${symbol}</span>`;
|
|
}
|
|
function normalizeAprsPacket(packet, receiver) {
|
|
return {
|
|
rig_id: packet.rig_id || null,
|
|
receiver,
|
|
srcCall: packet.src_call ?? "",
|
|
destCall: packet.dest_call ?? "",
|
|
path: packet.path ?? "",
|
|
info: packet.info ?? "",
|
|
info_bytes: packet.info_bytes ?? [],
|
|
type: packet.packet_type ?? "",
|
|
crcOk: packet.crc_ok ?? false,
|
|
ts_ms: packet.ts_ms ?? null,
|
|
lat: packet.lat ?? null,
|
|
lon: packet.lon ?? null,
|
|
symbolTable: packet.symbol_table ?? null,
|
|
symbolCode: packet.symbol_code ?? null
|
|
};
|
|
}
|
|
|
|
export {
|
|
aprsPacketCategory,
|
|
aprsCategoryLabel,
|
|
aprsAgeText,
|
|
collapseAprsDuplicates,
|
|
aprsHexBytes,
|
|
renderAprsInfo,
|
|
renderLocalAprsSymbol,
|
|
normalizeAprsPacket
|
|
};
|