From 520d834993bced33ef331fdd1389b2eba6b453e4 Mon Sep 17 00:00:00 2001 From: KD0NKS Date: Sat, 8 May 2021 08:40:06 -0500 Subject: [PATCH 1/5] Added packet type enum. --- index.ts | 27 +- package.json | 2 +- src/{ => enums}/ConversionConstantEnum.ts | 6 +- src/enums/PacketTypeEnum.ts | 12 + src/enums/index.ts | 7 + src/parser.ts | 61 +-- src/{ => utils}/ConversionUtil.ts | 2 +- src/{ => utils}/aprsUtil.ts | 546 +++++++++++----------- test/10badpacket.test.ts | 3 +- test/21decode-uncomp-moving.test.ts | 3 +- test/22decode-compressed.test.ts | 3 +- test/23decode-mice.test.ts | 7 +- test/24decode-gprmc.test.ts | 3 +- test/40decode-object-inv.test.ts | 11 +- test/41decode-object.test.ts | 8 +- test/42decode-item.test.ts | 7 +- test/51decode-msg.test.ts | 12 +- test/56decode-status.test.ts | 2 +- test/checkDate.test.ts | 2 +- test/degToRad.test.ts | 2 +- test/dxCluster.test.ts | 6 + test/radToDeg.test.ts | 2 +- 22 files changed, 383 insertions(+), 351 deletions(-) rename src/{ => enums}/ConversionConstantEnum.ts (84%) create mode 100644 src/enums/PacketTypeEnum.ts create mode 100644 src/enums/index.ts rename src/{ => utils}/ConversionUtil.ts (93%) rename src/{ => utils}/aprsUtil.ts (97%) create mode 100644 test/dxCluster.test.ts diff --git a/index.ts b/index.ts index 4d2acf5..7c831be 100644 --- a/index.ts +++ b/index.ts @@ -1,15 +1,16 @@ -import aprsPacket from './src/aprsPacket'; -import aprsParser from './src/parser'; -import ConversionConstantEnum from './src/ConversionConstantEnum'; -import digipeater from './src/digipeater'; -import telemetry from './src/telemetry'; -import wx from './src/wx'; +import aprsPacket from './src/aprsPacket' +import aprsParser from './src/parser' +import { ConversionConstantEnum, PacketTypeEnum } from './src/enums' +import digipeater from './src/digipeater' +import telemetry from './src/telemetry' +import wx from './src/wx' export { - aprsPacket - , aprsParser - , ConversionConstantEnum - , digipeater - , telemetry - , wx -}; \ No newline at end of file + aprsPacket + , aprsParser + , ConversionConstantEnum + , digipeater + , PacketTypeEnum + , telemetry + , wx +} \ No newline at end of file diff --git a/package.json b/package.json index 3aabc6d..2cba17d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "afairhurst", "license": "ISC", "name": "js-aprs-fap", - "version": "1.1.1", + "version": "1.1.2-alpha", "homepage": "https://github.com/KD0NKS/js-aprs-fap", "description": "NodeJs library for parsing APRS packets.", "repository": { diff --git a/src/ConversionConstantEnum.ts b/src/enums/ConversionConstantEnum.ts similarity index 84% rename from src/ConversionConstantEnum.ts rename to src/enums/ConversionConstantEnum.ts index 6c99cef..4d065db 100644 --- a/src/ConversionConstantEnum.ts +++ b/src/enums/ConversionConstantEnum.ts @@ -1,10 +1,8 @@ -const enum ConversionConstantEnum { +export enum ConversionConstantEnum { KNOT_TO_KMH = 1.852 // nautical miles per hour to kilometers per hour , MPH_TO_KMH = 1.609344 // miles per hour to kilometers per hour , KMH_TO_MS = 10 / 36 // kilometers per hour to meters per second , MPH_TO_MS = MPH_TO_KMH * KMH_TO_MS // miles per hour to meters per second , HINCH_TO_MM = 0.254 // hundredths of an inch to millimeters , FEET_TO_METERS = 0.3048 -} - -export default ConversionConstantEnum; \ No newline at end of file +} \ No newline at end of file diff --git a/src/enums/PacketTypeEnum.ts b/src/enums/PacketTypeEnum.ts new file mode 100644 index 0000000..7bb6c16 --- /dev/null +++ b/src/enums/PacketTypeEnum.ts @@ -0,0 +1,12 @@ +export enum PacketTypeEnum { + CAPABILITIES = 'capabilities' + , DX = 'dx' + , ITEM = 'item' + , LOCATION = 'location' + , MESSAGE = 'message' + , OBJECT = 'object' + , STATUS = 'status' + , TELEMETRY = 'telemetry' + , TELEMETRY_MESSAGE = 'telemetry-message' + , WEATHER = 'wx' +} \ No newline at end of file diff --git a/src/enums/index.ts b/src/enums/index.ts new file mode 100644 index 0000000..f093424 --- /dev/null +++ b/src/enums/index.ts @@ -0,0 +1,7 @@ +import { ConversionConstantEnum } from './ConversionConstantEnum' +import { PacketTypeEnum } from './PacketTypeEnum' + +export { + ConversionConstantEnum + , PacketTypeEnum +} \ No newline at end of file diff --git a/src/parser.ts b/src/parser.ts index d4c48a2..207f018 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1,11 +1,12 @@ import aprsPacket from './aprsPacket' -import ConversionConstantEnum from './ConversionConstantEnum' -import ConversionUtil from './ConversionUtil' +import { ConversionConstantEnum } from './enums' +import ConversionUtil from './utils/ConversionUtil' import digipeater from './digipeater' import { DST_SYMBOLS } from './DSTSymbols' import { RESULT_MESSAGES } from './ResultMessages' import telemetry from './telemetry' import wx from './wx' +import { PacketTypeEnum } from './enums' export default class aprsParser { constructor() { } @@ -253,7 +254,7 @@ export default class aprsParser { // mic-encoder data // minimum body length 9 chars if($paclen >= 9) { - retVal.type = 'location'; + retVal.type = PacketTypeEnum.LOCATION retVal = this._mice_to_decimal(body.substr(1), dstcallsign, srcCallsign, retVal, options); //return $rethash; @@ -266,7 +267,7 @@ export default class aprsParser { retVal.messaging = !($packettype == '!' || $packettype == '/'); if($paclen >= 14) { - retVal.type = 'location'; + retVal.type = PacketTypeEnum.LOCATION; if($packettype == '/' || $packettype == '@') { // With a prepended timestamp, check it and jump over. @@ -327,7 +328,7 @@ export default class aprsParser { } } else if($poschar == 33) { // '!' // Weather report from Ultimeter 2000 - retVal.type = 'wx'; + retVal.type = PacketTypeEnum.WEATHER retVal = this._wx_parse_peet_logging(body.substr(1), srcCallsign, retVal); } else { @@ -339,7 +340,7 @@ export default class aprsParser { // Weather report } else if($packettype == '_') { if(/_(\d{8})c[\- \.\d]{1,3}s[\- \.\d]{1,3}/.test(body)) { - retVal.type = 'wx'; + retVal.type = PacketTypeEnum.WEATHER retVal = this._wx_parse(body.substr(9), retVal); } else { @@ -348,7 +349,7 @@ export default class aprsParser { // Object } else if ($packettype == ';') { // if($paclen >= 31) { is there a case where this couldn't be - retVal.type = 'object'; + retVal.type = PacketTypeEnum.OBJECT retVal = this.objectToDecimal(options, body, srcCallsign, retVal); // NMEA data @@ -357,11 +358,11 @@ export default class aprsParser { if(body.substr(0, 3) == '$GP') { // dstcallsign can contain the APRS symbol to use, // so read that one too - retVal.type = 'location'; + retVal.type = PacketTypeEnum.LOCATION retVal = this._nmea_to_decimal(options, body.substr(1), srcCallsign, dstcallsign, retVal); } else if(body.substr(0, 5) == '$ULTW') { - retVal.type = 'wx'; + retVal.type = PacketTypeEnum.WEATHER retVal = this._wx_parse_peet_packet(body.substr(5), srcCallsign, retVal); } /* @@ -371,13 +372,13 @@ export default class aprsParser { */ // Item } else if ($packettype == ')') { - retVal.type = 'item'; + retVal.type = PacketTypeEnum.ITEM retVal = this._item_to_decimal(body, srcCallsign, retVal); // Message, bulletin or an announcement } else if($packettype === ':') { if($paclen >= 11) { // all are labeled as messages for the time being - retVal.type = 'message'; + retVal.type = PacketTypeEnum.MESSAGE retVal = this.messageParse(body, retVal); } @@ -390,7 +391,7 @@ export default class aprsParser { } else if($packettype == '<') { // at least one other character besides '<' required if($paclen >= 2) { - retVal.type = 'capabilities'; + retVal.type = PacketTypeEnum.CAPABILITIES retVal = this._capabilities_parse(body.substr(1), srcCallsign, retVal); } @@ -398,25 +399,28 @@ export default class aprsParser { } else if($packettype == '>') { // we can live with empty status reports if($paclen >= 1) { - retVal.type = 'status'; + retVal.type = PacketTypeEnum.STATUS retVal = this._status_parse(options, body.substr(1), srcCallsign, retVal) } // Telemetry } else if(/^T#(.*?),(.*)$/.test(body)) { - retVal.type = 'telemetry'; + retVal.type = PacketTypeEnum.TELEMETRY retVal = this._telemetry_parse(body.substr(2), retVal); // DX spot - } else if(/^DX\s+de\s+(.*?)\s*[:>]\s*(.*)$/i.test(body)) { + } + /* + else if (/^DX\s+de\s+(.*?)\s*[:>]\s*(.*)$/i.test(body)) { var tmp: string[]; tmp = body.match(/^DX\s+de\s+(.*?)\s*[:>]\s*(.*)$/i); - retVal.type = 'dx'; + retVal.type = PacketTypeEnum.DX retVal = this._dx_parse(tmp[1], tmp[2], retVal); //# Experimental - } else if(/^\{\{/i.test(body)) { + } */ + else if(/^\{\{/i.test(body)) { return this.addError(retVal, 'exp_unsupp'); // When all else fails, try to look for a !-position that can // occur anywhere within the 40 first characters according @@ -425,7 +429,7 @@ export default class aprsParser { let $pos = body.indexOf('!'); if($pos >= 0 && $pos <= 39) { - retVal.type = 'location'; + retVal.type = PacketTypeEnum.LOCATION retVal.messaging = false; let $pchar = body.substr($pos + 1, 1); @@ -662,7 +666,7 @@ export default class aprsParser { // catch telemetry messages if(/^(BITS|PARM|UNIT|EQNS)\./i.test($message)) { - retVal.type = 'telemetry-message'; + retVal.type = PacketTypeEnum.TELEMETRY_MESSAGE } // messages cannot contain |, ~, or { @@ -1222,7 +1226,7 @@ export default class aprsParser { $rest = $rest.substr(7); } else if((tmprest = $rest.match(/^RNG(\d{4})/))) { // radio range, in miles, so convert to km - $rethash['radiorange'] = parseInt(tmprest[1]) * ConversionConstantEnum.MPH_TO_KMH; + $rethash.radiorange = parseInt(tmprest[1]) * ConversionConstantEnum.MPH_TO_KMH; $rest = $rest.substr(7); } } @@ -1256,7 +1260,7 @@ export default class aprsParser { // anything is left (trim unprintable chars // out first and white space from both ends) if($rest.length > 0) { - $rethash['comment'] = $rest.trim(); + $rethash.comment = $rest.trim(); } // Always succeed as these are optional @@ -1381,7 +1385,7 @@ export default class aprsParser { // Check the APRS data extension and possible comments, // unless it is a weather report (we don't want erroneus // course/speed figures and weather in the comments..) - if($rethash['symbolcode'] != '_') { + if($rethash.symbolcode != '_') { $rethash = this._comments_to_decimal($packet.substr($locationoffset), $srccallsign, $rethash); } @@ -1416,7 +1420,7 @@ export default class aprsParser { $symboltable = matches[4]; - $rethash['symbolcode'] = matches[8]; + $rethash.symbolcode = matches[8]; if($sind == 'S') { $issouth = 1; @@ -1745,7 +1749,7 @@ export default class aprsParser { // also zero course is saved, which means unknown if($course >= 0) { - $rethash['course'] = $course; + $rethash.course = $course; } // do some important adjustements @@ -1990,14 +1994,12 @@ export default class aprsParser { * Parses the body of a DX spot packet. Returns the following * hash elements: dxsource (source of the info), dxfreq (frequency), * dxcall (DX callsign) and dxinfo (info string). - */ + * private _dx_parse($sourcecall: string, $info: string, $rethash: aprsPacket): aprsPacket { - if(!this.checkAX25Call($sourcecall)) { return this.addError($rethash, 'dx_inv_src', $sourcecall); } - /* $rethash['dxsource'] = $sourcecall; $info = $info.replace(/^\s*(.*?)\s*$/, $1); // strip whitespace @@ -2022,13 +2024,12 @@ export default class aprsParser { $info = $info.match(/\s+/ /g); $rethash['dxinfo'] = $info; - * return 1; - */ return $rethash; } + */ /** * _wx_parse($s, $rethash) @@ -2429,7 +2430,7 @@ export default class aprsParser { $t = $vals.shift(); if($t) { - $w['rain_midnight'] = ($t * ConversionConstantEnum.HINCH_TO_MM).toFixed(1); + $w.rain_midnight = ($t * ConversionConstantEnum.HINCH_TO_MM).toFixed(1); } // avg wind speed diff --git a/src/ConversionUtil.ts b/src/utils/ConversionUtil.ts similarity index 93% rename from src/ConversionUtil.ts rename to src/utils/ConversionUtil.ts index fe79006..d1abd51 100644 --- a/src/ConversionUtil.ts +++ b/src/utils/ConversionUtil.ts @@ -8,7 +8,7 @@ export default class ConversionUtil { * @param {Number} day day for the date * @returns {boolean} Whether or not the given date is valid */ - static CheckDate = function (year: number, month: number, day: number): boolean { + static CheckDate(year: number, month: number, day: number): boolean { var d = new Date(year, month, day); return d.getFullYear() === year && d.getMonth() === month && d.getDate() === day; diff --git a/src/aprsUtil.ts b/src/utils/aprsUtil.ts similarity index 97% rename from src/aprsUtil.ts rename to src/utils/aprsUtil.ts index 2d5eb16..38efe95 100644 --- a/src/aprsUtil.ts +++ b/src/utils/aprsUtil.ts @@ -1,274 +1,274 @@ - /** - * message bit types for mic-e - * from left to right, bits a, b and c - * standard one bit is 1, custom one bit is 2 - * - const MICE_MESSAGE_TYPES = { - '111': 'off duty' - , '222': 'custom 0' - , '110': 'en route' - , '220': 'custom 1' - , '101': 'in service' - , '202': 'custom 2' - , '100': 'returning' - , '200': 'custom 3' - , '011': 'committed' - , '022': 'custom 4' - , '010': 'special' - , '020': 'custom 5' - , '001': 'priority' - , '002': 'custom 6' - , '000': 'emergency' - }; - */ - - /** - * mice_mbits_to_message($packetdata{'mbits'}) - * Convert mic-e message bits (three numbers 0-2) to a textual message. - * - * @param {Number} $bits Three numbers 0 - 2 - * @returns {string} the message on success, null on failure. - * - private mice_mbits_to_message($bits: string): aprsPacket { - /* - if(($bits = $bits.match(/^\s*([0-2]{3})\s*$/))) { - $bits = $bits[1]; - - if(mice_messagetypes[$bits]) { - return mice_messagetypes[$bits]; - } - } - * - - return null; - } - */ - - /** - * If no parameter is given, use current time, - * else use the unix timestamp given in the parameter. - * - * @returns {string} A human readable timestamp in UTC, string form. - * - private _gettime(): string { - /* - let($sec,$min,$hour,$mday,$mon,$year,$wday,$yday); - - if(scalar(@_) >= 1) { - my $tstamp = shift @_; - ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime($tstamp); - } else { - ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime(); - } - - let $timestring = sprintf('%d-%02d-%02d %02d:%02d:%02d UTC', - $year + 1900, - $mon + 1, - $mday, - $hour, - $min, - $sec); - - return $timestring; - * - - return null; - } - */ - - /** - * TODO: Move to utility class - * Calculates the distance in kilometers between two locations - * given in decimal degrees. East and North positive. The calculation uses the great circle distance, it - * is not too exact, but good enough for us. - * - * @param {float} $lon0 The first station's longitude. - * @param {float} $lat0 The first station's latitude. - * @param {float} $lon1 The second station's longitude. - * @param {float} $lat1 The second station's latitude. - * @returns {float} The distance between 2 stations - * - private distance($lon0: number, $lat0: number, $lon1: number, $lat1: number): number { - /* - // decimal to radian - $lon0 = this.deg2rad($lon0); - $lon1 = this.deg2rad($lon1); - $lat0 = this.deg2rad($lat0); - $lat1 = this.deg2rad($lat1); - - // Use the haversine formula for distance calculation - // http://mathforum.org/library/drmath/view/51879.html - let $dlon = $lon1 - $lon0; - let $dlat = $lat1 - $lat0; - let $a = Math.pow(Math.sin($dlat / 2), 2) + Math.cos($lat0) * Math.cos($lat1) * Math.pow(Math.sin($dlon / 2), 2); - let $c = 2 * Math.atan2(Math.sqrt($a), Math.sqrt(1 - $a)); - let $distance = $c * 6366.71; // in kilometers - - return $distance; - * - - return null; - } - */ - - /** - * TODO: Move to utility class - * Returns the initial great circle direction in degrees - * from lat0/lon0 to lat1/lon1. Locations are input - * in decimal degrees, north and east positive. - * - * @param {float} $lon0 Longitude of the first station. - * @param {float} $lat0 Latitude of the first station. - * @param {float} $lon1 Longitude of the second station. - * @param {float} $lat1 Latitude of the second station. - * @return {float} The initial great circle direction in degrees from lat0/lon0 to lat1/lon1. - * - private direction = function($lon0: number, $lat0: number, $lon1: number, $lat1: number): number { - /* - $lon0 = this.deg2rad($lon0); - $lon1 = this.deg2rad($lon1); - $lat0 = this.deg2rad($lat0); - $lat1 = this.deg2rad($lat1); - - // direction from Aviation Formulary V1.42 by Ed Williams - let $direction = Math.atan2(Math.sin($lon1-$lon0) * Math.cos($lat1) - , Math.cos($lat0) * Math.sin($lat1) - Math.sin($lat0) * Math.cos($lat1) * Math.cos($lon1-$lon0)); - - if($direction < 0) { - // make direction positive - $direction += 2 * Math.PI; - } - - return this.rad2deg($direction); - * - - return null; - } - */ - - /** - * TODO: Move to utility class - * - * Count the number of digipeated hops in a (KISS) packet and return it. Returns -1 in case of error. - * The header parameter can contain the full packet or just the header - * in TNC2 format. All callsigns in the header must be AX.25 compatible - * and remember that the number returned is just an educated guess, not - * absolute truth. - * - * @param {string} $header Full APRS packet or just the header of the packet - * @returns {Number} The number of digipeated hops in the KISS packet. - * - private count_digihops($header: string): number { - let tmp; - - // Do a rough check on the header syntax - $header = $header.trim(); - $header = $header.toUpperCase(); - - if((tmp = $header.match(/^([^:]+):/))) { - // remove data part of packet, if present - $header = tmp[1]; - } - - /* - - - let $hops;; - - if($header =~ /^([A-Z0-9-]+)\>([A-Z0-9-]+)$/o) { - # check the callsigns for validity - my $retval = checkAX25Call($1); - if (not(defined($retval))) { - if ($debug > 0) { - warn "count_digihops: invalid source callsign ($1)\n"; - } - return -1; - } - $retval = checkAX25Call($2); - if (not(defined($retval))) { - if ($debug > 0) { - warn "count_digihops: invalid destination callsign ($2)\n"; - } - return -1; - } - # no path at all, so zero hops - return 0; - - } elsif ($header =~ /^([A-Z0-9-]+)\>([A-Z0-9-]+),([A-Z0-9,*-]+)$/o) { - my $retval = checkAX25Call($1); - if (not(defined($retval))) { - if ($debug > 0) { - warn "count_digihops: invalid source callsign ($1)\n"; - } - return -1; - } - $retval = checkAX25Call($2); - if (not(defined($retval))) { - if ($debug > 0) { - warn "count_digihops: invalid destination callsign ($2)\n"; - } - return -1; - } - # some hops - $hops = $3; - - } else { - # invalid - if ($debug > 0) { - warn "count_digihops: invalid packet header\n"; - } - return -1; - } - - my $hopcount = 0; - # split the path into parts - my @parts = split(/,/, $hops); - # now examine the parts one by one - foreach my $piece (@parts) { - # remove the possible "digistar" from the end of callsign - # and take note of its existence - my $wasdigied = 0; - if ($piece =~ /^[A-Z0-9-]+\*$/o) { - $wasdigied = 1; - $piece =~ s/\*$//; - } - # check the callsign for validity and expand it - my $call = checkAX25Call($piece); - if (not(defined($call))) { - if ($debug > 0) { - warn "count_digihops: invalid callsign in path ($piece)\n"; - } - return -1; - } - # check special cases, wideN-N and traceN-N for now - if ($call =~ /^WIDE([1-7])-([0-7])$/o) { - my $difference = $1 - $2; - if ($difference < 0) { - # ignore reversed N-N - if ($debug > 0) { - warn "count_digihops: reversed N-N in path ($call)\n"; - } - next; - } - $hopcount += $difference; - - } elsif ($call =~ /^TRACE([1-7])-([0-7])$/o) { - # skip traceN-N because the hops are already individually shown - # before this - next; - - } else { - # just a normal packet. if "digistar" is there, - # increment the digicounter by one - if ($wasdigied == 1) { - $hopcount++; - } - } - } - - return $hopcount; - * - - return null; - } + /** + * message bit types for mic-e + * from left to right, bits a, b and c + * standard one bit is 1, custom one bit is 2 + * + const MICE_MESSAGE_TYPES = { + '111': 'off duty' + , '222': 'custom 0' + , '110': 'en route' + , '220': 'custom 1' + , '101': 'in service' + , '202': 'custom 2' + , '100': 'returning' + , '200': 'custom 3' + , '011': 'committed' + , '022': 'custom 4' + , '010': 'special' + , '020': 'custom 5' + , '001': 'priority' + , '002': 'custom 6' + , '000': 'emergency' + }; + */ + + /** + * mice_mbits_to_message($packetdata{'mbits'}) + * Convert mic-e message bits (three numbers 0-2) to a textual message. + * + * @param {Number} $bits Three numbers 0 - 2 + * @returns {string} the message on success, null on failure. + * + private mice_mbits_to_message($bits: string): aprsPacket { + /* + if(($bits = $bits.match(/^\s*([0-2]{3})\s*$/))) { + $bits = $bits[1]; + + if(mice_messagetypes[$bits]) { + return mice_messagetypes[$bits]; + } + } + * + + return null; + } + */ + + /** + * If no parameter is given, use current time, + * else use the unix timestamp given in the parameter. + * + * @returns {string} A human readable timestamp in UTC, string form. + * + private _gettime(): string { + /* + let($sec,$min,$hour,$mday,$mon,$year,$wday,$yday); + + if(scalar(@_) >= 1) { + my $tstamp = shift @_; + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime($tstamp); + } else { + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime(); + } + + let $timestring = sprintf('%d-%02d-%02d %02d:%02d:%02d UTC', + $year + 1900, + $mon + 1, + $mday, + $hour, + $min, + $sec); + + return $timestring; + * + + return null; + } + */ + + /** + * TODO: Move to utility class + * Calculates the distance in kilometers between two locations + * given in decimal degrees. East and North positive. The calculation uses the great circle distance, it + * is not too exact, but good enough for us. + * + * @param {float} $lon0 The first station's longitude. + * @param {float} $lat0 The first station's latitude. + * @param {float} $lon1 The second station's longitude. + * @param {float} $lat1 The second station's latitude. + * @returns {float} The distance between 2 stations + * + private distance($lon0: number, $lat0: number, $lon1: number, $lat1: number): number { + /* + // decimal to radian + $lon0 = this.deg2rad($lon0); + $lon1 = this.deg2rad($lon1); + $lat0 = this.deg2rad($lat0); + $lat1 = this.deg2rad($lat1); + + // Use the haversine formula for distance calculation + // http://mathforum.org/library/drmath/view/51879.html + let $dlon = $lon1 - $lon0; + let $dlat = $lat1 - $lat0; + let $a = Math.pow(Math.sin($dlat / 2), 2) + Math.cos($lat0) * Math.cos($lat1) * Math.pow(Math.sin($dlon / 2), 2); + let $c = 2 * Math.atan2(Math.sqrt($a), Math.sqrt(1 - $a)); + let $distance = $c * 6366.71; // in kilometers + + return $distance; + * + + return null; + } + */ + + /** + * TODO: Move to utility class + * Returns the initial great circle direction in degrees + * from lat0/lon0 to lat1/lon1. Locations are input + * in decimal degrees, north and east positive. + * + * @param {float} $lon0 Longitude of the first station. + * @param {float} $lat0 Latitude of the first station. + * @param {float} $lon1 Longitude of the second station. + * @param {float} $lat1 Latitude of the second station. + * @return {float} The initial great circle direction in degrees from lat0/lon0 to lat1/lon1. + * + private direction = function($lon0: number, $lat0: number, $lon1: number, $lat1: number): number { + /* + $lon0 = this.deg2rad($lon0); + $lon1 = this.deg2rad($lon1); + $lat0 = this.deg2rad($lat0); + $lat1 = this.deg2rad($lat1); + + // direction from Aviation Formulary V1.42 by Ed Williams + let $direction = Math.atan2(Math.sin($lon1-$lon0) * Math.cos($lat1) + , Math.cos($lat0) * Math.sin($lat1) - Math.sin($lat0) * Math.cos($lat1) * Math.cos($lon1-$lon0)); + + if($direction < 0) { + // make direction positive + $direction += 2 * Math.PI; + } + + return this.rad2deg($direction); + * + + return null; + } + */ + + /** + * TODO: Move to utility class + * + * Count the number of digipeated hops in a (KISS) packet and return it. Returns -1 in case of error. + * The header parameter can contain the full packet or just the header + * in TNC2 format. All callsigns in the header must be AX.25 compatible + * and remember that the number returned is just an educated guess, not + * absolute truth. + * + * @param {string} $header Full APRS packet or just the header of the packet + * @returns {Number} The number of digipeated hops in the KISS packet. + * + private count_digihops($header: string): number { + let tmp; + + // Do a rough check on the header syntax + $header = $header.trim(); + $header = $header.toUpperCase(); + + if((tmp = $header.match(/^([^:]+):/))) { + // remove data part of packet, if present + $header = tmp[1]; + } + + /* + + + let $hops;; + + if($header =~ /^([A-Z0-9-]+)\>([A-Z0-9-]+)$/o) { + # check the callsigns for validity + my $retval = checkAX25Call($1); + if (not(defined($retval))) { + if ($debug > 0) { + warn "count_digihops: invalid source callsign ($1)\n"; + } + return -1; + } + $retval = checkAX25Call($2); + if (not(defined($retval))) { + if ($debug > 0) { + warn "count_digihops: invalid destination callsign ($2)\n"; + } + return -1; + } + # no path at all, so zero hops + return 0; + + } elsif ($header =~ /^([A-Z0-9-]+)\>([A-Z0-9-]+),([A-Z0-9,*-]+)$/o) { + my $retval = checkAX25Call($1); + if (not(defined($retval))) { + if ($debug > 0) { + warn "count_digihops: invalid source callsign ($1)\n"; + } + return -1; + } + $retval = checkAX25Call($2); + if (not(defined($retval))) { + if ($debug > 0) { + warn "count_digihops: invalid destination callsign ($2)\n"; + } + return -1; + } + # some hops + $hops = $3; + + } else { + # invalid + if ($debug > 0) { + warn "count_digihops: invalid packet header\n"; + } + return -1; + } + + my $hopcount = 0; + # split the path into parts + my @parts = split(/,/, $hops); + # now examine the parts one by one + foreach my $piece (@parts) { + # remove the possible "digistar" from the end of callsign + # and take note of its existence + my $wasdigied = 0; + if ($piece =~ /^[A-Z0-9-]+\*$/o) { + $wasdigied = 1; + $piece =~ s/\*$//; + } + # check the callsign for validity and expand it + my $call = checkAX25Call($piece); + if (not(defined($call))) { + if ($debug > 0) { + warn "count_digihops: invalid callsign in path ($piece)\n"; + } + return -1; + } + # check special cases, wideN-N and traceN-N for now + if ($call =~ /^WIDE([1-7])-([0-7])$/o) { + my $difference = $1 - $2; + if ($difference < 0) { + # ignore reversed N-N + if ($debug > 0) { + warn "count_digihops: reversed N-N in path ($call)\n"; + } + next; + } + $hopcount += $difference; + + } elsif ($call =~ /^TRACE([1-7])-([0-7])$/o) { + # skip traceN-N because the hops are already individually shown + # before this + next; + + } else { + # just a normal packet. if "digistar" is there, + # increment the digicounter by one + if ($wasdigied == 1) { + $hopcount++; + } + } + } + + return $hopcount; + * + + return null; + } */ \ No newline at end of file diff --git a/test/10badpacket.test.ts b/test/10badpacket.test.ts index ab9e6cc..8a4f454 100644 --- a/test/10badpacket.test.ts +++ b/test/10badpacket.test.ts @@ -6,6 +6,7 @@ const assert = require('assert'); const should = chai.should(); import aprsPacket from '../src/aprsPacket'; +import { PacketTypeEnum } from '../src/enums'; import aprsParser from '../src/parser'; describe('FAP - test bad packets', () => { @@ -28,7 +29,7 @@ describe('FAP - test bad packets', () => { }); it('Should return a type: location', () => { - assert.equal('location', parsed.type); + assert.equal(PacketTypeEnum.LOCATION, parsed.type); }); it('Should return the source call sign: ' + $srccall, () => { diff --git a/test/21decode-uncomp-moving.test.ts b/test/21decode-uncomp-moving.test.ts index 1b0755d..591de86 100644 --- a/test/21decode-uncomp-moving.test.ts +++ b/test/21decode-uncomp-moving.test.ts @@ -8,6 +8,7 @@ const assert = require('assert'); const should = chai.should(); import aprsPacket from '../src/aprsPacket'; +import { PacketTypeEnum } from '../src/enums'; import aprsParser from '../src/parser'; describe('FAP - Test decoding uncompressed packets', function() { @@ -43,7 +44,7 @@ describe('FAP - Test decoding uncompressed packets', function() { }); it('Should return a type: location', function() { - assert.equal('location', parsed.type); + assert.equal(PacketTypeEnum.LOCATION, parsed.type); }); it('Should return 3 valid digis', function() { diff --git a/test/22decode-compressed.test.ts b/test/22decode-compressed.test.ts index 6134b40..ff4295d 100644 --- a/test/22decode-compressed.test.ts +++ b/test/22decode-compressed.test.ts @@ -9,6 +9,7 @@ const should = chai.should(); const expect = chai.expect; import aprsPacket from '../src/aprsPacket'; +import { PacketTypeEnum } from '../src/enums'; import aprsParser from '../src/parser'; describe('FAP - Test decoding compressed packets', function() { @@ -44,7 +45,7 @@ describe('FAP - Test decoding compressed packets', function() { }); it('Should return a type: location', function() { - assert.equal('location', parsed.type); + assert.equal(PacketTypeEnum.LOCATION, parsed.type); }); it('Should return format: compressed', function() { diff --git a/test/23decode-mice.test.ts b/test/23decode-mice.test.ts index 183c069..4d249bf 100644 --- a/test/23decode-mice.test.ts +++ b/test/23decode-mice.test.ts @@ -1,6 +1,7 @@ const assert = require('assert'); import aprsPacket from '../src/aprsPacket'; +import { PacketTypeEnum } from '../src/enums'; import aprsParser from '../src/parser'; // a mic-e decoding test @@ -39,7 +40,7 @@ describe('FAP - Test parsing mic-e packages', () => { }); it('Should return the location type: location', () => { - assert.equal('location', parsed.type); + assert.equal(PacketTypeEnum.LOCATION, parsed.type); }); it('Should return the type: mice', () => { @@ -134,7 +135,7 @@ describe('FAP - Test parsing mic-e packages', () => { }); it('Should return the location type: location', () => { - assert.equal('location', parsed.type); + assert.equal(PacketTypeEnum.LOCATION, parsed.type); }); it('Should return the type: mice', () => { @@ -233,7 +234,7 @@ describe('FAP - Test parsing mic-e packages', () => { }); it('Should return the location type: location', () => { - assert.equal('location', parsed.type); + assert.equal(PacketTypeEnum.LOCATION, parsed.type); }); it('Should return the type: mice', () => { diff --git a/test/24decode-gprmc.test.ts b/test/24decode-gprmc.test.ts index cf202f4..d3db9f1 100644 --- a/test/24decode-gprmc.test.ts +++ b/test/24decode-gprmc.test.ts @@ -8,6 +8,7 @@ const assert = require('assert'); const should = chai.should(); import aprsPacket from '../src/aprsPacket'; +import { PacketTypeEnum } from '../src/enums'; import aprsParser from '../src/parser'; describe('FAP - Test decoding GPRMC NMEA', function() { @@ -35,7 +36,7 @@ describe('FAP - Test decoding GPRMC NMEA', function() { }); it('Should return the location type: location', function() { - assert.equal('location', parsed.type); + assert.equal(PacketTypeEnum.LOCATION, parsed.type); }); it('Should return the type: nmea', function() { diff --git a/test/40decode-object-inv.test.ts b/test/40decode-object-inv.test.ts index bdf55d4..421c5c8 100644 --- a/test/40decode-object-inv.test.ts +++ b/test/40decode-object-inv.test.ts @@ -4,9 +4,10 @@ * a cut 'n paste operation * Tue Dec 11 2007, Hessu, OH7LZB */ -import aprsPacket from '../src/aprsPacket'; -import aprsParser from '../src/parser'; -import * as chai from 'chai'; +import aprsPacket from '../src/aprsPacket' +import aprsParser from '../src/parser' +import * as chai from 'chai' +import { PacketTypeEnum } from '../src/enums' const assert = chai.assert; @@ -22,7 +23,7 @@ describe('FAP - Test parsing a bad packet', function() { }) it('Should return a type: object', function() { - assert.equal('object', parsed.type); + assert.equal(PacketTypeEnum.OBJECT, parsed.type); }) }) @@ -37,7 +38,7 @@ describe('FAP - Test parsing a bad packet', function() { }) it('Should return a type: object', function () { - assert.equal('object', parsed.type); + assert.equal(PacketTypeEnum.OBJECT, parsed.type); }) }) diff --git a/test/41decode-object.test.ts b/test/41decode-object.test.ts index 8d3c8be..719c4b7 100644 --- a/test/41decode-object.test.ts +++ b/test/41decode-object.test.ts @@ -2,11 +2,11 @@ // Tue Dec 11 2007, Hessu, OH7LZB import * as chai from 'chai'; -const assert = require('assert'); -const should = chai.should(); -const expect = chai.expect; +const assert = require('assert') +const expect = chai.expect import aprsPacket from '../src/aprsPacket'; +import { PacketTypeEnum } from '../src/enums'; import aprsParser from '../src/parser'; describe('FAP - Test parsing object', () => { @@ -38,7 +38,7 @@ describe('FAP - Test parsing object', () => { }); it('Should return type value: object', () => { - assert.equal('object', parsed.type); + assert.equal(PacketTypeEnum.OBJECT, parsed.type); }); it('Should return object name: \'SRAL HQ \'', () => { diff --git a/test/42decode-item.test.ts b/test/42decode-item.test.ts index b26b668..5ba1026 100644 --- a/test/42decode-item.test.ts +++ b/test/42decode-item.test.ts @@ -3,6 +3,7 @@ const assert = require('assert'); import aprsPacket from '../src/aprsPacket'; +import { PacketTypeEnum } from '../src/enums'; import aprsParser from '../src/parser'; describe('FAP - Test item parsing', function() { @@ -30,7 +31,7 @@ describe('FAP - Test item parsing', function() { }); it('Should return type value: item', function() { - assert.equal('item', parsed.type); + assert.equal(PacketTypeEnum.ITEM, parsed.type); }); it('Should return alive value: true', function() { @@ -88,7 +89,7 @@ describe('FAP - Test item parsing', function() { }); it('Should return type value: item', function() { - assert.equal('item', parsed.type); + assert.equal(PacketTypeEnum.ITEM, parsed.type); }); it('Should return alive value: false', function() { @@ -146,7 +147,7 @@ describe('FAP - Test item parsing', function() { }); it('Should return type value: item', function() { - assert.equal('item', parsed.type); + assert.equal(PacketTypeEnum.ITEM, parsed.type); }); it('Should return alive value: true', function() { diff --git a/test/51decode-msg.test.ts b/test/51decode-msg.test.ts index bf352fb..1c6a166 100644 --- a/test/51decode-msg.test.ts +++ b/test/51decode-msg.test.ts @@ -4,7 +4,7 @@ const assert = require('assert'); const should = chai.should(); import aprsPacket from '../src/aprsPacket'; -import digipeater from '../src/digipeater'; +import { PacketTypeEnum } from '../src/enums'; import aprsParser from '../src/parser'; describe('Test parsing messages', function() { @@ -26,7 +26,7 @@ describe('Test parsing messages', function() { }); it('Should return a type: message', function() { - assert.equal('message', packet.type); + assert.equal(PacketTypeEnum.MESSAGE, packet.type); }); it('Should return a destination: ' + destination.trim(), function() { @@ -56,7 +56,7 @@ describe('Test parsing messages', function() { }); it('Should return a type: message', function() { - assert.equal('message', packet.type); + assert.equal(PacketTypeEnum.MESSAGE, packet.type); }); @@ -82,7 +82,7 @@ describe('Test parsing messages', function() { }); it('Should return a type: message', function() { - assert.equal("message", packet.type); + assert.equal(PacketTypeEnum.MESSAGE, packet.type); }); it('Should return a destination: ' + destination.trim(), function() { @@ -109,7 +109,7 @@ describe('Test parsing messages', function() { }); it('Should return a type: message', function() { - assert.equal("message", packet.type); + assert.equal(PacketTypeEnum.MESSAGE, packet.type); }); it('Should return a destination: ' + destination.trim(), function() { @@ -136,7 +136,7 @@ describe('Test parsing messages', function() { }); it('Should return a type: message', function() { - assert.equal("telemetry-message", packet.type); + assert.equal(PacketTypeEnum.TELEMETRY_MESSAGE, packet.type); }); it('Should return a message: ' + message, function() { diff --git a/test/56decode-status.test.ts b/test/56decode-status.test.ts index 10765c5..52c72b0 100644 --- a/test/56decode-status.test.ts +++ b/test/56decode-status.test.ts @@ -2,8 +2,8 @@ import aprsPacket from '../src/aprsPacket' import aprsParser from '../src/parser' import * as chai from 'chai'; import { RESULT_MESSAGES } from '../src/ResultMessages' -import assert = require('assert') +const assert = chai.assert; const should = chai.should(); describe('FAP - Status message decoding', function() { diff --git a/test/checkDate.test.ts b/test/checkDate.test.ts index bdd8d2d..554641b 100644 --- a/test/checkDate.test.ts +++ b/test/checkDate.test.ts @@ -1,6 +1,6 @@ const assert = require('assert'); -import ConversionUtil from '../src/ConversionUtil'; +import ConversionUtil from '../src/utils/ConversionUtil'; describe('checkDate', function() { describe('Test valid checkdate', function() { diff --git a/test/degToRad.test.ts b/test/degToRad.test.ts index 3a3f864..ae3623f 100644 --- a/test/degToRad.test.ts +++ b/test/degToRad.test.ts @@ -1,5 +1,5 @@ var assert = require('assert'); -import ConversionUtil from '../src/ConversionUtil'; +import ConversionUtil from '../src/utils/ConversionUtil'; describe('#degToRad', function() { it('should return ~0.017453', function() { diff --git a/test/dxCluster.test.ts b/test/dxCluster.test.ts new file mode 100644 index 0000000..0b25d9c --- /dev/null +++ b/test/dxCluster.test.ts @@ -0,0 +1,6 @@ +/* +http://aprsisce.wikidot.com/kenwood-dx-cluster +URCALL>RESORC:DX de YOURCALL.>11111111112222222222*33333333334444444444*55555 +URCALL>RESORC:DX de YOURCALL.>FIELD-ONE.ITEMNAME*FIELD-TWOFIELD-3333*FORTH +URCALL>RESORC:DX de VE6SLP-10>144390.0 PIGEON 203 dg frm VE6SLP-10 74km +*/ \ No newline at end of file diff --git a/test/radToDeg.test.ts b/test/radToDeg.test.ts index 58d5fb3..9426bb3 100644 --- a/test/radToDeg.test.ts +++ b/test/radToDeg.test.ts @@ -1,5 +1,5 @@ var assert = require('assert'); -import ConversionUtil from '../src/ConversionUtil'; +import ConversionUtil from '../src/utils/ConversionUtil'; describe('#radToDeg', function() { it('should return ~0.017453', function() { From 43411e398e942b13dffd221c9d8ec2429dfede10 Mon Sep 17 00:00:00 2001 From: KD0NKS Date: Tue, 11 May 2021 21:04:33 -0500 Subject: [PATCH 2/5] * Now exporting conversionUtil * Working on npm publish --- .editorconfig | 2 +- .github/workflows/npm-publish.yml | 29 +++++++++++++++++++++++++++++ .npmignore | 3 ++- index.ts | 2 ++ src/parser.ts | 2 +- src/utils/ConversionUtil.ts | 2 +- 6 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/npm-publish.yml diff --git a/.editorconfig b/.editorconfig index 3826e65..28ecbbc 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,5 +6,5 @@ charset=utf-8 trim_trailing_whitespace=true insert_final_newline=false -[*.json] +[*.{json,yaml,yml}] indent_size = 2 \ No newline at end of file diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml new file mode 100644 index 0000000..caf3d67 --- /dev/null +++ b/.github/workflows/npm-publish.yml @@ -0,0 +1,29 @@ +name: npm-publish + +on: + push: + branches: [master] + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 16 + check-latest: true + + - name: npm install + run: npm install + + - name: npm test + run: npm test + + - name: npm build + run: npm run build + + - name: npm pack + run: npm pack + + diff --git a/.npmignore b/.npmignore index 8fb8f02..2eae302 100644 --- a/.npmignore +++ b/.npmignore @@ -1,8 +1,9 @@ +.github +.nyc_output .vscode build/ coverage/ lib/ -.nyc_output node_modules/ package-lock.json diff --git a/index.ts b/index.ts index 7c831be..fad83d9 100644 --- a/index.ts +++ b/index.ts @@ -3,12 +3,14 @@ import aprsParser from './src/parser' import { ConversionConstantEnum, PacketTypeEnum } from './src/enums' import digipeater from './src/digipeater' import telemetry from './src/telemetry' +import { ConversionUtil } from './src/utils/ConversionUtil' import wx from './src/wx' export { aprsPacket , aprsParser , ConversionConstantEnum + , ConversionUtil , digipeater , PacketTypeEnum , telemetry diff --git a/src/parser.ts b/src/parser.ts index 207f018..951208b 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1,6 +1,6 @@ import aprsPacket from './aprsPacket' import { ConversionConstantEnum } from './enums' -import ConversionUtil from './utils/ConversionUtil' +import { ConversionUtil } from './utils/ConversionUtil' import digipeater from './digipeater' import { DST_SYMBOLS } from './DSTSymbols' import { RESULT_MESSAGES } from './ResultMessages' diff --git a/src/utils/ConversionUtil.ts b/src/utils/ConversionUtil.ts index d1abd51..3d4a185 100644 --- a/src/utils/ConversionUtil.ts +++ b/src/utils/ConversionUtil.ts @@ -1,4 +1,4 @@ -export default class ConversionUtil { +export class ConversionUtil { /** * Utility method to replace perl's Date-Calc check_date method. * Given the year, month, and day, this checks to see if it it's a valid date. From 3ba72148aceffdf48ae5382ea4567ff33974346c Mon Sep 17 00:00:00 2001 From: KD0NKS Date: Tue, 11 May 2021 21:09:27 -0500 Subject: [PATCH 3/5] Fixed imports for conversionUtil --- .github/workflows/npm-publish.yml | 2 ++ test/checkDate.test.ts | 2 +- test/degToRad.test.ts | 2 +- test/radToDeg.test.ts | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index caf3d67..649f310 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -3,6 +3,8 @@ name: npm-publish on: push: branches: [master] + pull_request: + branches: [ master ] jobs: publish: diff --git a/test/checkDate.test.ts b/test/checkDate.test.ts index 554641b..3d17d92 100644 --- a/test/checkDate.test.ts +++ b/test/checkDate.test.ts @@ -1,6 +1,6 @@ const assert = require('assert'); -import ConversionUtil from '../src/utils/ConversionUtil'; +import { ConversionUtil } from '../src/utils/ConversionUtil'; describe('checkDate', function() { describe('Test valid checkdate', function() { diff --git a/test/degToRad.test.ts b/test/degToRad.test.ts index ae3623f..f453ab4 100644 --- a/test/degToRad.test.ts +++ b/test/degToRad.test.ts @@ -1,5 +1,5 @@ var assert = require('assert'); -import ConversionUtil from '../src/utils/ConversionUtil'; +import { ConversionUtil } from '../src/utils/ConversionUtil'; describe('#degToRad', function() { it('should return ~0.017453', function() { diff --git a/test/radToDeg.test.ts b/test/radToDeg.test.ts index 9426bb3..4d6ece3 100644 --- a/test/radToDeg.test.ts +++ b/test/radToDeg.test.ts @@ -1,5 +1,5 @@ var assert = require('assert'); -import ConversionUtil from '../src/utils/ConversionUtil'; +import { ConversionUtil } from '../src/utils/ConversionUtil'; describe('#radToDeg', function() { it('should return ~0.017453', function() { From 2ada643c444eb4bfbb5451682e1f039efc80c287 Mon Sep 17 00:00:00 2001 From: KD0NKS Date: Sat, 15 May 2021 17:40:04 -0500 Subject: [PATCH 4/5] Adding manual NPM publish step --- .github/workflows/npm-publish.yml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 649f310..b621797 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -1,9 +1,7 @@ name: npm-publish on: - push: - branches: [master] - pull_request: + workflow_dispatch: branches: [ master ] jobs: @@ -25,7 +23,7 @@ jobs: - name: npm build run: npm run build - - name: npm pack - run: npm pack - - + - name: npm publish + run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} From 31dcc1779f8c3a00188c113d0c0067797b5c7110 Mon Sep 17 00:00:00 2001 From: KD0NKS Date: Sat, 15 May 2021 17:42:28 -0500 Subject: [PATCH 5/5] Adding branch for testing. --- .github/workflows/npm-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index b621797..cad3c79 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -2,7 +2,7 @@ name: npm-publish on: workflow_dispatch: - branches: [ master ] + branches: [ master, 2021-05-08_PacketTypeFix ] jobs: publish: