import { FieldType, type Segment } from "@hamradio/packet"; import { Frame } from "./frame"; import { DataType, type Payload, type ThirdPartyPayload, UserDefinedPayload } from "./frame.types"; export const decodeUserDefinedPayload = ( raw: string, withStructure: boolean = false ): { payload: Payload | null; segment?: Segment[]; } => { try { if (raw.length < 2) return { payload: null }; // content after '{' const rest = raw.substring(1); // user packet type is first token (up to first space) often like '01' or 'TYP' const match = rest.match(/^([^\s]+)\s*(.*)$/s); let userPacketType = ""; let data = ""; if (match) { userPacketType = match[1] || ""; data = (match[2] || "").trim(); } const payload: UserDefinedPayload = { type: DataType.UserDefined, userPacketType, data } as const; if (withStructure) { const segments: Segment[] = []; segments.push({ name: "user-defined", data: new TextEncoder().encode(rest).buffer, isString: true, fields: [{ type: FieldType.STRING, name: "raw", length: rest.length }] }); segments.push({ name: "user-packet-type", data: new TextEncoder().encode(userPacketType).buffer, isString: true, fields: [ { type: FieldType.STRING, name: "type", length: userPacketType.length } ] }); segments.push({ name: "user-data", data: new TextEncoder().encode(data).buffer, isString: true, fields: [{ type: FieldType.STRING, name: "data", length: data.length }] }); return { payload, segment: segments }; } return { payload }; } catch { return { payload: null }; } }; export const decodeThirdPartyPayload = ( raw: string, withStructure: boolean = false ): { payload: Payload | null; segment?: Segment[]; } => { try { if (raw.length < 2) return { payload: null }; // Content after '}' is the encapsulated third-party frame or raw data const rest = raw.substring(1); // Attempt to parse the embedded text as a full APRS frame (route:payload) let nestedFrame: Frame | undefined; try { // parseFrame is defined in this module; use Frame.parse to attempt parse nestedFrame = Frame.parse(rest); } catch { nestedFrame = undefined; } const payload: ThirdPartyPayload = { type: DataType.ThirdParty, comment: rest, ...(nestedFrame ? { frame: nestedFrame } : {}) } as const; if (withStructure) { const segments: Segment[] = []; segments.push({ name: "third-party", data: new TextEncoder().encode(rest).buffer, isString: true, fields: [{ type: FieldType.STRING, name: "raw", length: rest.length }] }); if (nestedFrame) { // Include a short section pointing to the nested frame's data (stringified) const nf = nestedFrame; const nfStr = `${nf.source.toString()}>${nf.destination.toString()}:${nf.payload}`; segments.push({ name: "third-party-nested-frame", data: new TextEncoder().encode(nfStr).buffer, isString: true, fields: [ { type: FieldType.STRING, name: "nested", length: nfStr.length } ] }); } return { payload, segment: segments }; } return { payload }; } catch { return { payload: null }; } };