import { Dissected, Field, Segment } from "@hamradio/packet"; // Any comment that contains this marker will set the doNotArchive flag on the // decoded payload, which can be used by applications to skip archiving or // logging frames that are meant to be transient or test data. This allows users // to include the marker in their APRS comments when they want to indicate that // a particular frame should not be stored long-term. export const DO_NOT_ARCHIVE_MARKER = "!x!"; export interface IAddress { call: string; ssid: string; isRepeated: boolean; } export interface IFrame { source: IAddress; destination: IAddress; path: IAddress[]; payload: string; } // APRS Data Type Identifiers (first character of payload) export enum DataType { // Position Reports PositionNoTimestampNoMessaging = "!", PositionNoTimestampWithMessaging = "=", PositionWithTimestampNoMessaging = "/", PositionWithTimestampWithMessaging = "@", // Mic-E MicE = "`", MicEOld = "'", // Messages and Bulletins Message = ":", // Objects and Items Object = ";", Item = ")", // Status Status = ">", // Query Query = "?", // Telemetry TelemetryData = "T", // Weather WeatherReportNoPosition = "_", // Raw GPS Data RawGPS = "$", // Station Capabilities StationCapabilities = "<", // User-Defined UserDefined = "{", // Third-Party Traffic ThirdParty = "}", // Invalid/Test Data InvalidOrTest = "," } export const DataTypeNames: { [key in DataType]: string } = { [DataType.PositionNoTimestampNoMessaging]: "position", [DataType.PositionNoTimestampWithMessaging]: "position with messaging", [DataType.PositionWithTimestampNoMessaging]: "position with timestamp", [DataType.PositionWithTimestampWithMessaging]: "position with timestamp and messaging", [DataType.MicE]: "Mic-E", [DataType.MicEOld]: "Mic-E (old)", [DataType.Message]: "message/bulletin", [DataType.Object]: "object", [DataType.Item]: "item", [DataType.Status]: "status", [DataType.Query]: "query", [DataType.TelemetryData]: "telemetry data", [DataType.WeatherReportNoPosition]: "weather report", [DataType.RawGPS]: "raw GPS data", [DataType.StationCapabilities]: "station capabilities", [DataType.UserDefined]: "user defined", [DataType.ThirdParty]: "third-party traffic", [DataType.InvalidOrTest]: "invalid/test" }; export interface ISymbol { table: string; // Symbol table identifier code: string; // Symbol code toString(): string; // Return combined symbol representation (e.g., "tablecode") } // Position data common to multiple formats export interface IPosition { latitude: number; // Decimal degrees longitude: number; // Decimal degrees ambiguity?: number; // Position ambiguity (0-4) altitude?: number; // Meters speed?: number; // Speed in km/h course?: number; // Course in degrees range?: number; // Kilometers phg?: IPowerHeightGain; dfs?: IDirectionFinding; dao?: IDAO; // Optional DAO fields for added position precision symbol?: ISymbol; comment?: string; toString(): string; // Return combined position representation (e.g., "lat,lon,alt") toCompressed?(): CompressedPosition; // Optional method to convert to compressed format distanceTo?(other: IPosition): number; // Optional method to calculate distance to another position } export interface ITimestamp { day?: number; // Day of month (DHM format) month?: number; // Month (MDHM format) hours: number; minutes: number; seconds?: number; format: "DHM" | "HMS" | "MDHM"; // Day-Hour-Minute, Hour-Minute-Second, Month-Day-Hour-Minute zulu?: boolean; // Is UTC/Zulu time toDate(): Date; // Convert to Date object respecting timezone } export interface IPowerHeightGain { power?: number; // Transmit power in watts height?: number; // Antenna height in meters gain?: number; // Antenna gain in dBi directivity?: number | "omni" | "unknown"; // Optional directivity pattern (numeric code or "omni") } export interface IDirectionFinding { bearing?: number; // Direction finding bearing in degrees strength?: number; // Relative signal strength (0-9) height?: number; // Antenna height in meters gain?: number; // Antenna gain in dBi quality?: number; // Signal quality or other metric (0-9) directivity?: number | "omni" | "unknown"; // Optional directivity pattern (numeric code or "omni") } export interface ITelemetry { sequence: number; analog: number[]; digital?: number; } export interface IDAO { datum_id?: string; // Geodetic datum identifier (e.g., "W84" for WGS84) resolution?: number; // DAO resolution (0-3) latitude?: number; // Added latitude precision longitude?: number; // Added longitude precision } // Position Report Payload export interface PositionPayload { type: | DataType.PositionNoTimestampNoMessaging | DataType.PositionNoTimestampWithMessaging | DataType.PositionWithTimestampNoMessaging | DataType.PositionWithTimestampWithMessaging; doNotArchive?: boolean; // Optional flag to indicate frame should not be archived timestamp?: ITimestamp; position: IPosition; messaging: boolean; // Whether APRS messaging is enabled dao?: IDAO; // Optional DAO fields for added position precision micE?: { messageType?: string; isStandard?: boolean; }; sections?: Segment[]; } // Compressed Position Format export interface CompressedPosition { latitude: number; longitude: number; symbol: { table: string; code: string; }; course?: number; // Degrees speed?: number; // Knots range?: number; // Miles altitude?: number; // Feet radioRange?: number; // Miles compression: "old" | "current"; } // Mic-E Payload (compressed in destination address) export interface MicEPayload { type: DataType.MicE | DataType.MicEOld; doNotArchive?: boolean; // Optional flag to indicate frame should not be archived position: IPosition; messageType?: string; // Standard Mic-E message isStandard?: boolean; // Whether messageType is a standard Mic-E message telemetry?: number[]; // Optional telemetry channels status?: string; } export type MessageVariant = "message" | "bulletin"; // Message Payload export interface MessagePayload { type: DataType.Message; variant: "message"; doNotArchive?: boolean; // Optional flag to indicate frame should not be archived addressee: string; // 9 character padded callsign text: string; // Message text messageNumber?: string; // Message ID for acknowledgment ack?: string; // Acknowledgment of message ID reject?: string; // Rejection of message ID } // Bulletin/Announcement (variant of message) export interface BulletinPayload { type: DataType.Message; variant: "bulletin"; doNotArchive?: boolean; // Optional flag to indicate frame should not be archived bulletinId: string; // Bulletin identifier (BLN#) text: string; group?: string; // Optional group bulletin } // Object Payload export interface ObjectPayload { type: DataType.Object; doNotArchive?: boolean; // Optional flag to indicate frame should not be archived name: string; // 9 character object name timestamp: ITimestamp; alive: boolean; // True if object is active, false if killed position: IPosition; dao?: IDAO; // Optional DAO fields for added position precision course?: number; speed?: number; } // Item Payload export interface ItemPayload { type: DataType.Item; doNotArchive?: boolean; // Optional flag to indicate frame should not be archived name: string; // 3-9 character item name alive: boolean; // True if item is active, false if killed position: IPosition; dao?: IDAO; // Optional DAO fields for added position precision } // Status Payload export interface StatusPayload { type: DataType.Status; doNotArchive?: boolean; // Optional flag to indicate frame should not be archived timestamp?: ITimestamp; text: string; maidenhead?: string; // Optional Maidenhead grid locator dao?: IDAO; // Optional DAO fields for added position precision symbol?: { table: string; code: string; }; } // Query Payload export interface QueryPayload { type: DataType.Query; queryType: string; // e.g., 'APRSD', 'APRST', 'PING' target?: string; // Target callsign or area } export type TelemetryVariant = "data" | "parameters" | "unit" | "coefficients" | "bitsense"; // Telemetry Data Payload export interface TelemetryDataPayload { type: DataType.TelemetryData; variant: "data"; sequence: number; analog: number[]; // Up to 5 analog channels digital: number; // 8-bit digital value } // Telemetry Parameter Names export interface TelemetryParameterPayload { type: DataType.TelemetryData; variant: "parameters"; names: string[]; // Parameter names } // Telemetry Unit/Label export interface TelemetryUnitPayload { type: DataType.TelemetryData; variant: "unit"; units: string[]; // Units for each parameter } // Telemetry Coefficients export interface TelemetryCoefficientsPayload { type: DataType.TelemetryData; variant: "coefficients"; coefficients: { a: number[]; // a coefficients b: number[]; // b coefficients c: number[]; // c coefficients }; } // Telemetry Bit Sense/Project Name export interface TelemetryBitSensePayload { type: DataType.TelemetryData; variant: "bitsense"; sense: number; // 8-bit sense value projectName?: string; } // Weather Report Payload export interface WeatherPayload { type: DataType.WeatherReportNoPosition; timestamp?: ITimestamp; position?: IPosition; dao?: IDAO; // Optional DAO fields for added position precision windDirection?: number; // Degrees windSpeed?: number; // MPH windGust?: number; // MPH temperature?: number; // Fahrenheit rainLastHour?: number; // Hundredths of inch rainLast24Hours?: number; // Hundredths of inch rainSinceMidnight?: number; // Hundredths of inch humidity?: number; // Percent pressure?: number; // Tenths of millibar luminosity?: number; // Watts per square meter snowfall?: number; // Inches rawRain?: number; // Raw rain counter software?: string; // Weather software type weatherUnit?: string; // Weather station type comment?: string; // Additional comment } // Raw GPS Payload (NMEA sentences) export interface RawGPSPayload { type: DataType.RawGPS; sentence: string; // Raw NMEA sentence position?: IPosition; // Optional parsed position if available } // Station Capabilities Payload export interface StationCapabilitiesPayload { type: DataType.StationCapabilities; capabilities: string[]; } // User-Defined Payload export interface UserDefinedPayload { type: DataType.UserDefined; userPacketType: string; data: string; } // Third-Party Traffic Payload export interface ThirdPartyPayload { type: DataType.ThirdParty; frame?: IFrame; // Optional nested frame if payload contains another APRS frame comment?: string; // Optional comment } // DF Report Payload export interface DFReportPayload { timestamp?: ITimestamp; position: IPosition; course?: number; bearing?: number; // Direction finding bearing quality?: number; // Signal quality strength?: number; // Signal strength height?: number; // Antenna height gain?: number; // Antenna gain directivity?: string; // Antenna directivity pattern } export interface BasePayload { type: DataType; doNotArchive?: boolean; // Optional flag to indicate frame should not be archived } // Union type for all decoded payload types export type Payload = BasePayload & ( | PositionPayload | MicEPayload | MessagePayload | BulletinPayload | ObjectPayload | ItemPayload | StatusPayload | QueryPayload | TelemetryDataPayload | TelemetryParameterPayload | TelemetryUnitPayload | TelemetryCoefficientsPayload | TelemetryBitSensePayload | WeatherPayload | RawGPSPayload | StationCapabilitiesPayload | UserDefinedPayload | ThirdPartyPayload ); // Extended Frame with decoded payload export interface DecodedFrame extends IFrame { decoded?: Payload; structure?: Dissected; // Routing and other frame-level sections } // Extras is an internal helper type used during decoding to accumulate additional // information that may not fit directly into the standard payload structure, // such as comments, calculated fields, or other metadata that can be useful for // applications consuming the decoded frames. export interface Extras { comment: string; altitude?: number; range?: number; phg?: IPowerHeightGain; dfs?: IDirectionFinding; cse?: number; spd?: number; fields?: Field[]; telemetry?: ITelemetry; dao?: IDAO; // Optional DAO fields for added position precision }