Better parsing for extras; Added deviceID resolution

This commit is contained in:
2026-03-18 17:01:46 +01:00
parent be8cd00c00
commit 17caa22331
8 changed files with 1517 additions and 240 deletions

View File

@@ -3,8 +3,9 @@ import { describe, expect, it } from "vitest";
import { Frame } from "../src/frame";
import type { PositionPayload } from "../src/frame.types";
import { feetToMeters, milesToMeters } from "../src/parser";
describe("APRS extras test vectors (RNG / PHG / CSE/DDD / SPD / DFS)", () => {
describe("APRS extras test vectors", () => {
it("parses PHG from position with messaging (spec vector 1)", () => {
const raw = "NOCALL>APZRAZ,qAS,PA2RDK-14:=5154.19N/00627.77E>PHG500073 de NOCALL";
const frame = Frame.fromString(raw);
@@ -34,7 +35,7 @@ describe("APRS extras test vectors (RNG / PHG / CSE/DDD / SPD / DFS)", () => {
const commentSeg = structure.find((s) => /comment/i.test(String(s.name))) as Segment | undefined;
expect(commentSeg).toBeDefined();
const fields = (commentSeg!.fields ?? []) as Field[];
const hasPHG = fields.some((f) => f.name === "PHG");
const hasPHG = fields.some((f) => f.name === "PHG marker");
expect(hasPHG).toBe(true);
});
@@ -52,7 +53,7 @@ describe("APRS extras test vectors (RNG / PHG / CSE/DDD / SPD / DFS)", () => {
const commentSeg = structure.find((s) => /comment/i.test(String(s.name))) as Segment | undefined;
expect(commentSeg).toBeDefined();
const fieldsDFS = (commentSeg!.fields ?? []) as Field[];
const hasDFS = fieldsDFS.some((f) => f.name === "DFS");
const hasDFS = fieldsDFS.some((f) => f.name === "DFS marker");
expect(hasDFS).toBe(true);
});
@@ -72,12 +73,12 @@ describe("APRS extras test vectors (RNG / PHG / CSE/DDD / SPD / DFS)", () => {
const commentSeg = structure.find((s) => /comment/i.test(String(s.name))) as Segment | undefined;
expect(commentSeg).toBeDefined();
const fieldsCSE = (commentSeg!.fields ?? []) as Field[];
const hasCSE = fieldsCSE.some((f) => f.name === "CSE/SPD");
const hasCSE = fieldsCSE.some((f) => f.name === "course");
expect(hasCSE).toBe(true);
});
it("parses combined tokens: DDD/SSS PHG and DFS", () => {
const raw = "N0CALL>APRS,WIDE1-1:!4500.00N/07000.00W>090/045PHG5132/DFS2132";
const raw = "N0CALL>APRS,WIDE1-1:!4500.00N/07000.00W>090/045PHG5132DFS2132";
const frame = Frame.fromString(raw);
const res = frame.decode(true) as { payload: PositionPayload | null; structure: Dissected };
const { payload, structure } = res;
@@ -92,6 +93,24 @@ describe("APRS extras test vectors (RNG / PHG / CSE/DDD / SPD / DFS)", () => {
const commentSeg = structure.find((s) => /comment/i.test(String(s.name))) as Segment | undefined;
expect(commentSeg).toBeDefined();
const fieldsCombined = (commentSeg!.fields ?? []) as Field[];
expect(fieldsCombined.some((f) => ["CSE/SPD", "PHG", "DFS"].includes(String(f.name)))).toBe(true);
expect(fieldsCombined.some((f) => ["course", "PHG marker", "DFS marker"].includes(String(f.name)))).toBe(true);
});
it("parses RNG token and emits structure", () => {
const raw =
"NOCALL-S>APDG01,TCPIP*,qAC,NOCALL-GS:;DN9PJF B *181227z5148.38ND00634.32EaRNG0001/A=000010 70cm Voice (D-Star) 439.50000MHz -7.6000MHz";
const frame = Frame.fromString(raw);
const res = frame.decode(true) as { payload: PositionPayload | null; structure: Dissected };
const { payload, structure } = res;
expect(payload).not.toBeNull();
expect(payload!.position.altitude).toBeCloseTo(feetToMeters(10), 3);
expect(payload!.position.range).toBe(milesToMeters(1) / 1000);
const commentSeg = structure.find((s) => /comment/i.test(String(s.name))) as Segment | undefined;
expect(commentSeg).toBeDefined();
const fieldsRNG = (commentSeg!.fields ?? []) as Field[];
const hasRNG = fieldsRNG.some((f) => f.name === "RNG marker");
expect(hasRNG).toBe(true);
});
});