Major change: switched to DataType enum
This commit is contained in:
137
src/frame.ts
137
src/frame.ts
@@ -1,26 +1,28 @@
|
||||
import type { Dissected, Segment, Field } from "@hamradio/packet";
|
||||
import { FieldType } from "@hamradio/packet";
|
||||
import type {
|
||||
IAddress,
|
||||
IFrame,
|
||||
Payload,
|
||||
ITimestamp,
|
||||
PositionPayload,
|
||||
MessagePayload,
|
||||
IPosition,
|
||||
ObjectPayload,
|
||||
ItemPayload,
|
||||
StatusPayload,
|
||||
QueryPayload,
|
||||
TelemetryDataPayload,
|
||||
TelemetryBitSensePayload,
|
||||
TelemetryCoefficientsPayload,
|
||||
TelemetryParameterPayload,
|
||||
TelemetryUnitPayload,
|
||||
WeatherPayload,
|
||||
RawGPSPayload,
|
||||
StationCapabilitiesPayload,
|
||||
ThirdPartyPayload,
|
||||
import {
|
||||
type IAddress,
|
||||
type IFrame,
|
||||
type Payload,
|
||||
type ITimestamp,
|
||||
type PositionPayload,
|
||||
type MessagePayload,
|
||||
type IPosition,
|
||||
type ObjectPayload,
|
||||
type ItemPayload,
|
||||
type StatusPayload,
|
||||
type QueryPayload,
|
||||
type TelemetryDataPayload,
|
||||
type TelemetryBitSensePayload,
|
||||
type TelemetryCoefficientsPayload,
|
||||
type TelemetryParameterPayload,
|
||||
type TelemetryUnitPayload,
|
||||
type WeatherPayload,
|
||||
type RawGPSPayload,
|
||||
type StationCapabilitiesPayload,
|
||||
type ThirdPartyPayload,
|
||||
DataType,
|
||||
MicEPayload,
|
||||
} from "./frame.types";
|
||||
import { Position } from "./position";
|
||||
import { base91ToNumber } from "./parser";
|
||||
@@ -498,8 +500,30 @@ export class Frame implements IFrame {
|
||||
}
|
||||
}
|
||||
|
||||
let payloadType:
|
||||
| DataType.PositionNoTimestampNoMessaging
|
||||
| DataType.PositionNoTimestampWithMessaging
|
||||
| DataType.PositionWithTimestampNoMessaging
|
||||
| DataType.PositionWithTimestampWithMessaging;
|
||||
switch (dataType) {
|
||||
case "!":
|
||||
payloadType = DataType.PositionNoTimestampNoMessaging;
|
||||
break;
|
||||
case "=":
|
||||
payloadType = DataType.PositionNoTimestampWithMessaging;
|
||||
break;
|
||||
case "/":
|
||||
payloadType = DataType.PositionWithTimestampNoMessaging;
|
||||
break;
|
||||
case "@":
|
||||
payloadType = DataType.PositionWithTimestampWithMessaging;
|
||||
break;
|
||||
default:
|
||||
return { payload: null };
|
||||
}
|
||||
|
||||
const payload: PositionPayload = {
|
||||
type: "position",
|
||||
type: payloadType,
|
||||
timestamp,
|
||||
position,
|
||||
messaging,
|
||||
@@ -897,8 +921,20 @@ export class Frame implements IFrame {
|
||||
}
|
||||
}
|
||||
|
||||
const result: PositionPayload = {
|
||||
type: "position",
|
||||
let payloadType: DataType.MicECurrent | DataType.MicEOld;
|
||||
switch (this.payload.charAt(0)) {
|
||||
case "`":
|
||||
payloadType = DataType.MicECurrent;
|
||||
break;
|
||||
case "'":
|
||||
payloadType = DataType.MicEOld;
|
||||
break;
|
||||
default:
|
||||
return { payload: null };
|
||||
}
|
||||
|
||||
const result: MicEPayload = {
|
||||
type: payloadType,
|
||||
position: {
|
||||
latitude,
|
||||
longitude,
|
||||
@@ -907,11 +943,8 @@ export class Frame implements IFrame {
|
||||
code: symbolCode,
|
||||
},
|
||||
},
|
||||
messaging: true, // Mic-E is always messaging-capable
|
||||
micE: {
|
||||
messageType,
|
||||
isStandard,
|
||||
},
|
||||
messageType,
|
||||
isStandard,
|
||||
};
|
||||
|
||||
if (speed > 0) {
|
||||
@@ -1133,6 +1166,13 @@ export class Frame implements IFrame {
|
||||
text = this.payload.substring(textStart + 1);
|
||||
}
|
||||
|
||||
const payload: MessagePayload = {
|
||||
type: DataType.Message,
|
||||
variant: "message",
|
||||
addressee: recipient,
|
||||
text,
|
||||
};
|
||||
|
||||
if (withStructure) {
|
||||
// Emit text section
|
||||
segments.push({
|
||||
@@ -1142,21 +1182,9 @@ export class Frame implements IFrame {
|
||||
fields: [{ type: FieldType.STRING, name: "text", length: text.length }],
|
||||
});
|
||||
|
||||
const payload: MessagePayload = {
|
||||
type: "message",
|
||||
addressee: recipient,
|
||||
text,
|
||||
};
|
||||
|
||||
return { payload, segment: segments };
|
||||
}
|
||||
|
||||
const payload: MessagePayload = {
|
||||
type: "message",
|
||||
addressee: recipient,
|
||||
text,
|
||||
};
|
||||
|
||||
return { payload };
|
||||
}
|
||||
|
||||
@@ -1285,7 +1313,7 @@ export class Frame implements IFrame {
|
||||
}
|
||||
|
||||
const payload: ObjectPayload = {
|
||||
type: "object",
|
||||
type: DataType.Object,
|
||||
name,
|
||||
timestamp,
|
||||
alive,
|
||||
@@ -1420,7 +1448,7 @@ export class Frame implements IFrame {
|
||||
}
|
||||
|
||||
const payload: ItemPayload = {
|
||||
type: "item",
|
||||
type: DataType.Item,
|
||||
name,
|
||||
alive,
|
||||
position,
|
||||
@@ -1472,7 +1500,7 @@ export class Frame implements IFrame {
|
||||
}
|
||||
|
||||
const payload: StatusPayload = {
|
||||
type: "status",
|
||||
type: DataType.Status,
|
||||
timestamp: undefined,
|
||||
text: statusText,
|
||||
};
|
||||
@@ -1557,7 +1585,7 @@ export class Frame implements IFrame {
|
||||
}
|
||||
|
||||
const payload: QueryPayload = {
|
||||
type: "query",
|
||||
type: DataType.Query,
|
||||
queryType,
|
||||
...(target ? { target } : {}),
|
||||
};
|
||||
@@ -1639,7 +1667,8 @@ export class Frame implements IFrame {
|
||||
}
|
||||
|
||||
const payload: TelemetryDataPayload = {
|
||||
type: "telemetry-data",
|
||||
type: DataType.TelemetryData,
|
||||
variant: "data",
|
||||
sequence: isNaN(seq) ? 0 : seq,
|
||||
analog,
|
||||
digital: isNaN(digital) ? 0 : digital,
|
||||
@@ -1664,7 +1693,8 @@ export class Frame implements IFrame {
|
||||
});
|
||||
}
|
||||
const payload: TelemetryParameterPayload = {
|
||||
type: "telemetry-parameters",
|
||||
type: DataType.TelemetryData,
|
||||
variant: "parameters",
|
||||
names,
|
||||
};
|
||||
if (withStructure) return { payload, segment: segments };
|
||||
@@ -1686,7 +1716,8 @@ export class Frame implements IFrame {
|
||||
});
|
||||
}
|
||||
const payload: TelemetryUnitPayload = {
|
||||
type: "telemetry-units",
|
||||
type: DataType.TelemetryData,
|
||||
variant: "unit",
|
||||
units,
|
||||
};
|
||||
if (withStructure) return { payload, segment: segments };
|
||||
@@ -1717,7 +1748,8 @@ export class Frame implements IFrame {
|
||||
});
|
||||
}
|
||||
const payload: TelemetryCoefficientsPayload = {
|
||||
type: "telemetry-coefficients",
|
||||
type: DataType.TelemetryData,
|
||||
variant: "coefficients",
|
||||
coefficients,
|
||||
};
|
||||
if (withStructure) return { payload, segment: segments };
|
||||
@@ -1741,7 +1773,8 @@ export class Frame implements IFrame {
|
||||
});
|
||||
}
|
||||
const payload: TelemetryBitSensePayload = {
|
||||
type: "telemetry-bitsense",
|
||||
type: DataType.TelemetryData,
|
||||
variant: "bitsense",
|
||||
sense: isNaN(sense) ? 0 : sense,
|
||||
...(projectName ? { projectName } : {}),
|
||||
};
|
||||
@@ -1818,7 +1851,9 @@ export class Frame implements IFrame {
|
||||
|
||||
const rest = this.payload.substring(offset).trim();
|
||||
|
||||
const payload: WeatherPayload = { type: "weather" };
|
||||
const payload: WeatherPayload = {
|
||||
type: DataType.WeatherReportNoPosition,
|
||||
};
|
||||
if (timestamp) payload.timestamp = timestamp;
|
||||
if (position) payload.position = position;
|
||||
|
||||
|
||||
@@ -14,54 +14,51 @@ export interface IFrame {
|
||||
}
|
||||
|
||||
// APRS Data Type Identifiers (first character of payload)
|
||||
export const DataTypeIdentifier = {
|
||||
export enum DataType {
|
||||
// Position Reports
|
||||
PositionNoTimestampNoMessaging: "!",
|
||||
PositionNoTimestampWithMessaging: "=",
|
||||
PositionWithTimestampNoMessaging: "/",
|
||||
PositionWithTimestampWithMessaging: "@",
|
||||
PositionNoTimestampNoMessaging = "!",
|
||||
PositionNoTimestampWithMessaging = "=",
|
||||
PositionWithTimestampNoMessaging = "/",
|
||||
PositionWithTimestampWithMessaging = "@",
|
||||
|
||||
// Mic-E
|
||||
MicECurrent: "`",
|
||||
MicEOld: "'",
|
||||
MicECurrent = "`",
|
||||
MicEOld = "'",
|
||||
|
||||
// Messages and Bulletins
|
||||
Message: ":",
|
||||
Message = ":",
|
||||
|
||||
// Objects and Items
|
||||
Object: ";",
|
||||
Item: ")",
|
||||
Object = ";",
|
||||
Item = ")",
|
||||
|
||||
// Status
|
||||
Status: ">",
|
||||
Status = ">",
|
||||
|
||||
// Query
|
||||
Query: "?",
|
||||
Query = "?",
|
||||
|
||||
// Telemetry
|
||||
TelemetryData: "T",
|
||||
TelemetryData = "T",
|
||||
|
||||
// Weather
|
||||
WeatherReportNoPosition: "_",
|
||||
WeatherReportNoPosition = "_",
|
||||
|
||||
// Raw GPS Data
|
||||
RawGPS: "$",
|
||||
RawGPS = "$",
|
||||
|
||||
// Station Capabilities
|
||||
StationCapabilities: "<",
|
||||
StationCapabilities = "<",
|
||||
|
||||
// User-Defined
|
||||
UserDefined: "{",
|
||||
UserDefined = "{",
|
||||
|
||||
// Third-Party Traffic
|
||||
ThirdParty: "}",
|
||||
ThirdParty = "}",
|
||||
|
||||
// Invalid/Test Data
|
||||
InvalidOrTest: ",",
|
||||
} as const;
|
||||
|
||||
export type DataTypeIdentifier =
|
||||
(typeof DataTypeIdentifier)[keyof typeof DataTypeIdentifier];
|
||||
InvalidOrTest = ",",
|
||||
}
|
||||
|
||||
export interface ISymbol {
|
||||
table: string; // Symbol table identifier
|
||||
@@ -99,7 +96,11 @@ export interface ITimestamp {
|
||||
|
||||
// Position Report Payload
|
||||
export interface PositionPayload {
|
||||
type: "position";
|
||||
type:
|
||||
| DataType.PositionNoTimestampNoMessaging
|
||||
| DataType.PositionNoTimestampWithMessaging
|
||||
| DataType.PositionWithTimestampNoMessaging
|
||||
| DataType.PositionWithTimestampWithMessaging;
|
||||
timestamp?: ITimestamp;
|
||||
position: IPosition;
|
||||
messaging: boolean; // Whether APRS messaging is enabled
|
||||
@@ -128,19 +129,20 @@ export interface CompressedPosition {
|
||||
|
||||
// Mic-E Payload (compressed in destination address)
|
||||
export interface MicEPayload {
|
||||
type: "mic-e";
|
||||
type: DataType.MicECurrent | DataType.MicEOld;
|
||||
position: IPosition;
|
||||
course?: number;
|
||||
speed?: number;
|
||||
altitude?: number;
|
||||
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: "message";
|
||||
type: DataType.Message;
|
||||
variant: "message";
|
||||
addressee: string; // 9 character padded callsign
|
||||
text: string; // Message text
|
||||
messageNumber?: string; // Message ID for acknowledgment
|
||||
@@ -150,7 +152,8 @@ export interface MessagePayload {
|
||||
|
||||
// Bulletin/Announcement (variant of message)
|
||||
export interface BulletinPayload {
|
||||
type: "bulletin";
|
||||
type: DataType.Message;
|
||||
variant: "bulletin";
|
||||
bulletinId: string; // Bulletin identifier (BLN#)
|
||||
text: string;
|
||||
group?: string; // Optional group bulletin
|
||||
@@ -158,7 +161,7 @@ export interface BulletinPayload {
|
||||
|
||||
// Object Payload
|
||||
export interface ObjectPayload {
|
||||
type: "object";
|
||||
type: DataType.Object;
|
||||
name: string; // 9 character object name
|
||||
timestamp: ITimestamp;
|
||||
alive: boolean; // True if object is active, false if killed
|
||||
@@ -169,7 +172,7 @@ export interface ObjectPayload {
|
||||
|
||||
// Item Payload
|
||||
export interface ItemPayload {
|
||||
type: "item";
|
||||
type: DataType.Item;
|
||||
name: string; // 3-9 character item name
|
||||
alive: boolean; // True if item is active, false if killed
|
||||
position: IPosition;
|
||||
@@ -177,7 +180,7 @@ export interface ItemPayload {
|
||||
|
||||
// Status Payload
|
||||
export interface StatusPayload {
|
||||
type: "status";
|
||||
type: DataType.Status;
|
||||
timestamp?: ITimestamp;
|
||||
text: string;
|
||||
maidenhead?: string; // Optional Maidenhead grid locator
|
||||
@@ -189,14 +192,22 @@ export interface StatusPayload {
|
||||
|
||||
// Query Payload
|
||||
export interface QueryPayload {
|
||||
type: "query";
|
||||
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: "telemetry-data";
|
||||
type: DataType.TelemetryData;
|
||||
variant: "data";
|
||||
sequence: number;
|
||||
analog: number[]; // Up to 5 analog channels
|
||||
digital: number; // 8-bit digital value
|
||||
@@ -204,19 +215,22 @@ export interface TelemetryDataPayload {
|
||||
|
||||
// Telemetry Parameter Names
|
||||
export interface TelemetryParameterPayload {
|
||||
type: "telemetry-parameters";
|
||||
type: DataType.TelemetryData;
|
||||
variant: "parameters";
|
||||
names: string[]; // Parameter names
|
||||
}
|
||||
|
||||
// Telemetry Unit/Label
|
||||
export interface TelemetryUnitPayload {
|
||||
type: "telemetry-units";
|
||||
type: DataType.TelemetryData;
|
||||
variant: "unit";
|
||||
units: string[]; // Units for each parameter
|
||||
}
|
||||
|
||||
// Telemetry Coefficients
|
||||
export interface TelemetryCoefficientsPayload {
|
||||
type: "telemetry-coefficients";
|
||||
type: DataType.TelemetryData;
|
||||
variant: "coefficients";
|
||||
coefficients: {
|
||||
a: number[]; // a coefficients
|
||||
b: number[]; // b coefficients
|
||||
@@ -226,14 +240,15 @@ export interface TelemetryCoefficientsPayload {
|
||||
|
||||
// Telemetry Bit Sense/Project Name
|
||||
export interface TelemetryBitSensePayload {
|
||||
type: "telemetry-bitsense";
|
||||
type: DataType.TelemetryData;
|
||||
variant: "bitsense";
|
||||
sense: number; // 8-bit sense value
|
||||
projectName?: string;
|
||||
}
|
||||
|
||||
// Weather Report Payload
|
||||
export interface WeatherPayload {
|
||||
type: "weather";
|
||||
type: DataType.WeatherReportNoPosition;
|
||||
timestamp?: ITimestamp;
|
||||
position?: IPosition;
|
||||
windDirection?: number; // Degrees
|
||||
@@ -255,34 +270,33 @@ export interface WeatherPayload {
|
||||
|
||||
// Raw GPS Payload (NMEA sentences)
|
||||
export interface RawGPSPayload {
|
||||
type: "raw-gps";
|
||||
type: DataType.RawGPS;
|
||||
sentence: string; // Raw NMEA sentence
|
||||
position?: IPosition; // Optional parsed position if available
|
||||
}
|
||||
|
||||
// Station Capabilities Payload
|
||||
export interface StationCapabilitiesPayload {
|
||||
type: "capabilities";
|
||||
type: DataType.StationCapabilities;
|
||||
capabilities: string[];
|
||||
}
|
||||
|
||||
// User-Defined Payload
|
||||
export interface UserDefinedPayload {
|
||||
type: "user-defined";
|
||||
type: DataType.UserDefined;
|
||||
userPacketType: string;
|
||||
data: string;
|
||||
}
|
||||
|
||||
// Third-Party Traffic Payload
|
||||
export interface ThirdPartyPayload {
|
||||
type: "third-party";
|
||||
type: DataType.ThirdParty;
|
||||
frame?: IFrame; // Optional nested frame if payload contains another APRS frame
|
||||
comment?: string; // Optional comment
|
||||
}
|
||||
|
||||
// DF Report Payload
|
||||
export interface DFReportPayload {
|
||||
type: "df-report";
|
||||
timestamp?: ITimestamp;
|
||||
position: IPosition;
|
||||
course?: number;
|
||||
@@ -295,7 +309,7 @@ export interface DFReportPayload {
|
||||
}
|
||||
|
||||
export interface BasePayload {
|
||||
type: string;
|
||||
type: DataType;
|
||||
}
|
||||
|
||||
// Union type for all decoded payload types
|
||||
@@ -319,7 +333,6 @@ export type Payload = BasePayload &
|
||||
| StationCapabilitiesPayload
|
||||
| UserDefinedPayload
|
||||
| ThirdPartyPayload
|
||||
| DFReportPayload
|
||||
);
|
||||
|
||||
// Extended Frame with decoded payload
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
export { Frame, Address, Timestamp } from "./frame";
|
||||
|
||||
export { type IAddress, type IFrame, DataTypeIdentifier } from "./frame.types";
|
||||
export {
|
||||
type IAddress,
|
||||
type IFrame,
|
||||
DataType as DataTypeIdentifier,
|
||||
} from "./frame.types";
|
||||
|
||||
export {
|
||||
DataType,
|
||||
type ISymbol,
|
||||
type IPosition,
|
||||
type ITimestamp,
|
||||
|
||||
Reference in New Issue
Block a user