diff --git a/lib/DateTimeUtils.ts b/lib/DateTimeUtils.ts index efb75f1..e171a4b 100644 --- a/lib/DateTimeUtils.ts +++ b/lib/DateTimeUtils.ts @@ -30,7 +30,7 @@ export class DateTimeUtils { * @returns seconds since midnight */ public static convertHHMMSSToTod(time: string): number { - if(time.length === 4) { // add seconds if not present + if(time.length === 4) { time += '00'; } const h = Number(time.substring(0, 2)); diff --git a/lib/plugins/Label_44_ETA.test.ts b/lib/plugins/Label_44_ETA.test.ts new file mode 100644 index 0000000..6992062 --- /dev/null +++ b/lib/plugins/Label_44_ETA.test.ts @@ -0,0 +1,67 @@ +import { MessageDecoder } from '../MessageDecoder'; +import { Label_44_ETA } from './Label_44_ETA'; + +describe('Label 44 IN', () => { + let plugin: Label_44_ETA; + + beforeEach(() => { + const decoder = new MessageDecoder(); + plugin = new Label_44_ETA(decoder); + }); + + test('matches qualifiers', () => { + expect(plugin.decode).toBeDefined(); + expect(plugin.name).toBe('label-44-eta'); + expect(plugin.qualifiers).toBeDefined(); + expect(plugin.qualifiers()).toEqual({ + labels: ['44'], + preambles: ['00ETA01', '00ETA02', '00ETA03', 'ETA01', 'ETA02', 'ETA03'], + }); + }); + + test('decodes variant 1', () => { + // https://app.airframes.io/messages/3569460297 + const text = '00ETA03,N38241W081357,330,KBNA,KBWI,1107,0123,0208,008.1'; + const decodeResult = plugin.decode({ text: text }); + expect(decodeResult.decoded).toBe(true); + expect(decodeResult.decoder.decodeLevel).toBe('full'); + expect(decodeResult.raw.position.latitude).toBe(38.401666666666664); + expect(decodeResult.raw.position.longitude).toBe(-81.595); + expect(decodeResult.raw.altitude).toBe(33000); + expect(decodeResult.raw.departure_icao).toBe('KBNA'); + expect(decodeResult.raw.arrival_icao).toBe('KBWI'); + expect(decodeResult.raw.month).toBe(11); + expect(decodeResult.raw.day).toBe(7); + expect(decodeResult.raw.time_of_day).toBe(4980); + expect(decodeResult.raw.eta_time).toBe(7680); + expect(decodeResult.formatted.items.length).toBe(9); + expect(decodeResult.formatted.items[0].label).toBe('Aircraft Position'); + expect(decodeResult.formatted.items[0].value).toBe('38.402 N, 81.595 W'); + expect(decodeResult.formatted.items[1].label).toBe('Altitude'); + expect(decodeResult.formatted.items[1].value).toBe('33000 feet'); + expect(decodeResult.formatted.items[2].label).toBe('Origin'); + expect(decodeResult.formatted.items[2].value).toBe('KBNA'); + expect(decodeResult.formatted.items[3].label).toBe('Destination'); + expect(decodeResult.formatted.items[3].value).toBe('KBWI'); + expect(decodeResult.formatted.items[4].label).toBe('Month of Year'); + expect(decodeResult.formatted.items[4].value).toBe('11'); + expect(decodeResult.formatted.items[5].label).toBe('Day of Month'); + expect(decodeResult.formatted.items[5].value).toBe('7'); + expect(decodeResult.formatted.items[6].label).toBe('Message Timestamp'); + expect(decodeResult.formatted.items[6].value).toBe('01:23:00'); + expect(decodeResult.formatted.items[7].label).toBe('Estimated Time of Arrival'); + expect(decodeResult.formatted.items[7].value).toBe('02:08:00'); + expect(decodeResult.formatted.items[8].label).toBe('Fuel Remaining'); + expect(decodeResult.formatted.items[8].value).toBe('8.1'); + }); + + test('does not decode invalid', () => { + + const text = '00OFF01 Bogus message'; + const decodeResult = plugin.decode({ text: text }); + + expect(decodeResult.decoded).toBe(false); + expect(decodeResult.decoder.decodeLevel).toBe('none'); + expect(decodeResult.message.text).toBe(text); + }); +}); diff --git a/lib/plugins/Label_44_ETA.ts b/lib/plugins/Label_44_ETA.ts index 39c5553..e466132 100644 --- a/lib/plugins/Label_44_ETA.ts +++ b/lib/plugins/Label_44_ETA.ts @@ -1,3 +1,4 @@ +import { DateTimeUtils } from '../DateTimeUtils'; import { DecoderPlugin } from '../DecoderPlugin'; import { DecodeResult, Message, Options } from '../DecoderPluginInterface'; import { CoordinateUtils } from '../utils/coordinate_utils'; @@ -14,38 +15,45 @@ export class Label_44_ETA extends DecoderPlugin { }; } - decode(message: Message, options: Options = {}) : DecodeResult { + decode(message: Message, options: Options = {}): DecodeResult { const decodeResult = this.defaultResult(); decodeResult.decoder.name = this.name; decodeResult.formatted.description = 'ETA Report'; decodeResult.message = message; - // Style: IN02,N38338W121179,KMHR,KPDX,0806,2355,005.1 - // Match: IN02,coords,departure_icao,arrival_icao,current_date,current_time,fuel_in_tons - const regex = /^.*,(?.*),(?.*),(?.*),(?.*),(?.*),(?.*)$/; - const results = message.text.match(regex); - if (results?.groups) { + const data = message.text.split(','); + if (data.length >= 9) { if (options.debug) { console.log(`Label 44 ETA Report: groups`); - console.log(results.groups); + console.log(data); } - ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords)); - ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao); - ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao); + ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[1])); + ResultFormatter.altitude(decodeResult, 100 * Number(data[2])); + ResultFormatter.departureAirport(decodeResult, data[3]); + ResultFormatter.arrivalAirport(decodeResult, data[4]); - decodeResult.raw.current_time = Date.parse( - new Date().getFullYear() + "-" + - results.groups.current_date.substr(0, 2) + "-" + - results.groups.current_date.substr(2, 2) + "T" + - results.groups.current_time.substr(0, 2) + ":" + - results.groups.current_time.substr(2, 2) + ":00Z" - ); + ResultFormatter.month(decodeResult, Number(data[5].substring(0, 2))); + ResultFormatter.day(decodeResult, Number(data[5].substring(2, 4))); + ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[6])); + ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[7])); + const fuel = Number(data[8]); + if (!isNaN(fuel)) { + ResultFormatter.remainingFuel(decodeResult, Number(fuel)); + } - if (results.groups.fuel_in_tons != '***' && results.groups.fuel_in_tons != '****') { - ResultFormatter.remainingFuel(decodeResult, Number(results.groups.fuel_in_tons)); + if (data.length > 9) { + ResultFormatter.unknownArr(decodeResult, data.slice(9)); } + } else { + if (options.debug) { + console.log(`Decoder: Unknown 44 message: ${message.text}`); + } + ResultFormatter.unknown(decodeResult, message.text); + decodeResult.decoded = false; + decodeResult.decoder.decodeLevel = 'none'; + return decodeResult; } decodeResult.decoded = true; diff --git a/lib/plugins/Label_44_IN.test.ts b/lib/plugins/Label_44_IN.test.ts new file mode 100644 index 0000000..333c7ff --- /dev/null +++ b/lib/plugins/Label_44_IN.test.ts @@ -0,0 +1,89 @@ +import { decode } from 'punycode'; +import { MessageDecoder } from '../MessageDecoder'; +import { Label_44_IN } from './Label_44_IN'; + +describe('Label 44 IN', () => { + let plugin: Label_44_IN; + + beforeEach(() => { + const decoder = new MessageDecoder(); + plugin = new Label_44_IN(decoder); + }); + + test('matches qualifiers', () => { + expect(plugin.decode).toBeDefined(); + expect(plugin.name).toBe('label-44-in'); + expect(plugin.qualifiers).toBeDefined(); + expect(plugin.qualifiers()).toEqual({ + labels: ['44'], + preambles: ['00IN01', '00IN02', '00IN03', 'IN01', 'IN02', 'IN03'], + }); + }); + + test('decodes variant 1', () => { + // https://app.airframes.io/messages/3563679070 + const text = 'IN01,N33528W084181,KCLT,KPDK,1106,0045,---.-' + const decodeResult = plugin.decode({ text: text }); + expect(decodeResult.decoded).toBe(true); + expect(decodeResult.decoder.decodeLevel).toBe('full'); + expect(decodeResult.raw.position.latitude).toBe(33.88); + expect(decodeResult.raw.position.longitude).toBe(-84.30166666666666); + expect(decodeResult.raw.departure_icao).toBe('KCLT'); + expect(decodeResult.raw.arrival_icao).toBe('KPDK'); + expect(decodeResult.raw.month).toBe(11); + expect(decodeResult.raw.day).toBe(6); + expect(decodeResult.raw.in_time).toBe(2700); + expect(decodeResult.formatted.items.length).toBe(6); + expect(decodeResult.formatted.items[0].label).toBe('Aircraft Position'); + expect(decodeResult.formatted.items[0].value).toBe('33.880 N, 84.302 W'); + expect(decodeResult.formatted.items[1].label).toBe('Origin'); + expect(decodeResult.formatted.items[1].value).toBe('KCLT'); + expect(decodeResult.formatted.items[2].label).toBe('Destination'); + expect(decodeResult.formatted.items[2].value).toBe('KPDK'); + expect(decodeResult.formatted.items[3].label).toBe('Month of Year'); + expect(decodeResult.formatted.items[3].value).toBe('11'); + expect(decodeResult.formatted.items[4].label).toBe('Day of Month'); + expect(decodeResult.formatted.items[4].value).toBe('6'); + expect(decodeResult.formatted.items[5].label).toBe('In Gate Time'); + expect(decodeResult.formatted.items[5].value).toBe('00:45:00'); + }); + + test('decodes variant 2', () => { + const text = 'IN02,N38338W121179,KMHR,KPDX,0806,2355,005.1' + const decodeResult = plugin.decode({ text: text }); + expect(decodeResult.decoded).toBe(true); + expect(decodeResult.decoder.decodeLevel).toBe('full'); + expect(decodeResult.raw.position.latitude).toBe(38.56333333333333); + expect(decodeResult.raw.position.longitude).toBe(-121.29833333333333); + expect(decodeResult.raw.departure_icao).toBe('KMHR'); + expect(decodeResult.raw.arrival_icao).toBe('KPDX'); + expect(decodeResult.raw.month).toBe(8); + expect(decodeResult.raw.day).toBe(6); + expect(decodeResult.raw.in_time).toBe(86100); + expect(decodeResult.formatted.items.length).toBe(7); + expect(decodeResult.formatted.items[0].label).toBe('Aircraft Position'); + expect(decodeResult.formatted.items[0].value).toBe('38.563 N, 121.298 W'); + expect(decodeResult.formatted.items[1].label).toBe('Origin'); + expect(decodeResult.formatted.items[1].value).toBe('KMHR'); + expect(decodeResult.formatted.items[2].label).toBe('Destination'); + expect(decodeResult.formatted.items[2].value).toBe('KPDX'); + expect(decodeResult.formatted.items[3].label).toBe('Month of Year'); + expect(decodeResult.formatted.items[3].value).toBe('8'); + expect(decodeResult.formatted.items[4].label).toBe('Day of Month'); + expect(decodeResult.formatted.items[4].value).toBe('6'); + expect(decodeResult.formatted.items[5].label).toBe('In Gate Time'); + expect(decodeResult.formatted.items[5].value).toBe('23:55:00'); + expect(decodeResult.formatted.items[6].label).toBe('Fuel Remaining'); + expect(decodeResult.formatted.items[6].value).toBe('5.1'); + }); + + test('does not decode invalid', () => { + + const text = '00OFF01 Bogus message'; + const decodeResult = plugin.decode({ text: text }); + + expect(decodeResult.decoded).toBe(false); + expect(decodeResult.decoder.decodeLevel).toBe('none'); + expect(decodeResult.message.text).toBe(text); + }); +}); diff --git a/lib/plugins/Label_44_IN.ts b/lib/plugins/Label_44_IN.ts index 782c84d..b7d021a 100644 --- a/lib/plugins/Label_44_IN.ts +++ b/lib/plugins/Label_44_IN.ts @@ -1,3 +1,4 @@ +import { DateTimeUtils } from '../DateTimeUtils'; import { DecoderPlugin } from '../DecoderPlugin'; import { DecodeResult, Message, Options } from '../DecoderPluginInterface'; import { CoordinateUtils } from '../utils/coordinate_utils'; @@ -14,38 +15,42 @@ export class Label_44_IN extends DecoderPlugin { }; } - decode(message: Message, options: Options = {}) : DecodeResult { + decode(message: Message, options: Options = {}): DecodeResult { const decodeResult = this.defaultResult(); decodeResult.decoder.name = this.name; decodeResult.formatted.description = 'In Air Report'; decodeResult.message = message; - // Style: IN02,N38338W121179,KMHR,KPDX,0806,2355,005.1 - // Match: IN02,coords,departure_icao,arrival_icao,current_date,current_time,fuel_in_tons - const regex = /^.*,(?.*),(?.*),(?.*),(?.*),(?.*),(?.*)$/; - const results = message.text.match(regex); - if (results?.groups) { + const data = message.text.split(','); + if (data.length >= 7) { if (options.debug) { console.log(`Label 44 In Air Report: groups`); - console.log(results.groups); + console.log(data); } - ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords)); - ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao); - ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao); - - decodeResult.raw.current_time = Date.parse( - new Date().getFullYear() + "-" + - results.groups.current_date.substr(0, 2) + "-" + - results.groups.current_date.substr(2, 2) + "T" + - results.groups.current_time.substr(0, 2) + ":" + - results.groups.current_time.substr(2, 2) + ":00Z" - ); + ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[1])); + ResultFormatter.departureAirport(decodeResult, data[2]); + ResultFormatter.arrivalAirport(decodeResult, data[3]); + ResultFormatter.month(decodeResult, Number(data[4].substring(0, 2))); + ResultFormatter.day(decodeResult, Number(data[4].substring(2, 4))); + ResultFormatter.in(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[5])); + const fuel = Number(data[6]); + if (!isNaN(fuel)) { + ResultFormatter.remainingFuel(decodeResult, Number(fuel)); + } - if (results.groups.fuel_in_tons != '***' && results.groups.fuel_in_tons != '****') { - decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons); + if (data.length > 7) { + ResultFormatter.unknownArr(decodeResult, data.slice(7)); } + } else { + if (options.debug) { + console.log(`Decoder: Unknown 44 message: ${message.text}`); + } + ResultFormatter.unknown(decodeResult, message.text); + decodeResult.decoded = false; + decodeResult.decoder.decodeLevel = 'none'; + return decodeResult; } decodeResult.decoded = true; diff --git a/lib/plugins/Label_44_OFF.test.ts b/lib/plugins/Label_44_OFF.test.ts new file mode 100644 index 0000000..a914bc2 --- /dev/null +++ b/lib/plugins/Label_44_OFF.test.ts @@ -0,0 +1,65 @@ +import { decode } from 'punycode'; +import { MessageDecoder } from '../MessageDecoder'; +import { Label_44_OFF } from './Label_44_OFF'; + +describe('Label 44 OFF', () => { + let plugin: Label_44_OFF; + + beforeEach(() => { + const decoder = new MessageDecoder(); + plugin = new Label_44_OFF(decoder); + }); + + test('matches qualifiers', () => { + expect(plugin.decode).toBeDefined(); + expect(plugin.name).toBe('label-44-off'); + expect(plugin.qualifiers).toBeDefined(); + expect(plugin.qualifiers()).toEqual({ + labels: ['44'], + preambles: ['00OFF01', '00OFF02', '00OFF03', 'OFF01', 'OFF02', 'OFF03'], + }); + }); + + test('decodes variant 1', () => { + const text = 'OFF02,N39247W077226,KFDK,KSNA,1106,2124,0248,011.1' + const decodeResult = plugin.decode({ text: text }); + expect(decodeResult.decoded).toBe(true); + expect(decodeResult.decoder.decodeLevel).toBe('full'); + expect(decodeResult.raw.position.latitude).toBe(39.41166666666667); + expect(decodeResult.raw.position.longitude).toBe(-77.37666666666667); + expect(decodeResult.raw.departure_icao).toBe('KFDK'); + expect(decodeResult.raw.arrival_icao).toBe('KSNA'); + expect(decodeResult.raw.month).toBe(11); + expect(decodeResult.raw.day).toBe(6); + expect(decodeResult.raw.off_time).toBe(77040); + expect(decodeResult.raw.eta_time).toBe(10080); + expect(decodeResult.raw.fuel_remaining).toBe(11.1); + expect(decodeResult.formatted.items.length).toBe(8); + expect(decodeResult.formatted.items[0].label).toBe('Aircraft Position'); + expect(decodeResult.formatted.items[0].value).toBe('39.412 N, 77.377 W'); + expect(decodeResult.formatted.items[1].label).toBe('Origin'); + expect(decodeResult.formatted.items[1].value).toBe('KFDK'); + expect(decodeResult.formatted.items[2].label).toBe('Destination'); + expect(decodeResult.formatted.items[2].value).toBe('KSNA'); + expect(decodeResult.formatted.items[3].label).toBe('Month of Year'); + expect(decodeResult.formatted.items[3].value).toBe('11'); + expect(decodeResult.formatted.items[4].label).toBe('Day of Month'); + expect(decodeResult.formatted.items[4].value).toBe('6'); + expect(decodeResult.formatted.items[5].label).toBe('Takeoff Time'); + expect(decodeResult.formatted.items[5].value).toBe('21:24:00'); + expect(decodeResult.formatted.items[6].label).toBe('Estimated Time of Arrival'); + expect(decodeResult.formatted.items[6].value).toBe('02:48:00'); + expect(decodeResult.formatted.items[7].label).toBe('Fuel Remaining'); + expect(decodeResult.formatted.items[7].value).toBe('11.1'); + }); + + test('does not decode invalid', () => { + + const text = '00OFF01 Bogus message'; + const decodeResult = plugin.decode({ text: text }); + + expect(decodeResult.decoded).toBe(false); + expect(decodeResult.decoder.decodeLevel).toBe('none'); + expect(decodeResult.message.text).toBe(text); + }); +}); diff --git a/lib/plugins/Label_44_OFF.ts b/lib/plugins/Label_44_OFF.ts index 3961d14..813cc34 100644 --- a/lib/plugins/Label_44_OFF.ts +++ b/lib/plugins/Label_44_OFF.ts @@ -1,3 +1,4 @@ +import { DateTimeUtils } from '../DateTimeUtils'; import { DecoderPlugin } from '../DecoderPlugin'; import { DecodeResult, Message, Options } from '../DecoderPluginInterface'; import { CoordinateUtils } from '../utils/coordinate_utils'; @@ -14,45 +15,44 @@ export class Label_44_OFF extends DecoderPlugin { }; } - decode(message: Message, options: Options = {}) : DecodeResult { + decode(message: Message, options: Options = {}): DecodeResult { const decodeResult = this.defaultResult(); decodeResult.decoder.name = this.name; decodeResult.formatted.description = 'Off Runway Report'; decodeResult.message = message; - // Style: OFF02,N38334W121176,KMHR,KPDX,0807,0014,0123,004.9 - // Match: OFF02,coords,departure_icao,arrival_icao,current_date,current_time,eta_time,fuel_in_tons - const regex = /^.*,(?.*),(?.*),(?.*),(?.*),(?.*),(?.*),(?.*)$/; - const results = message.text.match(regex); - if (results?.groups) { + + const data = message.text.split(','); + if (data.length >= 8) { if (options.debug) { console.log(`Label 44 Off Runway Report: groups`); - console.log(results.groups); + console.log(data); } - ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords)); - ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao); - ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao); - - decodeResult.raw.current_time = Date.parse( - new Date().getFullYear() + "-" + - results.groups.current_date.substr(0, 2) + "-" + - results.groups.current_date.substr(2, 2) + "T" + - results.groups.current_time.substr(0, 2) + ":" + - results.groups.current_time.substr(2, 2) + ":00Z" - ); - decodeResult.raw.eta_time = Date.parse( - new Date().getFullYear() + "-" + - results.groups.current_date.substr(0, 2) + "-" + - results.groups.current_date.substr(2, 2) + "T" + - results.groups.eta_time.substr(0, 2) + ":" + - results.groups.eta_time.substr(2, 2) + ":00Z" - ); + ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[1])); + ResultFormatter.departureAirport(decodeResult, data[2]); + ResultFormatter.arrivalAirport(decodeResult, data[3]); + ResultFormatter.month(decodeResult, Number(data[4].substring(0, 2))); + ResultFormatter.day(decodeResult, Number(data[4].substring(2, 4))); + ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[5])); + ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[6])); + const fuel = Number(data[7]); + if (!isNaN(fuel)) { + ResultFormatter.remainingFuel(decodeResult, Number(fuel)); + } - if (results.groups.fuel_in_tons != '***' && results.groups.fuel_in_tons != '****') { - decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons); + if (data.length > 8) { + ResultFormatter.unknownArr(decodeResult, data.slice(8)); } + } else { + if (options.debug) { + console.log(`Decoder: Unknown 44 message: ${message.text}`); + } + ResultFormatter.unknown(decodeResult, message.text); + decodeResult.decoded = false; + decodeResult.decoder.decodeLevel = 'none'; + return decodeResult; } decodeResult.decoded = true; diff --git a/lib/plugins/Label_44_ON.test.ts b/lib/plugins/Label_44_ON.test.ts new file mode 100644 index 0000000..3014e18 --- /dev/null +++ b/lib/plugins/Label_44_ON.test.ts @@ -0,0 +1,89 @@ +import { decode } from 'punycode'; +import { MessageDecoder } from '../MessageDecoder'; +import { Label_44_ON } from './Label_44_ON'; + +describe('Label 44 ON', () => { + let plugin: Label_44_ON; + + beforeEach(() => { + const decoder = new MessageDecoder(); + plugin = new Label_44_ON(decoder); + }); + + test('matches qualifiers', () => { + expect(plugin.decode).toBeDefined(); + expect(plugin.name).toBe('label-44-on'); + expect(plugin.qualifiers).toBeDefined(); + expect(plugin.qualifiers()).toEqual({ + labels: ['44'], + preambles: ['00ON01', '00ON02', '00ON03', 'ON01', 'ON02', 'ON03'], + }); + }); + + test('decodes variant 1', () => { + // https://app.airframes.io/messages/3563679058 + const text = 'ON01,N33522W084181,KCLT,KPDK,1106,004023,---.-,' + const decodeResult = plugin.decode({ text: text }); + expect(decodeResult.decoded).toBe(true); + expect(decodeResult.decoder.decodeLevel).toBe('full'); + expect(decodeResult.raw.position.latitude).toBe(33.87); + expect(decodeResult.raw.position.longitude).toBe(-84.30166666666666); + expect(decodeResult.raw.departure_icao).toBe('KCLT'); + expect(decodeResult.raw.arrival_icao).toBe('KPDK'); + expect(decodeResult.raw.month).toBe(11); + expect(decodeResult.raw.day).toBe(6); + expect(decodeResult.raw.on_time).toBe(2423); + expect(decodeResult.formatted.items.length).toBe(6); + expect(decodeResult.formatted.items[0].label).toBe('Aircraft Position'); + expect(decodeResult.formatted.items[0].value).toBe('33.870 N, 84.302 W'); + expect(decodeResult.formatted.items[1].label).toBe('Origin'); + expect(decodeResult.formatted.items[1].value).toBe('KCLT'); + expect(decodeResult.formatted.items[2].label).toBe('Destination'); + expect(decodeResult.formatted.items[2].value).toBe('KPDK'); + expect(decodeResult.formatted.items[3].label).toBe('Month of Year'); + expect(decodeResult.formatted.items[3].value).toBe('11'); + expect(decodeResult.formatted.items[4].label).toBe('Day of Month'); + expect(decodeResult.formatted.items[4].value).toBe('6'); + expect(decodeResult.formatted.items[5].label).toBe('Landing Time'); + expect(decodeResult.formatted.items[5].value).toBe('00:40:23'); + }); + + test('decodes variant 2', () => { + const text = 'ON02,N38333W121178,KRNO,KMHR,0806,2350,005.2' + const decodeResult = plugin.decode({ text: text }); + expect(decodeResult.decoded).toBe(true); + expect(decodeResult.decoder.decodeLevel).toBe('full'); + expect(decodeResult.raw.position.latitude).toBe(38.555); + expect(decodeResult.raw.position.longitude).toBe(-121.29666666666667); + expect(decodeResult.raw.departure_icao).toBe('KRNO'); + expect(decodeResult.raw.arrival_icao).toBe('KMHR'); + expect(decodeResult.raw.month).toBe(8); + expect(decodeResult.raw.day).toBe(6); + expect(decodeResult.raw.on_time).toBe(85800); + expect(decodeResult.formatted.items.length).toBe(7); + expect(decodeResult.formatted.items[0].label).toBe('Aircraft Position'); + expect(decodeResult.formatted.items[0].value).toBe('38.555 N, 121.297 W'); + expect(decodeResult.formatted.items[1].label).toBe('Origin'); + expect(decodeResult.formatted.items[1].value).toBe('KRNO'); + expect(decodeResult.formatted.items[2].label).toBe('Destination'); + expect(decodeResult.formatted.items[2].value).toBe('KMHR'); + expect(decodeResult.formatted.items[3].label).toBe('Month of Year'); + expect(decodeResult.formatted.items[3].value).toBe('8'); + expect(decodeResult.formatted.items[4].label).toBe('Day of Month'); + expect(decodeResult.formatted.items[4].value).toBe('6'); + expect(decodeResult.formatted.items[5].label).toBe('Landing Time'); + expect(decodeResult.formatted.items[5].value).toBe('23:50:00'); + expect(decodeResult.formatted.items[6].label).toBe('Fuel Remaining'); + expect(decodeResult.formatted.items[6].value).toBe('5.2'); + }); + + test('does not decode invalid', () => { + + const text = '00OFF01 Bogus message'; + const decodeResult = plugin.decode({ text: text }); + + expect(decodeResult.decoded).toBe(false); + expect(decodeResult.decoder.decodeLevel).toBe('none'); + expect(decodeResult.message.text).toBe(text); + }); +}); diff --git a/lib/plugins/Label_44_ON.ts b/lib/plugins/Label_44_ON.ts index 2f4e7ee..f275abf 100644 --- a/lib/plugins/Label_44_ON.ts +++ b/lib/plugins/Label_44_ON.ts @@ -1,3 +1,4 @@ +import { DateTimeUtils } from '../DateTimeUtils'; import { DecoderPlugin } from '../DecoderPlugin'; import { DecodeResult, Message, Options } from '../DecoderPluginInterface'; import { CoordinateUtils } from '../utils/coordinate_utils'; @@ -14,38 +15,42 @@ export class Label_44_ON extends DecoderPlugin { }; } - decode(message: Message, options: Options = {}) : DecodeResult { + decode(message: Message, options: Options = {}): DecodeResult { const decodeResult = this.defaultResult(); decodeResult.decoder.name = this.name; decodeResult.formatted.description = 'On Runway Report'; decodeResult.message = message; - // Style: ON02,N38333W121178,KRNO,KMHR,0806,2350,005.2 - // Match: ON02,coords,departure_icao,arrival_icao,current_date,current_time,fuel_in_tons - const regex = /^.*,(?.*),(?.*),(?.*),(?.*),(?.*),(?.*)$/; - const results = message.text.match(regex); - if (results?.groups) { + const data = message.text.split(','); + if (data.length >= 7) { if (options.debug) { console.log(`Label 44 On Runway Report: groups`); - console.log(results.groups); + console.log(data); } - ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords)); - ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao); - ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao); - - decodeResult.raw.current_time = Date.parse( - new Date().getFullYear() + "-" + - results.groups.current_date.substr(0, 2) + "-" + - results.groups.current_date.substr(2, 2) + "T" + - results.groups.current_time.substr(0, 2) + ":" + - results.groups.current_time.substr(2, 2) + ":00Z" - ); + ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[1])); + ResultFormatter.departureAirport(decodeResult, data[2]); + ResultFormatter.arrivalAirport(decodeResult, data[3]); + ResultFormatter.month(decodeResult, Number(data[4].substring(0, 2))); + ResultFormatter.day(decodeResult, Number(data[4].substring(2, 4))); + ResultFormatter.on(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[5])); + const fuel = Number(data[6]); + if (!isNaN(fuel)) { + ResultFormatter.remainingFuel(decodeResult, Number(fuel)); + } - if (results.groups.fuel_in_tons != '***' && results.groups.fuel_in_tons != '****') { - ResultFormatter.remainingFuel(decodeResult, Number(results.groups.fuel_in_tons)); + if (data.length > 7) { + ResultFormatter.unknownArr(decodeResult, data.slice(7)); } + } else { + if (options.debug) { + console.log(`Decoder: Unknown 44 message: ${message.text}`); + } + ResultFormatter.unknown(decodeResult, message.text); + decodeResult.decoded = false; + decodeResult.decoder.decodeLevel = 'none'; + return decodeResult; } decodeResult.decoded = true; diff --git a/lib/utils/result_formatter.ts b/lib/utils/result_formatter.ts index e63b103..44e152a 100644 --- a/lib/utils/result_formatter.ts +++ b/lib/utils/result_formatter.ts @@ -327,7 +327,7 @@ export class ResultFormatter { static day(decodeResult: DecodeResult, day: number) { decodeResult.raw.day = day; decodeResult.formatted.items.push({ - type: 'day_of_month', + type: 'day', code: 'MSG_DAY', label: 'Day of Month', value: `${day}`, @@ -337,7 +337,7 @@ export class ResultFormatter { static month(decodeResult: DecodeResult, month: number) { decodeResult.raw.month = month; decodeResult.formatted.items.push({ - type: 'month_of_year', + type: 'month', code: 'MSG_MON', label: 'Month of Year', value: `${month}`, @@ -347,7 +347,7 @@ export class ResultFormatter { static departureDay(decodeResult: DecodeResult, day: number) { decodeResult.raw.departure_day = day; decodeResult.formatted.items.push({ - type: 'day_of_month', + type: 'day', code: 'DEP_DAY', label: 'Departure Day', value: `${day}`, @@ -357,7 +357,7 @@ export class ResultFormatter { static arrivalDay(decodeResult: DecodeResult, day: number) { decodeResult.raw.arrival_day = day; decodeResult.formatted.items.push({ - type: 'day_of_month', + type: 'day', code: 'ARR_DAY', label: 'Arrival Day', value: `${day}`,