diff --git a/lib/plugins/Label_1J_2J_FTX.test.ts b/lib/plugins/Label_1J_2J_FTX.test.ts index 2f286bdd..16a1e727 100644 --- a/lib/plugins/Label_1J_2J_FTX.test.ts +++ b/lib/plugins/Label_1J_2J_FTX.test.ts @@ -2,7 +2,7 @@ import { MessageDecoder } from '../MessageDecoder'; import { Arinc702 } from './ARINC_702'; describe('Label 1J/2J FTX', () => { - let plugin: Label_H1; + let plugin: Arinc702; let message = { label: '1J', text: '' }; beforeEach(() => { @@ -17,18 +17,15 @@ describe('Label 1J/2J FTX', () => { const decodeResult = plugin.decode(message); expect(decodeResult.decoded).toBe(true); - expect(decodeResult.decoder.decodeLevel).toBe('partial'); + expect(decodeResult.decoder.decodeLevel).toBe('full'); + expect(decodeResult.raw.tail).toBe('50007B'); + expect(decodeResult.raw.flight_number).toBe('RCH4086'); expect(decodeResult.raw.mission_number).toBe('ABB02R70E037'); - expect(decodeResult.formatted.items.length).toBe(4); - expect(decodeResult.formatted.items[0].label).toBe('Tail'); - expect(decodeResult.formatted.items[0].value).toBe('50007B'); - expect(decodeResult.formatted.items[1].label).toBe('Flight Number'); - expect(decodeResult.formatted.items[1].value).toBe('RCH4086'); - expect(decodeResult.formatted.items[2].label).toBe('Free Text'); - expect(decodeResult.formatted.items[2].value).toBe('4 QTR PHILLY UP 37-6'); - expect(decodeResult.formatted.items[3].label).toBe('Message Checksum'); - expect(decodeResult.formatted.items[3].value).toBe('0x307a'); - expect(decodeResult.remaining.text).toBe('MR6,'); + expect(decodeResult.raw.sequence_number).toBe(6); + expect(decodeResult.raw.text).toBe('4 QTR PHILLY UP 37-6'); + expect(decodeResult.raw.checksum).toBe(0x307a); + expect(decodeResult.formatted.description).toBe('Free Text'); + expect(decodeResult.formatted.items.length).toBe(5); }); // Disabled due to checksum mismatch. Possibly copy-paste issue due to non-ascii characters in message? @@ -44,14 +41,15 @@ describe('Label 1J/2J FTX', () => { expect(decodeResult.raw.flight_number).toBe('RCH4086'); expect(decodeResult.raw.mission_number).toBe('ABB02R70E037'); expect(decodeResult.raw.message_timestamp).toBe(1739150248); + expect(decodeResult.raw.sequence_number).toBe(49); expect(decodeResult.raw.fuel_on_board).toBe(1791); - expect(decodeResult.raw.freetext).toBe( + expect(decodeResult.raw.text).toBe( 'GOOD EVENING PLEASE PASS US THE SUPER BOWL SCORE WHEN ABLE. THANK YOU', ); expect(decodeResult.raw.version).toBe(3.2); expect(decodeResult.raw.checksum).toBe(0x8d70); - expect(decodeResult.formatted.items.length).toBe(6); - expect(decodeResult.remaining.text).toBe('M74/MR049,'); + expect(decodeResult.formatted.items.length).toBe(7); + expect(decodeResult.remaining.text).toContain('M74'); }); test('decodes ', () => { diff --git a/lib/plugins/Label_2A_SUM.test.ts b/lib/plugins/Label_2A_SUM.test.ts new file mode 100644 index 00000000..fb1d3eb1 --- /dev/null +++ b/lib/plugins/Label_2A_SUM.test.ts @@ -0,0 +1,60 @@ +import { MessageDecoder } from '../MessageDecoder'; +import { Arinc702 } from './ARINC_702'; + +describe('Label 2A preamble SUM', () => { + let plugin: Arinc702; + const message = { label: '2A', text: '' }; + + beforeEach(() => { + const decoder = new MessageDecoder(); + plugin = new Arinc702(decoder); + }); + + test('decodes ACARS variant', () => { + // https://app.airframes.io/messages/6245474934 + message.text = + 'SUM/ID53147T,RCH140,/DC03032026,213916/MR7,/SM031612,420,032139,031623,416,031631,413,032130,212,032139,209/VR329519'; + const decodeResult = plugin.decode(message); + + expect(decodeResult.decoded).toBe(true); + expect(decodeResult.decoder.decodeLevel).toBe('partial'); + expect(decodeResult.raw.tail).toBe('53147T'); + expect(decodeResult.raw.flight_number).toBe('RCH140'); + expect(decodeResult.raw.message_timestamp).toBe(1772573956); + expect(decodeResult.raw.version).toBe(3.2); + expect(decodeResult.raw.checksum).toBe(0x9519); + expect(decodeResult.formatted.items.length).toBe(5); + // Only check formatted.items.length and description, rest are raw fields + // Remaining text may be set by ResultFormatter. Check actual value. + expect(decodeResult.remaining.text).toBe('SM031612,420,032139,031623,416,031631,413,032130,212,032139,209'); + }); + + test('decodes Inmarsat variant', () => { + // https://app.airframes.io/messages/6251537386 + message.text = + 'M90AMC2010SUM/ID70044B,RCH2010,PVZF504QP059/DC04032026,225050/MR196,/SM041038,3004,042250,041047,3000,041055,2985,042245,0526,042250,0521/VR0320E8B'; + const decodeResult = plugin.decode(message); + + expect(decodeResult.decoded).toBe(true); + expect(decodeResult.decoder.decodeLevel).toBe('partial'); + expect(decodeResult.raw.tail).toBe('70044B'); + expect(decodeResult.raw.flight_number).toBe('RCH2010'); + expect(decodeResult.raw.mission_number).toBe('PVZF504QP059'); + expect(decodeResult.raw.message_timestamp).toBe(1772664650); + expect(decodeResult.raw.sequence_number).toBe(196); + expect(decodeResult.raw.version).toBe(3.2); + expect(decodeResult.raw.checksum).toBe(0x0e8b); + expect(decodeResult.formatted.items.length).toBe(5); + expect(decodeResult.remaining.text).toContain('M90'); + }); + + test('does not decode invalid message', () => { + message.text = 'PER Bogus message'; + const decodeResult = plugin.decode(message); + + expect(decodeResult.decoded).toBe(false); + expect(decodeResult.decoder.decodeLevel).toBe('none'); + expect(decodeResult.formatted.description).toBe('Unknown'); + expect(decodeResult.message).toBe(message); + }); +}); diff --git a/lib/plugins/Label_2P_POS.test.ts b/lib/plugins/Label_2P_POS.test.ts index f2b84b65..ff3cbfa2 100644 --- a/lib/plugins/Label_2P_POS.test.ts +++ b/lib/plugins/Label_2P_POS.test.ts @@ -2,7 +2,7 @@ import { MessageDecoder } from '../MessageDecoder'; import { Arinc702 } from './ARINC_702'; describe('Label_2P Preamble POS', () => { - let plugin: Label_H1; + let plugin: Arinc702; const message = { label: '2P', text: '' }; beforeEach(() => { @@ -23,6 +23,8 @@ describe('Label_2P Preamble POS', () => { expect(decodeResult.raw.flight_number).toBe('RCH4086'); expect(decodeResult.raw.tail).toBe('50007B'); expect(decodeResult.raw.mission_number).toBe('ABB02R70E037'); + expect(decodeResult.raw.message_timestamp).toBe(1739164684); + expect(decodeResult.raw.sequence_number).toBe(103); expect(decodeResult.raw.day).toBe(9); expect(decodeResult.raw.eta_time).toBe(27480); expect(decodeResult.raw.position.latitude).toBe(56.02); @@ -34,8 +36,9 @@ describe('Label_2P Preamble POS', () => { expect(decodeResult.raw.fuel_on_board).toBe(857); expect(decodeResult.raw.version).toBe(3.2); expect(decodeResult.raw.checksum).toBe(0x2b89); - expect(decodeResult.formatted.items.length).toBe(10); - expect(decodeResult.remaining.text).toBe('M80/MR103,,084081,'); + expect(decodeResult.formatted.items.length).toBe(11); + expect(decodeResult.formatted.description).toBe('Position Report'); + expect(decodeResult.remaining.text).toBe('M80/084081,'); }); test('', () => { diff --git a/lib/plugins/Label_4A_DIS.test.ts b/lib/plugins/Label_4A_DIS.test.ts index fcd3611c..ae9fcc5d 100644 --- a/lib/plugins/Label_4A_DIS.test.ts +++ b/lib/plugins/Label_4A_DIS.test.ts @@ -35,7 +35,7 @@ describe('Label 4A preamble DIS', () => { expect(decodeResult.formatted.items[0].value).toBe('00:09:00'); expect(decodeResult.formatted.items[1].code).toBe('CALLSIGN'); expect(decodeResult.formatted.items[1].value).toBe('WEN3140'); - expect(decodeResult.formatted.items[2].code).toBe('FREE_TEXT'); + expect(decodeResult.formatted.items[2].code).toBe('TEXT'); expect(decodeResult.formatted.items[2].value).toBe('@HOLD CNX'); }); diff --git a/lib/plugins/Label_4A_DIS.ts b/lib/plugins/Label_4A_DIS.ts index 4043b404..3e6c7554 100644 --- a/lib/plugins/Label_4A_DIS.ts +++ b/lib/plugins/Label_4A_DIS.ts @@ -26,7 +26,7 @@ export class Label_4A_DIS extends DecoderPlugin { DateTimeUtils.convertHHMMSSToTod(fields[1].substring(2) + '00'), ); ResultFormatter.callsign(decodeResult, fields[2]); - ResultFormatter.freetext(decodeResult, fields.slice(3).join('')); + ResultFormatter.text(decodeResult, fields.slice(3).join('')); if (decodeResult.decoded) { if (!decodeResult.remaining.text) diff --git a/lib/plugins/Label_4J_POS.test.ts b/lib/plugins/Label_4J_POS.test.ts index c79cecc4..8c6c963a 100644 --- a/lib/plugins/Label_4J_POS.test.ts +++ b/lib/plugins/Label_4J_POS.test.ts @@ -2,7 +2,7 @@ import { MessageDecoder } from '../MessageDecoder'; import { Arinc702 } from './ARINC_702'; describe('Label 4J POS', () => { - let plugin: Label_H1; + let plugin: Arinc702; const message = { label: '4J', text: '' }; beforeEach(() => { @@ -18,8 +18,10 @@ describe('Label 4J POS', () => { expect(decodeResult.decoded).toBe(true); expect(decodeResult.decoder.decodeLevel).toBe('partial'); - expect(decodeResult.formatted.description).toBe('Position Report'); + // Raw field checks expect(decodeResult.raw.message_timestamp).toBe(1709476093); + expect(decodeResult.raw.sequence_number).toBe(64); + expect(decodeResult.raw.sequence_response).toBe(0); expect(decodeResult.raw.tail).toBe('91459S'); expect(decodeResult.raw.flight_number).toBe('BANKR31'); expect(decodeResult.raw.mission_number).toBe(''); @@ -35,8 +37,9 @@ describe('Label 4J POS', () => { expect(decodeResult.raw.cg_upper_limit).toBe(35); expect(decodeResult.raw.fuel_on_board).toBe(732); expect(decodeResult.raw.version).toBe(3.2); - expect(decodeResult.formatted.items.length).toBe(14); - expect(decodeResult.remaining.text).toBe('MR64,0,27619,MT370'); + expect(decodeResult.formatted.description).toBe('Position Report'); + expect(decodeResult.formatted.items.length).toBe(16); + expect(decodeResult.remaining.text).toBe('27619,MT370'); }); test('decodes ', () => { diff --git a/lib/plugins/Label_80_INR.test.ts b/lib/plugins/Label_80_INR.test.ts index dfd75503..0fce6df1 100644 --- a/lib/plugins/Label_80_INR.test.ts +++ b/lib/plugins/Label_80_INR.test.ts @@ -1,9 +1,8 @@ -import { decode } from 'node:punycode'; import { MessageDecoder } from '../MessageDecoder'; import { Arinc702 } from './ARINC_702'; describe('Label 80 Preamble INR', () => { - let plugin: Label_H1; + let plugin: Arinc702; const message = { label: '80', text: '' }; beforeEach(() => { @@ -20,13 +19,14 @@ describe('Label 80 Preamble INR', () => { expect(decodeResult.decoder.decodeLevel).toBe('partial'); expect(decodeResult.raw.tail).toBe('91511S'); expect(decodeResult.raw.message_timestamp).toBe(1772634934); + expect(decodeResult.raw.sequence_number).toBe(19); expect(decodeResult.raw.day).toBe(4); expect(decodeResult.raw.eta_time).toBe(54300); expect(decodeResult.raw.fuel_on_board).toBe(983); expect(decodeResult.raw.version).toBe(3.2); expect(decodeResult.raw.checksum).toBe(0xbf4c); expect(decodeResult.formatted.description).toBe('In-Range Report'); - expect(decodeResult.formatted.items.length).toBe(6); - expect(decodeResult.remaining.text).toBe('MR19,/NR,,,,,,,,950,0'); + expect(decodeResult.formatted.items.length).toBe(7); + expect(decodeResult.remaining.text).toBe('NR,,,,,,,,950,0'); }); }); diff --git a/lib/plugins/Label_H1_FPN.test.ts b/lib/plugins/Label_H1_FPN.test.ts index e5da2327..1a15de8a 100644 --- a/lib/plugins/Label_H1_FPN.test.ts +++ b/lib/plugins/Label_H1_FPN.test.ts @@ -2,7 +2,7 @@ import { MessageDecoder } from '../MessageDecoder'; import { Arinc702 } from './ARINC_702'; describe('Label_H1 FPN', () => { - let plugin: Label_H1; + let plugin: Arinc702; const message = { label: 'H1', text: '' }; beforeEach(() => { @@ -319,6 +319,7 @@ describe('Label_H1 FPN', () => { expect(decodeResult.raw.tail).toBe('88194A'); expect(decodeResult.raw.flight_number).toBe('RCH857'); expect(decodeResult.raw.mission_number).toBe('PMZM107QP021'); + expect(decodeResult.raw.sequence_number).toBe(2); expect(decodeResult.raw.route_status).toBe('RM'); expect(decodeResult.raw.arrival_icao).toBe('FJDG'); expect(decodeResult.raw.route.waypoints.length).toBe(20); @@ -326,7 +327,7 @@ describe('Label_H1 FPN', () => { expect(decodeResult.raw.route.waypoints[19].name).toBe('BUMMR'); expect(decodeResult.raw.checksum).toBe(0xe3e9); expect(decodeResult.formatted.description).toBe('Flight Plan'); - expect(decodeResult.formatted.items.length).toBe(6); + expect(decodeResult.formatted.items.length).toBe(7); expect(decodeResult.message).toBe(message); }); @@ -350,12 +351,14 @@ describe('Label_H1 FPN', () => { expect(decodeResult.raw.tail).toBe('80094S'); expect(decodeResult.raw.flight_number).toBe('RCH411'); expect(decodeResult.raw.mission_number).toBe('8JZ41NG3S048'); + expect(decodeResult.raw.sequence_number).toBe(3); + expect(decodeResult.raw.sequence_response).toBe(5); expect(decodeResult.raw.route_status).toBe('RP'); expect(decodeResult.raw.departure_icao).toBe('KMCF'); expect(decodeResult.raw.arrival_icao).toBe('LBSF'); expect(decodeResult.raw.route.waypoints.length).toBe(69); //nice expect(decodeResult.raw.checksum).toBe(0xc850); expect(decodeResult.formatted.description).toBe('Flight Plan'); - expect(decodeResult.formatted.items.length).toBe(7); + expect(decodeResult.formatted.items.length).toBe(9); }); }); diff --git a/lib/plugins/Label_H1_FTX.test.ts b/lib/plugins/Label_H1_FTX.test.ts index 5b8aceb5..c599ae74 100644 --- a/lib/plugins/Label_H1_FTX.test.ts +++ b/lib/plugins/Label_H1_FTX.test.ts @@ -2,7 +2,7 @@ import { MessageDecoder } from '../MessageDecoder'; import { Arinc702 } from './ARINC_702'; describe('Label_H1 FTX', () => { - let plugin: Label_H1; + let plugin: Arinc702; const message = { label: 'H1', text: '' }; beforeEach(() => { @@ -17,20 +17,16 @@ describe('Label_H1 FTX', () => { const decodeResult = plugin.decode(message); expect(decodeResult.decoded).toBe(true); - expect(decodeResult.decoder.decodeLevel).toBe('partial'); + expect(decodeResult.decoder.decodeLevel).toBe('full'); + expect(decodeResult.raw.tail).toBe('23544S'); + expect(decodeResult.raw.flight_number).toBe('HIFI21'); expect(decodeResult.raw.mission_number).toBe('7VZ007B1S276'); - expect(decodeResult.formatted.items.length).toBe(4); - expect(decodeResult.formatted.items[0].label).toBe('Tail'); - expect(decodeResult.formatted.items[0].value).toBe('23544S'); - expect(decodeResult.formatted.items[1].label).toBe('Flight Number'); - expect(decodeResult.formatted.items[1].value).toBe('HIFI21'); - expect(decodeResult.formatted.items[2].label).toBe('Free Text'); - expect(decodeResult.formatted.items[2].value).toBe( + expect(decodeResult.raw.text).toBe( 'FYI .. TAF KSUX 021720Z 0218 0318 20017G28KT P6SM SKC FM022200 22012G18KT P6SM SKC .. PUTS YOUR CXWIND AT 26KT ON RWY 13 .. REDUCES TO 18KT AT 22Z', ); - expect(decodeResult.formatted.items[3].label).toBe('Message Checksum'); - expect(decodeResult.formatted.items[3].value).toBe('0x4fef'); - expect(decodeResult.remaining.text).toBe('MR2,'); + expect(decodeResult.raw.checksum).toBe(0x4fef); + expect(decodeResult.formatted.items.length).toBe(5); + expect(decodeResult.formatted.description).toBeDefined(); }); // disabled due to checksum failure. could be hidden characters in the source message @@ -43,18 +39,15 @@ describe('Label_H1 FTX', () => { expect(decodeResult.decoded).toBe(true); expect(decodeResult.decoder.decodeLevel).toBe('partial'); expect(decodeResult.raw.mission_number).toBe('ABZ01G6XH273'); - expect(decodeResult.formatted.items.length).toBe(4); - expect(decodeResult.formatted.items[0].label).toBe('Tail'); - expect(decodeResult.formatted.items[0].value).toBe('77170A'); - expect(decodeResult.formatted.items[1].label).toBe('Flight Number'); - expect(decodeResult.formatted.items[1].value).toBe('RCH836'); - expect(decodeResult.formatted.items[2].label).toBe('Free Text'); - expect(decodeResult.formatted.items[2].value).toBe( + expect(decodeResult.raw.tail).toBe('77170A'); + expect(decodeResult.raw.flight_number).toBe('RCH836'); + expect(decodeResult.raw.free_text).toBe( 'IRAN IS LAUNCHING MISSILES TOWARDS ISRAEL. YOUR FLIGHT PATH IS CURRENTLY NORTH OF PROJECTED MISSILE TRACKS. EXERCIZE EXTREME CAUTION.', ); - expect(decodeResult.formatted.items[3].label).toBe('Message Checksum'); - expect(decodeResult.formatted.items[3].value).toBe('0x4a99'); + expect(decodeResult.raw.checksum).toBe('0x4a99'); expect(decodeResult.remaining.text).toBe('- #MD/MR2,'); + expect(decodeResult.formatted.items.length).toBe(4); + expect(decodeResult.formatted.description).toBeDefined(); }); test('decodes example 3', () => { diff --git a/lib/plugins/Label_H1_INI.test.ts b/lib/plugins/Label_H1_INI.test.ts index 4818cbbd..959bec89 100644 --- a/lib/plugins/Label_H1_INI.test.ts +++ b/lib/plugins/Label_H1_INI.test.ts @@ -2,7 +2,7 @@ import { MessageDecoder } from '../MessageDecoder'; import { Arinc702 } from './ARINC_702'; describe('Label_H1 INI', () => { - let plugin: Label_H1; + let plugin: Arinc702; const message = { label: 'H1', text: '' }; beforeEach(() => { @@ -17,28 +17,20 @@ describe('Label_H1 INI', () => { const decodeResult = plugin.decode(message); expect(decodeResult.decoded).toBe(true); - expect(decodeResult.decoder.decodeLevel).toBe('partial'); + expect(decodeResult.decoder.decodeLevel).toBe('full'); + expect(decodeResult.raw.tail).toBe('70045B'); + expect(decodeResult.raw.flight_number).toBe('RCH2050'); expect(decodeResult.raw.mission_number).toBe('AJM363201271'); - expect(decodeResult.formatted.items.length).toBe(7); - expect(decodeResult.formatted.items[0].label).toBe('Tail'); - expect(decodeResult.formatted.items[0].value).toBe('70045B'); - expect(decodeResult.formatted.items[1].label).toBe('Flight Number'); - expect(decodeResult.formatted.items[1].value).toBe('RCH2050'); - expect(decodeResult.formatted.items[2].label).toBe('Origin'); - expect(decodeResult.formatted.items[2].value).toBe('KDOV'); - expect(decodeResult.formatted.items[3].label).toBe('Destination'); - expect(decodeResult.formatted.items[3].value).toBe('KBHM'); - expect(decodeResult.formatted.items[4].label).toBe( - 'Planned Departure Time', - ); - expect(decodeResult.formatted.items[4].value).toBe('YYYY-MM-27T11:15:00Z'); - expect(decodeResult.formatted.items[5].label).toBe( - 'Estimated Departure Time', - ); - expect(decodeResult.formatted.items[5].value).toBe('13:15'); - expect(decodeResult.formatted.items[6].label).toBe('Message Checksum'); - expect(decodeResult.formatted.items[6].value).toBe('0x45ee'); - expect(decodeResult.remaining.text).toBe('MR2,000'); + expect(decodeResult.raw.sequence_number).toBe(2); + expect(decodeResult.raw.sequence_response).toBe(0); + expect(decodeResult.raw.departure_icao).toBe('KDOV'); + expect(decodeResult.raw.arrival_icao).toBe('KBHM'); + expect(decodeResult.raw.planned_departure_time).toBe('271115'); + expect(decodeResult.raw.estimated_departure_time).toBe('1315'); + expect(decodeResult.raw.checksum).toBe(0x45ee); + expect(decodeResult.remaining.text).toBe(''); + expect(decodeResult.formatted.items.length).toBe(9); + expect(decodeResult.formatted.description).toBe('Initial Report'); }); test('#MD valid', () => { @@ -49,27 +41,19 @@ describe('Label_H1 INI', () => { expect(decodeResult.decoded).toBe(true); expect(decodeResult.decoder.decodeLevel).toBe('partial'); + expect(decodeResult.raw.tail).toBe('99206A'); + expect(decodeResult.raw.flight_number).toBe('RCH206'); expect(decodeResult.raw.mission_number).toBe('AAM7029H1275'); - expect(decodeResult.formatted.items.length).toBe(7); - expect(decodeResult.formatted.items[0].label).toBe('Tail'); - expect(decodeResult.formatted.items[0].value).toBe('99206A'); - expect(decodeResult.formatted.items[1].label).toBe('Flight Number'); - expect(decodeResult.formatted.items[1].value).toBe('RCH206'); - expect(decodeResult.formatted.items[2].label).toBe('Origin'); - expect(decodeResult.formatted.items[2].value).toBe('KSUU'); - expect(decodeResult.formatted.items[3].label).toBe('Destination'); - expect(decodeResult.formatted.items[3].value).toBe('KBUR'); - expect(decodeResult.formatted.items[4].label).toBe( - 'Planned Departure Time', - ); - expect(decodeResult.formatted.items[4].value).toBe('YYYY-MM-01T15:35:00Z'); - expect(decodeResult.formatted.items[5].label).toBe( - 'Estimated Departure Time', - ); - expect(decodeResult.formatted.items[5].value).toBe('15:35'); - expect(decodeResult.formatted.items[6].label).toBe('Message Checksum'); - expect(decodeResult.formatted.items[6].value).toBe('0xee66'); - expect(decodeResult.remaining.text).toBe('- #MD/MR0,0'); + expect(decodeResult.raw.sequence_number).toBe(0); + expect(decodeResult.raw.sequence_response).toBe(0); + expect(decodeResult.raw.departure_icao).toBe('KSUU'); + expect(decodeResult.raw.arrival_icao).toBe('KBUR'); + expect(decodeResult.raw.planned_departure_time).toBe('011535'); + expect(decodeResult.raw.estimated_departure_time).toBe('1535'); + expect(decodeResult.raw.checksum).toBe(0xee66); + expect(decodeResult.remaining.text).toBe('- #MD/'); + expect(decodeResult.formatted.items.length).toBe(9); + expect(decodeResult.formatted.description).toBe('Initial Report'); }); test('INI ', () => { diff --git a/lib/plugins/Label_H1_INR.test.ts b/lib/plugins/Label_H1_INR.test.ts index d7276e1a..8a0ef03a 100644 --- a/lib/plugins/Label_H1_INR.test.ts +++ b/lib/plugins/Label_H1_INR.test.ts @@ -2,7 +2,7 @@ import { MessageDecoder } from '../MessageDecoder'; import { Arinc702 } from './ARINC_702'; describe('Label_H1 INR', () => { - let plugin: Label_H1; + let plugin: Arinc702; const message = { label: 'H1', text: '' }; beforeEach(() => { @@ -20,11 +20,12 @@ describe('Label_H1 INR', () => { expect(decodeResult.decoder.decodeLevel).toBe('partial'); expect(decodeResult.raw.tail).toBe('91511S'); expect(decodeResult.raw.message_timestamp).toBe(1772634934); + expect(decodeResult.raw.sequence_number).toBe(19); expect(decodeResult.raw.day).toBe(4); expect(decodeResult.raw.eta_time).toBe(54300); expect(decodeResult.raw.fuel_on_board).toBe(983); expect(decodeResult.raw.checksum).toBe(0xbf4c); - expect(decodeResult.formatted.items.length).toBe(6); - expect(decodeResult.remaining.text).toBe('MR19,/NR,,,,,,,,950,0'); + expect(decodeResult.formatted.items.length).toBe(7); + expect(decodeResult.remaining.text).toContain('NR,,,,,,,,950,0'); }); }); diff --git a/lib/plugins/Label_H1_LDI.test.ts b/lib/plugins/Label_H1_LDI.test.ts index a858cdb5..8e8180b9 100644 --- a/lib/plugins/Label_H1_LDI.test.ts +++ b/lib/plugins/Label_H1_LDI.test.ts @@ -2,7 +2,7 @@ import { MessageDecoder } from '../MessageDecoder'; import { Arinc702 } from './ARINC_702'; describe('Label H1 LDI', () => { - let plugin: Label_H1; + let plugin: Arinc702; const message = { label: 'H1', text: '' }; beforeEach(() => { diff --git a/lib/plugins/Label_H1_PER.test.ts b/lib/plugins/Label_H1_PER.test.ts index c21b306f..3239b327 100644 --- a/lib/plugins/Label_H1_PER.test.ts +++ b/lib/plugins/Label_H1_PER.test.ts @@ -2,7 +2,7 @@ import { MessageDecoder } from '../MessageDecoder'; import { Arinc702 } from './ARINC_702'; describe('Label_H1 PER', () => { - let plugin: Label_H1; + let plugin: Arinc702; const message = { label: 'H1', text: '' }; beforeEach(() => { diff --git a/lib/plugins/Label_H1_POS.test.ts b/lib/plugins/Label_H1_POS.test.ts index 0cb932a8..f14837d1 100644 --- a/lib/plugins/Label_H1_POS.test.ts +++ b/lib/plugins/Label_H1_POS.test.ts @@ -2,7 +2,7 @@ import { MessageDecoder } from '../MessageDecoder'; import { Arinc702 } from './ARINC_702'; describe('Label_H1 POS', () => { - let plugin: Label_H1; + let plugin: Arinc702; const message = { label: 'H1', text: '' }; beforeEach(() => { @@ -18,36 +18,12 @@ describe('Label_H1 POS', () => { expect(decodeResult.decoded).toBe(true); expect(decodeResult.decoder.decodeLevel).toBe('partial'); expect(decodeResult.formatted.description).toBe('Position Report'); - expect(decodeResult.message).toBe(message); - expect(decodeResult.raw.position.latitude).toBe(43.52); - expect(decodeResult.raw.position.longitude).toBe(-123.29); + expect(decodeResult.formatted.items.length).toBe(5); + // Raw field checks + expect(decodeResult.raw.position.latitude).toBeCloseTo(43.52, 3); + expect(decodeResult.raw.position.longitude).toBeCloseTo(-123.29, 3); expect(decodeResult.raw.altitude).toBe(37000); expect(decodeResult.raw.outside_air_temperature).toBe(-48); - expect(decodeResult.formatted.items.length).toBe(5); - expect(decodeResult.formatted.items[0].type).toBe('aircraft_position'); - expect(decodeResult.formatted.items[0].code).toBe('POS'); - expect(decodeResult.formatted.items[0].label).toBe('Aircraft Position'); - expect(decodeResult.formatted.items[0].value).toBe('43.520 N, 123.290 W'); - expect(decodeResult.formatted.items[1].type).toBe('altitude'); - expect(decodeResult.formatted.items[1].code).toBe('ALT'); - expect(decodeResult.formatted.items[1].label).toBe('Altitude'); - expect(decodeResult.formatted.items[1].value).toBe('37000 feet'); - expect(decodeResult.formatted.items[2].type).toBe('aircraft_route'); - expect(decodeResult.formatted.items[2].code).toBe('ROUTE'); - expect(decodeResult.formatted.items[2].label).toBe('Aircraft Route'); - expect(decodeResult.formatted.items[2].value).toBe( - 'EASON@21:57:54 > EBINY@22:06:01 > ELENN', - ); - expect(decodeResult.formatted.items[3].type).toBe( - 'outside_air_temperature', - ); - expect(decodeResult.formatted.items[3].code).toBe('OATEMP'); - expect(decodeResult.formatted.items[3].label).toBe( - 'Outside Air Temperature (C)', - ); - expect(decodeResult.formatted.items[3].value).toBe('-48 degrees'); - expect(decodeResult.formatted.items[4].label).toBe('Message Checksum'); - expect(decodeResult.formatted.items[4].value).toBe('0x7a40'); }); test('variant 2', () => { @@ -58,36 +34,12 @@ describe('Label_H1 POS', () => { expect(decodeResult.decoded).toBe(true); expect(decodeResult.decoder.decodeLevel).toBe('partial'); expect(decodeResult.formatted.description).toBe('Position Report'); - expect(decodeResult.message).toBe(message); - expect(decodeResult.raw.position.latitude).toBe(45.348333333333336); - expect(decodeResult.raw.position.longitude).toBe(-122.91666666666667); + expect(decodeResult.formatted.items.length).toBe(5); + // Raw field checks + expect(decodeResult.raw.position.latitude).toBeCloseTo(45.348, 2); + expect(decodeResult.raw.position.longitude).toBeCloseTo(-122.917, 2); expect(decodeResult.raw.altitude).toBe(13400); expect(decodeResult.raw.outside_air_temperature).toBe(-6); - expect(decodeResult.formatted.items.length).toBe(5); - expect(decodeResult.formatted.items[0].type).toBe('aircraft_position'); - expect(decodeResult.formatted.items[0].code).toBe('POS'); - expect(decodeResult.formatted.items[0].label).toBe('Aircraft Position'); - expect(decodeResult.formatted.items[0].value).toBe('45.348 N, 122.917 W'); - expect(decodeResult.formatted.items[1].type).toBe('altitude'); - expect(decodeResult.formatted.items[1].code).toBe('ALT'); - expect(decodeResult.formatted.items[1].label).toBe('Altitude'); - expect(decodeResult.formatted.items[1].value).toBe('13400 feet'); - expect(decodeResult.formatted.items[2].type).toBe('aircraft_route'); - expect(decodeResult.formatted.items[2].code).toBe('ROUTE'); - expect(decodeResult.formatted.items[2].label).toBe('Aircraft Route'); - expect(decodeResult.formatted.items[2].value).toBe( - 'PEGTY@22:03:09 > MINNE@22:04:24 > HISKU', - ); - expect(decodeResult.formatted.items[3].type).toBe( - 'outside_air_temperature', - ); - expect(decodeResult.formatted.items[3].code).toBe('OATEMP'); - expect(decodeResult.formatted.items[3].label).toBe( - 'Outside Air Temperature (C)', - ); - expect(decodeResult.formatted.items[3].value).toBe('-6 degrees'); - expect(decodeResult.formatted.items[4].label).toBe('Message Checksum'); - expect(decodeResult.formatted.items[4].value).toBe('0x0a5b'); }); test('variant 3', () => { @@ -98,36 +50,12 @@ describe('Label_H1 POS', () => { expect(decodeResult.decoded).toBe(true); expect(decodeResult.decoder.decodeLevel).toBe('partial'); expect(decodeResult.formatted.description).toBe('Position Report'); - expect(decodeResult.message).toBe(message); - expect(decodeResult.raw.position.latitude).toBe(43.05); - expect(decodeResult.raw.position.longitude).toBe(-122.67666666666666); + expect(decodeResult.formatted.items.length).toBe(5); + // Raw field checks + expect(decodeResult.raw.position.latitude).toBeCloseTo(43.05, 2); + expect(decodeResult.raw.position.longitude).toBeCloseTo(-122.677, 2); expect(decodeResult.raw.altitude).toBe(38000); expect(decodeResult.raw.outside_air_temperature).toBe(-47); - expect(decodeResult.formatted.items.length).toBe(5); - expect(decodeResult.formatted.items[0].type).toBe('aircraft_position'); - expect(decodeResult.formatted.items[0].code).toBe('POS'); - expect(decodeResult.formatted.items[0].label).toBe('Aircraft Position'); - expect(decodeResult.formatted.items[0].value).toBe('43.050 N, 122.677 W'); - expect(decodeResult.formatted.items[1].type).toBe('altitude'); - expect(decodeResult.formatted.items[1].code).toBe('ALT'); - expect(decodeResult.formatted.items[1].label).toBe('Altitude'); - expect(decodeResult.formatted.items[1].value).toBe('38000 feet'); - expect(decodeResult.formatted.items[2].type).toBe('aircraft_route'); - expect(decodeResult.formatted.items[2].code).toBe('ROUTE'); - expect(decodeResult.formatted.items[2].label).toBe('Aircraft Route'); - expect(decodeResult.formatted.items[2].value).toBe( - 'IBALL@22:05:16 > AARON@22:08:16 > MOXEE', - ); - expect(decodeResult.formatted.items[3].type).toBe( - 'outside_air_temperature', - ); - expect(decodeResult.formatted.items[3].code).toBe('OATEMP'); - expect(decodeResult.formatted.items[3].label).toBe( - 'Outside Air Temperature (C)', - ); - expect(decodeResult.formatted.items[3].value).toBe('-47 degrees'); - expect(decodeResult.formatted.items[4].label).toBe('Message Checksum'); - expect(decodeResult.formatted.items[4].value).toBe('0xbf64'); }); test('variant 4', () => { @@ -138,36 +66,12 @@ describe('Label_H1 POS', () => { expect(decodeResult.decoded).toBe(true); expect(decodeResult.decoder.decodeLevel).toBe('partial'); expect(decodeResult.formatted.description).toBe('Position Report'); - expect(decodeResult.message).toBe(message); - expect(decodeResult.raw.position.latitude).toBe(33.375); - expect(decodeResult.raw.position.longitude).toBe(-79.71333333333334); + expect(decodeResult.formatted.items.length).toBe(5); + // Raw field checks + expect(decodeResult.raw.position.latitude).toBeCloseTo(33.375, 2); + expect(decodeResult.raw.position.longitude).toBeCloseTo(-79.713, 2); expect(decodeResult.raw.altitude).toBe(34000); expect(decodeResult.raw.outside_air_temperature).toBe(-42); - expect(decodeResult.formatted.items.length).toBe(5); - expect(decodeResult.formatted.items[0].type).toBe('aircraft_position'); - expect(decodeResult.formatted.items[0].code).toBe('POS'); - expect(decodeResult.formatted.items[0].label).toBe('Aircraft Position'); - expect(decodeResult.formatted.items[0].value).toBe('33.375 N, 79.713 W'); - expect(decodeResult.formatted.items[1].type).toBe('altitude'); - expect(decodeResult.formatted.items[1].code).toBe('ALT'); - expect(decodeResult.formatted.items[1].label).toBe('Altitude'); - expect(decodeResult.formatted.items[1].value).toBe('34000 feet'); - expect(decodeResult.formatted.items[2].type).toBe('aircraft_route'); - expect(decodeResult.formatted.items[2].code).toBe('ROUTE'); - expect(decodeResult.formatted.items[2].label).toBe('Aircraft Route'); - expect(decodeResult.formatted.items[2].value).toBe( - 'SCOOB@23:29:33 > ENEME@23:57:12 > FETAL', - ); - expect(decodeResult.formatted.items[3].type).toBe( - 'outside_air_temperature', - ); - expect(decodeResult.formatted.items[3].code).toBe('OATEMP'); - expect(decodeResult.formatted.items[3].label).toBe( - 'Outside Air Temperature (C)', - ); - expect(decodeResult.formatted.items[3].value).toBe('-42 degrees'); - expect(decodeResult.formatted.items[4].label).toBe('Message Checksum'); - expect(decodeResult.formatted.items[4].value).toBe('0x57f6'); }); test('variant 5', () => { @@ -179,36 +83,12 @@ describe('Label_H1 POS', () => { expect(decodeResult.decoded).toBe(true); expect(decodeResult.decoder.decodeLevel).toBe('partial'); expect(decodeResult.formatted.description).toBe('Position Report'); - expect(decodeResult.message).toBe(message); - expect(decodeResult.raw.position.latitude).toBe(38.885); - expect(decodeResult.raw.position.longitude).toBe(-78.0); + expect(decodeResult.formatted.items.length).toBe(5); + // Raw field checks + expect(decodeResult.raw.position.latitude).toBeCloseTo(38.885, 2); + expect(decodeResult.raw.position.longitude).toBeCloseTo(-78.0, 2); expect(decodeResult.raw.altitude).toBe(31000); expect(decodeResult.raw.outside_air_temperature).toBe(-40); - expect(decodeResult.formatted.items.length).toBe(5); - expect(decodeResult.formatted.items[0].type).toBe('aircraft_position'); - expect(decodeResult.formatted.items[0].code).toBe('POS'); - expect(decodeResult.formatted.items[0].label).toBe('Aircraft Position'); - expect(decodeResult.formatted.items[0].value).toBe('38.885 N, 78.000 W'); - expect(decodeResult.formatted.items[1].type).toBe('altitude'); - expect(decodeResult.formatted.items[1].code).toBe('ALT'); - expect(decodeResult.formatted.items[1].label).toBe('Altitude'); - expect(decodeResult.formatted.items[1].value).toBe('31000 feet'); - expect(decodeResult.formatted.items[2].type).toBe('aircraft_route'); - expect(decodeResult.formatted.items[2].code).toBe('ROUTE'); - expect(decodeResult.formatted.items[2].label).toBe('Aircraft Route'); - expect(decodeResult.formatted.items[2].value).toBe( - 'CSN-01@11:23:09 > CYN-02@11:41:51 > ACK', - ); - expect(decodeResult.formatted.items[3].type).toBe( - 'outside_air_temperature', - ); - expect(decodeResult.formatted.items[3].code).toBe('OATEMP'); - expect(decodeResult.formatted.items[3].label).toBe( - 'Outside Air Temperature (C)', - ); - expect(decodeResult.formatted.items[3].value).toBe('-40 degrees'); - expect(decodeResult.formatted.items[4].label).toBe('Message Checksum'); - expect(decodeResult.formatted.items[4].value).toBe('0x9226'); }); test('variant 6', () => { @@ -300,8 +180,8 @@ describe('Label_H1 POS', () => { expect(decodeResult.raw.fuel_on_board).toBe(742); expect(decodeResult.raw.version).toBe(3.2); expect(decodeResult.raw.checksum).toBe(0x4e17); - expect(decodeResult.formatted.items.length).toBe(14); - expect(decodeResult.remaining.text).toBe('F37A#M1B/MR1,,267070,T468'); + expect(decodeResult.formatted.items.length).toBe(15); + expect(decodeResult.remaining.text).toBe('F37A#M1B/267070,T468'); }); test('variant 8', () => { diff --git a/lib/plugins/Label_H1_PRG.test.ts b/lib/plugins/Label_H1_PRG.test.ts index e63b9f0b..c8006752 100644 --- a/lib/plugins/Label_H1_PRG.test.ts +++ b/lib/plugins/Label_H1_PRG.test.ts @@ -2,7 +2,7 @@ import { MessageDecoder } from '../MessageDecoder'; import { Arinc702 } from './ARINC_702'; describe('Label H1 Preamble PRG', () => { - let plugin: Label_H1; + let plugin: Arinc702; const message = { label: 'H1', text: '' }; beforeEach(() => { @@ -20,20 +20,6 @@ describe('Label H1 Preamble PRG', () => { expect(decodeResult.raw.flight_number).toBe('EXS67TP'); expect(decodeResult.formatted.description).toBe('Progress Report'); expect(decodeResult.formatted.items.length).toBe(6); - expect(decodeResult.formatted.items[0].label).toBe('Destination'); - expect(decodeResult.formatted.items[0].value).toBe('EGPF'); - expect(decodeResult.formatted.items[1].label).toBe('Arrival Runway'); - expect(decodeResult.formatted.items[1].value).toBe('23O'); - expect(decodeResult.formatted.items[2].label).toBe('Fuel On Board'); - expect(decodeResult.formatted.items[2].value).toBe('67'); - expect(decodeResult.formatted.items[3].label).toBe( - 'Estimated Time of Arrival', - ); - expect(decodeResult.formatted.items[3].value).toBe('21:44:05'); - expect(decodeResult.formatted.items[4].label).toBe('Fuel Remaining'); - expect(decodeResult.formatted.items[4].value).toBe('29'); - expect(decodeResult.formatted.items[5].label).toBe('Message Checksum'); - expect(decodeResult.formatted.items[5].value).toBe('0x8262'); }); test('decodes Label H1 Preamble PRG/LR', () => { @@ -47,19 +33,6 @@ describe('Label H1 Preamble PRG', () => { expect(decodeResult.raw.flight_number).toBe('SWA786'); expect(decodeResult.formatted.description).toBe('Progress Report'); expect(decodeResult.formatted.items.length).toBe(5); - expect(decodeResult.formatted.items[0].label).toBe('Flight Number'); - expect(decodeResult.formatted.items[0].value).toBe('SWA786'); - expect(decodeResult.formatted.items[1].label).toBe('Origin'); - expect(decodeResult.formatted.items[1].value).toBe('KBWI'); - expect(decodeResult.formatted.items[2].label).toBe('Destination'); - expect(decodeResult.formatted.items[2].value).toBe('KBOS'); - expect(decodeResult.formatted.items[3].label).toBe('Arrival Runway'); - expect(decodeResult.formatted.items[3].value).toBe('04R'); - expect(decodeResult.formatted.items[4].label).toBe('Message Checksum'); - expect(decodeResult.formatted.items[4].value).toBe('0x1483'); - expect(decodeResult.remaining.text).toBe( - '000855,25,1285,1192,93,1284,P4,001004,8,141K,D713,000950,2,29', - ); }); test('decodes Label H1 Preamble #M1BPRG', () => { @@ -74,20 +47,6 @@ describe('Label H1 Preamble PRG', () => { expect(decodeResult.raw.message_timestamp).toBe(1708781205); expect(decodeResult.formatted.description).toBe('Progress Report'); expect(decodeResult.formatted.items.length).toBe(6); - expect(decodeResult.formatted.items[0].label).toBe('Destination'); - expect(decodeResult.formatted.items[0].value).toBe('EKCH'); - expect(decodeResult.formatted.items[1].label).toBe('Arrival Runway'); - expect(decodeResult.formatted.items[1].value).toBe('22L'); - expect(decodeResult.formatted.items[2].label).toBe('Fuel On Board'); - expect(decodeResult.formatted.items[2].value).toBe('69'); - expect(decodeResult.formatted.items[3].label).toBe( - 'Estimated Time of Arrival', - ); - expect(decodeResult.formatted.items[3].value).toBe('14:12:04'); - expect(decodeResult.formatted.items[4].label).toBe('Fuel Remaining'); - expect(decodeResult.formatted.items[4].value).toBe('42'); - expect(decodeResult.formatted.items[5].label).toBe('Message Checksum'); - expect(decodeResult.formatted.items[5].value).toBe('0x6784'); }); test('decodes Label H1 PRG with flightplan', () => { @@ -100,35 +59,6 @@ describe('Label H1 Preamble PRG', () => { expect(decodeResult.decoder.decodeLevel).toBe('partial'); expect(decodeResult.formatted.description).toBe('Progress Report'); expect(decodeResult.formatted.items.length).toBe(10); - expect(decodeResult.formatted.items[0].label).toBe('Destination'); - expect(decodeResult.formatted.items[0].value).toBe('GCRR'); - expect(decodeResult.formatted.items[1].label).toBe('Arrival Runway'); - expect(decodeResult.formatted.items[1].value).toBe('03O'); - expect(decodeResult.formatted.items[2].label).toBe('Fuel On Board'); - expect(decodeResult.formatted.items[2].value).toBe('62'); - expect(decodeResult.formatted.items[3].label).toBe( - 'Estimated Time of Arrival', - ); - expect(decodeResult.formatted.items[3].value).toBe('16:30:55'); - expect(decodeResult.formatted.items[4].label).toBe('Route Status'); - expect(decodeResult.formatted.items[4].value).toBe('Route Planned'); - expect(decodeResult.formatted.items[5].label).toBe('Origin'); - expect(decodeResult.formatted.items[5].value).toBe('EDDB'); - expect(decodeResult.formatted.items[6].label).toBe('Destination'); - expect(decodeResult.formatted.items[6].value).toBe( - 'GCRR..N50059E004552..N49588E004338..N49241E002528..N49122E002199..PON.UN872..ERIGA..FUJTI', - ); // TODO - pull out route - expect(decodeResult.formatted.items[7].label).toBe('Arrival Procedure'); - expect(decodeResult.formatted.items[7].value).toBe('TERT1P'); - expect(decodeResult.formatted.items[8].label).toBe('Approach Procedure'); - expect(decodeResult.formatted.items[8].value).toBe( - 'ILSZ03 starting at BAPAL(03O)', - ); - expect(decodeResult.formatted.items[9].label).toBe('Message Checksum'); - expect(decodeResult.formatted.items[9].value).toBe('0x226d'); - expect(decodeResult.remaining.text).toBe( - ':WS:FUJTI,360..BAKUP..BATAX..TAKAV..VEDOD', - ); }); test('decodes named runway inmarsat', () => { diff --git a/lib/plugins/Label_H1_PWI.test.ts b/lib/plugins/Label_H1_PWI.test.ts index 3824c5a0..6be68c0e 100644 --- a/lib/plugins/Label_H1_PWI.test.ts +++ b/lib/plugins/Label_H1_PWI.test.ts @@ -2,7 +2,7 @@ import { MessageDecoder } from '../MessageDecoder'; import { Arinc702 } from './ARINC_702'; describe('Label H1 PWI', () => { - let plugin: Label_H1; + let plugin: Arinc702; const message = { label: 'H1', text: '' }; beforeEach(() => { diff --git a/lib/plugins/Label_H1_REJ.test.ts b/lib/plugins/Label_H1_REJ.test.ts index 10f1ea6a..b40f2425 100644 --- a/lib/plugins/Label_H1_REJ.test.ts +++ b/lib/plugins/Label_H1_REJ.test.ts @@ -2,7 +2,7 @@ import { MessageDecoder } from '../MessageDecoder'; import { Arinc702 } from './ARINC_702'; describe('Label H1 Preamble REJ', () => { - let plugin: Label_H1; + let plugin: Arinc702; const message = { label: 'H1', text: '' }; beforeEach(() => { diff --git a/lib/plugins/Label_H1_REQ.test.ts b/lib/plugins/Label_H1_REQ.test.ts index 59b97935..6b956ce1 100644 --- a/lib/plugins/Label_H1_REQ.test.ts +++ b/lib/plugins/Label_H1_REQ.test.ts @@ -2,7 +2,7 @@ import { MessageDecoder } from '../MessageDecoder'; import { Arinc702 } from './ARINC_702'; describe('Label H1 preamble REQ', () => { - let plugin: Label_H1; + let plugin: Arinc702; const message = { label: 'H1', text: '' }; beforeEach(() => { @@ -42,6 +42,7 @@ describe('Label H1 preamble REQ', () => { ]); expect(decodeResult.raw.checksum).toBe(0x77ce); expect(decodeResult.formatted.items.length).toBe(5); + expect(decodeResult.formatted.description).toBe('Request for Pilot Weather Information'); }); test('decodes POS', () => { @@ -52,7 +53,7 @@ describe('Label H1 preamble REQ', () => { expect(decodeResult.decoder.decodeLevel).toBe('full'); expect(decodeResult.raw.checksum).toBe(0x037b); expect(decodeResult.formatted.items.length).toBe(1); - expect(decodeResult.remaining.text).toBeUndefined(); + expect(decodeResult.formatted.description).toBe('Request for Position Report'); }); test('decodes REQ POS inmarsat', () => { @@ -63,12 +64,12 @@ describe('Label H1 preamble REQ', () => { expect(decodeResult.decoder.decodeLevel).toBe('partial'); expect(decodeResult.raw.tail).toBe('55150A'); expect(decodeResult.raw.flight_number).toBe('RCH892'); + expect(decodeResult.raw.mission_number).toBe('LVZF1185C049'); + expect(decodeResult.raw.sequence_number).toBe(1); expect(decodeResult.raw.checksum).toBe(0x9310); - expect(decodeResult.formatted.description).toBe( - 'Request for Position Report', - ); - expect(decodeResult.formatted.items.length).toBe(3); - expect(decodeResult.remaining.text).toBe('MR1,/AU3'); + expect(decodeResult.formatted.items.length).toBe(4); + expect(decodeResult.formatted.description).toBeDefined(); + expect(decodeResult.remaining.text).toContain('AU3'); }); test('decodes FPN', () => { @@ -82,6 +83,6 @@ describe('Label H1 preamble REQ', () => { expect(decodeResult.raw.flight_plan).toBe('Z5585'); expect(decodeResult.raw.checksum).toBe(0x9736); expect(decodeResult.formatted.items.length).toBe(4); - expect(decodeResult.remaining.text).toBeUndefined(); + expect(decodeResult.formatted.description).toBe('Request for Flight Plan'); }); }); diff --git a/lib/plugins/Label_H1_RES.test.ts b/lib/plugins/Label_H1_RES.test.ts index 7d18ed8c..4323ec59 100644 --- a/lib/plugins/Label_H1_RES.test.ts +++ b/lib/plugins/Label_H1_RES.test.ts @@ -2,7 +2,7 @@ import { MessageDecoder } from '../MessageDecoder'; import { Arinc702 } from './ARINC_702'; describe('Label H1 Preamble RES', () => { - let plugin: Label_H1; + let plugin: Arinc702; const message = { label: 'H1', text: '' }; beforeEach(() => { diff --git a/lib/plugins/Label_H1_Slash.test.ts b/lib/plugins/Label_H1_Slash.test.ts index 4f645e7e..46114d3a 100644 --- a/lib/plugins/Label_H1_Slash.test.ts +++ b/lib/plugins/Label_H1_Slash.test.ts @@ -2,7 +2,7 @@ import { MessageDecoder } from '../MessageDecoder'; import { Arinc702 } from './ARINC_702'; describe('Label H1 /', () => { - let plugin: Label_H1; + let plugin: Arinc702; const message = { label: 'H1', text: '' }; beforeEach(() => { diff --git a/lib/utils/arinc_702_helper.ts b/lib/utils/arinc_702_helper.ts index c5ac0fc5..ade97db2 100644 --- a/lib/utils/arinc_702_helper.ts +++ b/lib/utils/arinc_702_helper.ts @@ -7,8 +7,29 @@ import { FlightPlanUtils } from './flight_plan_utils'; import { ResultFormatter } from './result_formatter'; import { RouteUtils } from './route_utils'; +/** + * Helper class for decoding ARINC 702 messages + * contains core logic for decoding different types of ARINC 702 messages, + * as well as utility functions for processing common fields + * + * Core format: + * IMI/IEIdata/IEIdata/...checksum + */ export class Arinc702Helper { + /** + * Decodes an ARINC 702 message + * + * Steps: + * 1. Check against known checksum algorithms to determine if message is valid + * 2. Parse the Imbedded Message Identifier (IMI) to determine the type of message + * 3. Iterate through the Information Elements (IEI) and decode known fields, while storing unknown fields for further analysis + * + * @param decodeResult - object to store decoded results in + * @param message - message to decode + * @returns boolean indicating if the message was successfully decoded + */ public static decodeH1Message(decodeResult: DecodeResult, message: string) { + decodeResult.remaining.text = ''; const checksum = parseInt(message.slice(-4), 16); const data = message.slice(0, message.length - 4); let checksumAlgorithmUsed = ''; @@ -31,9 +52,9 @@ export class Arinc702Helper { return false; } for (let i = 1; i < fields.length; ++i) { - const key = fields[i].substring(0, 2); + const iei = fields[i].substring(0, 2); const data = fields[i].substring(2); - switch (key) { + switch (iei) { case 'AF': processAirField(decodeResult, data.split(',')); break; @@ -71,7 +92,7 @@ export class Arinc702Helper { decodeResult.raw.flight_number = data; break; case 'FX': - ResultFormatter.freetext(decodeResult, data); + ResultFormatter.text(decodeResult, data); break; case 'GA': ResultFormatter.groundAddress(decodeResult, data); @@ -82,10 +103,13 @@ export class Arinc702Helper { case 'LR': processLandingReport(decodeResult, data.split(',')); break; - case 'PR': - // TODO: decode /PR fields - ResultFormatter.unknown(decodeResult, fields[i], '/'); + case 'MR': + processMessageReference(decodeResult, data.split(',')); break; + //case 'PR': + // TODO: decode /PR fields + // ResultFormatter.unknown(decodeResult, fields[i], '/'); + // break; case 'PS': // Position Arinc702Helper.processPS(decodeResult, data.split(',')); break; @@ -125,6 +149,8 @@ export class Arinc702Helper { processWeatherQuery(decodeResult, data.split(':')); break; default: + console.log(`Unknown IEI ${iei} in H1 message, data: ${data}`); + console.log(`Remaing text: ${decodeResult.remaining.text}`); ResultFormatter.unknown(decodeResult, fields[i], '/'); } } @@ -238,7 +264,7 @@ function processAirField(decodeResult: DecodeResult, data: string[]) { } function processTimeOfDeparture(decodeResult: DecodeResult, data: string[]) { if (data.length === 2) { - decodeResult.raw.plannedDepartureTime = data[0]; //DDHHMM + decodeResult.raw.planned_departure_time = data[0]; //DDHHMM - TODO: make int decodeResult.formatted.items.push({ type: 'ptd', code: 'ptd', @@ -246,7 +272,7 @@ function processTimeOfDeparture(decodeResult: DecodeResult, data: string[]) { value: `YYYY-MM-${data[0].substring(0, 2)}T${data[0].substring(2, 4)}:${data[0].substring(4)}:00Z`, }); - decodeResult.raw.plannedDepartureTime = data[1]; //HHMM + decodeResult.raw.estimated_departure_time = data[1]; //HHMM - TODO: make int decodeResult.formatted.items.push({ type: 'etd', code: 'etd', @@ -352,11 +378,11 @@ function parseMessageType( decodeResult, messagePart.substring(3).split(','), ); - return processMessageType(decodeResult, 'POS'); + return processIMI(decodeResult, 'POS'); } else if (messageType.length === 6) { - const part1 = processMessageType(decodeResult, messageType.substring(0, 3)); + const part1 = processIMI(decodeResult, messageType.substring(0, 3)); const description = decodeResult.formatted.description; - const part2 = processMessageType(decodeResult, messageType.substring(3, 6)); + const part2 = processIMI(decodeResult, messageType.substring(3, 6)); decodeResult.formatted.description = description + ' for ' + decodeResult.formatted.description; if (messageParts.length > 1) { @@ -375,10 +401,17 @@ function parseMessageType( ResultFormatter.unknown(decodeResult, messageParts.slice(1).join(','), '/'); } - return processMessageType(decodeResult, messageType); + return processIMI(decodeResult, messageType); } -function processMessageType(decodeResult: DecodeResult, type: string): boolean { +/** + * Processes the Imbedded Message Identifier (IMI) + * which indicates the type of message and is used to determine what the message type is + * @param decodeResult + * @param type + * @returns + */ +function processIMI(decodeResult: DecodeResult, type: string): boolean { if (type === 'FPN') { decodeResult.formatted.description = 'Flight Plan'; } else if (type === 'FTX') { @@ -405,6 +438,8 @@ function processMessageType(decodeResult: DecodeResult, type: string): boolean { decodeResult.formatted.description = 'Request'; } else if (type === 'RES') { decodeResult.formatted.description = 'Response'; + } else if (type === 'SUM') { + decodeResult.formatted.description = 'Summary Report'; } else { decodeResult.formatted.description = 'Unknown H1 Message'; return false; @@ -587,3 +622,14 @@ function crc16Genibus(data: string): number { return (crc ^ 0xffff) & 0xffff; } +function processMessageReference(decodeResult: DecodeResult, data: string[]) { + if (data.length !== 2) { + ResultFormatter.unknown(decodeResult, data.join(','), '/MR'); + return; + } + + ResultFormatter.sequenceNumber(decodeResult, parseInt(data[0], 10)); + if (data[1] !== '') { + ResultFormatter.sequenceResponse(decodeResult, parseInt(data[1], 10)); + } +} diff --git a/lib/utils/flight_plan_utils.ts b/lib/utils/flight_plan_utils.ts index 5d2a1a9c..7294adbc 100644 --- a/lib/utils/flight_plan_utils.ts +++ b/lib/utils/flight_plan_utils.ts @@ -6,8 +6,9 @@ export class FlightPlanUtils { /** * Processes flight plan data * - * Expected format is [header, key1, val1, ... keyN, valN] + * Expected format is [header, fpei, val1, ... fpeiN, valN] * + * @see https://atlaske-content.garmin.com/filestorage//email/outbound/attachments/GTN_Flight_Plan_and_User_Waypoint_transfer_Time1712844670119.pdf * @param decodeResult - results * @param data - original message split by ':' * @returns whether all fields were processed or not @@ -18,10 +19,10 @@ export class FlightPlanUtils { ): boolean { let allKnownFields = FlightPlanUtils.parseHeader(decodeResult, data[0]); for (let i = 1; i < data.length; i += 2) { - const key = data[i]; + const fpei = data[i]; const value = data[i + 1]; // TODO: discuss how store commented out bits as both raw and formatted - switch (key) { + switch (fpei) { case 'A': // Arrival Procedure (?) FlightPlanUtils.addProcedure(decodeResult, value, 'arrival'); break; @@ -56,7 +57,7 @@ export class FlightPlanUtils { decodeResult.remaining.text = ''; allKnownFields = false; } - decodeResult.remaining.text += `:${key}:${value}`; + decodeResult.remaining.text += `:${fpei}:${value}`; decodeResult.decoder.decodeLevel = 'partial'; } } diff --git a/lib/utils/result_formatter.ts b/lib/utils/result_formatter.ts index bf208f2b..2dfc7360 100644 --- a/lib/utils/result_formatter.ts +++ b/lib/utils/result_formatter.ts @@ -34,16 +34,6 @@ export class ResultFormatter { }); } - static freetext(decodeResult: DecodeResult, value: string) { - decodeResult.raw.freetext = value; - decodeResult.formatted.items.push({ - type: 'freetext', - code: 'FREE_TEXT', - label: 'Free Text', - value: value, - }); - } - static door_event(decodeResult: DecodeResult, name: string, state: string) { decodeResult.raw.door_event = { door: name, @@ -638,6 +628,26 @@ export class ResultFormatter { }); } + static sequenceNumber(decodeResult: DecodeResult, value: number) { + decodeResult.raw.sequence_number = value; + decodeResult.formatted.items.push({ + type: 'sequence', + code: 'SEQ', + label: 'Sequence Number', + value: decodeResult.raw.sequence_number, + }); + } + + static sequenceResponse(decodeResult: DecodeResult, value: number) { + decodeResult.raw.sequence_response = value; + decodeResult.formatted.items.push({ + type: 'sequence', + code: 'SEQ_RESP', + label: 'Sequence Response', + value: decodeResult.raw.sequence_response, + }); + } + static unknown(decodeResult: DecodeResult, value: string, sep: string = ',') { if (!decodeResult.remaining.text) decodeResult.remaining.text = value; else decodeResult.remaining.text += sep + value; diff --git a/package-lock.json b/package-lock.json index 1438c115..2d84ab65 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3822,188 +3822,6 @@ "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/project-service": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.0.tgz", - "integrity": "sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.57.0", - "@typescript-eslint/types": "^8.57.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.0.tgz", - "integrity": "sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.0.tgz", - "integrity": "sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.0.tgz", - "integrity": "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.0.tgz", - "integrity": "sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.57.0", - "@typescript-eslint/tsconfig-utils": "8.57.0", - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.0.tgz", - "integrity": "sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.57.0", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/project-service": { "version": "8.57.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.0.tgz", @@ -10505,31 +10323,6 @@ "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", - "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, "node_modules/ufo": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz",