js-aprs-fap
Version:
NodeJs library for parsing APRS packets.
238 lines • 10 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PacketFactory = void 0;
const ConversionConstantEnum_1 = require("./ConversionConstantEnum");
const TimeFormatEnum_1 = require("./TimeFormatEnum");
const NmeaSourceEnum_1 = require("./NmeaSourceEnum");
const CompressionOriginEnum_1 = require("./CompressionOriginEnum");
class PacketFactory {
makeTimestamp(timestamp, timeFormat) {
let date;
if (timestamp == 0) {
date = new Date();
}
else {
date = new Date(timestamp);
}
switch (timeFormat) {
case TimeFormatEnum_1.TimeFormatEnum.DHM:
return String(date.getUTCDate()).padStart(2, "0")
+ String(date.getUTCHours()).padStart(2, "0")
+ String(date.getUTCMinutes()).padStart(2, "0")
+ 'z';
case TimeFormatEnum_1.TimeFormatEnum.HMS:
return String(date.getUTCHours()).padStart(2, "0")
+ String(date.getUTCMinutes()).padStart(2, "0")
+ String(date.getUTCSeconds()).padStart(2, "0")
+ "h";
default:
throw new Error("Unsupported time format.");
}
}
makePosition(data) {
let retVal = "";
try {
retVal = this.buildData(data);
}
catch (e) {
throw e;
}
if (data.timestamp && data.timestamp != null) {
if (data.isMessagingEnabled && data.isMessagingEnabled == true) {
retVal = `@${retVal}`;
}
else {
retVal = `/${retVal}`;
}
}
else {
if (data.isMessagingEnabled && data.isMessagingEnabled == true) {
retVal = `=${retVal}`;
}
else {
retVal = `!${retVal}`;
}
}
return retVal;
}
buildData(data) {
if (!data || data == null) {
throw new Error("No data provided.");
}
if (data.ambiguity && data.ambiguity != null && data.ambiguity != undefined) {
data.isUseDao = false;
}
if (!data.latitude || data.latitude == null || data.latitude < -89.99999 || data.latitude > 89.99999
|| !data.longitude || data.longitude == null || data.longitude < -179.99999 || data.longitude > 179.99999) {
throw new Error("Invalid location.");
}
let symbolTable = "";
let symbolCode = "";
if (data.symbols == null || data.symbols == "") {
symbolTable = "/";
symbolCode = "/";
}
else if (/^([\/\\A-Z0-9])([\x21-\x7b\x7d])$/.test(data.symbols)) {
[, symbolTable, symbolCode] = data.symbols.match(/^([\/\\A-Z0-9])([\x21-\x7b\x7d])$/);
}
else {
throw new Error("Invalid symbols.");
}
let retVal = "";
let latMinDao;
let lonMinDao;
if (data.isUseCompression == true) {
let lat = 380926 * (90 - data.latitude);
let lon = 190463 * (180 + data.longitude);
let latString = "";
let lonString = "";
for (let i = 3; i >= 0; i--) {
let value = Math.floor(lat / (91 ** i));
lat = lat % (91 ** i);
latString += String.fromCharCode(value + 33);
value = Math.floor(lon / (91 ** i));
lon = lon % (91 ** i);
lonString += String.fromCharCode(value + 33);
}
if (isNaN(Number(symbolTable)) == false) {
symbolTable = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"][Number(symbolTable)];
}
retVal = `${symbolTable}${latString}${lonString}${symbolCode}`;
if (data.speed != null && data.speed >= 0
&& data.course != null && data.course > 0 && data.course <= 360) {
let cVal = Math.floor((data.course + 2) / 4);
if (cVal > 89) {
cVal = 0;
}
retVal += String.fromCharCode(cVal + 33);
let speedNum = Math.floor((Math.log((data.speed / ConversionConstantEnum_1.ConversionConstantEnum.KNOT_TO_KMH) + 1) / Math.log(1.08)) + 0.5);
if (speedNum > 89) {
speedNum = 89;
}
retVal += String.fromCharCode(speedNum + 33);
}
else {
retVal += " ";
}
const compressionType = String.fromCharCode(parseInt("001" + NmeaSourceEnum_1.NmeaSourceEnum.OTHER + CompressionOriginEnum_1.CompressionOriginEnum.COMPRESSED, 2) + 33);
retVal += compressionType;
}
else {
let latDir = "N";
let lonDir = "E";
let latitude = data.latitude;
let longitude = data.longitude;
if (latitude && latitude != null && latitude < 0.0) {
latitude = latitude * -1;
latDir = "S";
}
let latDegrees = Math.floor(latitude);
let latMin = (latitude - latDegrees) * 60;
let latMinStr;
if (data.isUseDao != null && data.isUseDao == true) {
latMinStr = (latMin * 10000).toFixed(0).padStart(6, "0");
latMinDao = latMinStr.substring(4, 6);
}
else {
latMinStr = String((latMin * 100).toFixed(0)).padStart(4, "0");
}
if (/^60/.test(latMinStr)) {
latMinStr = "5999";
latMinDao = "99";
}
let latString = String(latDegrees).padStart(2, "0")
+ String(latMinStr).substring(0, 2).padStart(2, "0")
+ "."
+ String(latMinStr).substring(2, 4);
if (longitude && longitude != null && longitude < 0.0) {
longitude = longitude * -1;
lonDir = "W";
}
let lonDegrees = Math.floor(longitude);
let lonMin = (longitude - lonDegrees) * 60;
let lonMinStr;
if (data.isUseDao != null && data.isUseDao == true) {
lonMinStr = String((lonMin * 10000).toFixed(0)).padStart(6, "0");
lonMinDao = lonMinStr.substring(4, 6);
}
else {
lonMinStr = String((lonMin * 100).toFixed(0)).padStart(4, "0");
}
if (/^60/.test(lonMinStr)) {
lonMinStr = "5999";
lonMinDao = "99";
}
let lonString = `${String(lonDegrees).padStart(3, "0")}${String(lonMinStr).substring(0, 2)}.${String(lonMinStr).substring(2, 4)}`;
if (data.ambiguity && data.ambiguity > 0 && data.ambiguity <= 4) {
if (data.ambiguity <= 2) {
latString = latString.substring(0, 7 - data.ambiguity).padEnd(7, " ");
lonString = lonString.substring(0, 8 - data.ambiguity).padEnd(8, " ");
}
else if (data.ambiguity == 3) {
latString = `${latString.substring(0, 3)} . `;
lonString = `${lonString.substring(0, 4)} . `;
}
else if (data.ambiguity == 4) {
latString = `${latString.substring(0, 2)} . `;
lonString = `${lonString.substring(0, 3)} . `;
}
}
retVal += `${latString}${latDir}${symbolTable}${lonString}${lonDir}${symbolCode}`;
let course = data.course;
let speed = data.speed;
if (course && course != null && course >= 0
&& speed && speed != null && speed >= 0) {
speed = speed / ConversionConstantEnum_1.ConversionConstantEnum.KNOT_TO_KMH;
if (speed > 999) {
speed = 999;
}
if (course > 360) {
course = 0;
}
retVal += `${String(course).padStart(3, "0")}/${String(speed).padStart(3, "0")}`;
}
}
if (data.altitude && data.altitude != null) {
let altitude = data.altitude / ConversionConstantEnum_1.ConversionConstantEnum.FEET_TO_METERS;
if (altitude >= 0) {
retVal += `/A=${String(altitude.toFixed(0)).padStart(6, "0")}`;
}
else {
retVal += `/A=-${Math.abs(altitude).toFixed(0).padStart(5, "0")}`;
}
}
if (!!data.comment) {
retVal += data.comment;
}
if (data.isUseCompression == false && data.isUseDao != null && data.isUseDao == true) {
retVal += '!w' + String.fromCharCode((Math.floor(Number(latMinDao)) / 1.1 + 0.5) + 33)
+ String.fromCharCode((Math.floor(Number(lonMinDao)) / 1.1 + 0.5) + 33) + '!';
}
if (data.timestamp != null) {
let timestamp = data.timestamp;
if (/^\d+$/.test(timestamp.toString()) == false) {
throw new Error("Timestamp must be numeric.");
}
let now = new Date().getTime();
if (timestamp == 0) {
timestamp = now;
}
let age = now - timestamp;
if (age < -3610) {
throw new Error("Timestamp too far in the futre.");
}
else if (age < 84600) {
retVal = `${this.makeTimestamp(timestamp, TimeFormatEnum_1.TimeFormatEnum.HMS)}${retVal}`;
}
else if (age < 2419200) {
retVal = `${this.makeTimestamp(timestamp, TimeFormatEnum_1.TimeFormatEnum.DHM)}${retVal}`;
}
else {
throw new Error("Timestamp too far in the past.");
}
}
return retVal;
}
}
exports.PacketFactory = PacketFactory;
//# sourceMappingURL=PacketFactory.js.map