@airframes/acars-decoder 1.6.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,2832 @@
1
+ // lib/IcaoDecoder.ts
2
+ var IcaoDecoder = class {
3
+ name;
4
+ icao;
5
+ constructor(icao) {
6
+ this.name = "icao-decoder-typescript";
7
+ this.icao = icao;
8
+ }
9
+ isMilitary() {
10
+ let i = this.icao;
11
+ return i.match(/^adf[7-9]/) || i.match(/^adf[a-f]/) || i.match(/^a(e|f)/) || i.match(/^0100(7|8)/) || i.match(/^0a4/) || i.match(/^33ff/) || i >= "350000" && i <= "37ffff" || i.match(/^3a(8|9|[a-f])/) || i.match(/^3b/) || i.match(/^3e(a|b)/) || i.match(/^3f([4-9]|[a-b])/) || i.match(/^4000[0-3]/) || i.match(/^43c/) || i.match(/^44[4-7]/) && i != "447ac7" || i.match(/^44f/) || i.match(/^457/) || i.match(/^45f4/) || i.match(/^468[0-3]/) || i.match(/^473c0/) || i.match(/^4781/) || i.match(/^480/) || i.match(/^48d8[0-7]/) || i.match(/^497c/) || i.match(/^49842/) || i.match(/^4b7/) || i.match(/^4b82/) || i.match(/^506f/) || i.match(/^70c07/) || i.match(/^7102[5-8]/) || i.match(/^7103[8-9]/) || i.match(/^738a/) || i.match(/^7c8([2-4]|8)/) || i >= "7c9000" && i <= "7cbfff" || i.match(/^7[d-f]/) || i.match(/^8002/) || i.match(/^c[2-3]/) || i.match(/^e4[0-1]/) || i.match(/^e806/);
12
+ }
13
+ };
14
+
15
+ // lib/DecoderPlugin.ts
16
+ var DecoderPlugin = class {
17
+ decoder;
18
+ name = "unknown";
19
+ defaultResult = {
20
+ decoded: false,
21
+ decoder: {
22
+ name: "unknown",
23
+ type: "pattern-match",
24
+ decodeLevel: "none"
25
+ },
26
+ formatted: {
27
+ description: "Unknown",
28
+ items: []
29
+ },
30
+ raw: {},
31
+ remaining: {}
32
+ };
33
+ options;
34
+ constructor(decoder, options = {}) {
35
+ this.decoder = decoder;
36
+ this.options = options;
37
+ }
38
+ id() {
39
+ console.log("DecoderPlugin subclass has not overriden id() to provide a unique ID for this plugin!");
40
+ return "abstract_decoder_plugin";
41
+ }
42
+ meetsStateRequirements() {
43
+ return true;
44
+ }
45
+ // onRegister(store: Store<any>) {
46
+ // this.store = store;
47
+ // }
48
+ qualifiers() {
49
+ const labels = [];
50
+ return {
51
+ labels
52
+ };
53
+ }
54
+ decode(message) {
55
+ const decodeResult = this.defaultResult;
56
+ decodeResult.remaining.text = message.text;
57
+ return decodeResult;
58
+ }
59
+ };
60
+
61
+ // lib/plugins/Label_5Z.ts
62
+ var Label_5Z = class extends DecoderPlugin {
63
+ name = "label-5z";
64
+ descriptions = {
65
+ B1: "Request Weight and Balance",
66
+ B3: "Request Departure Clearance",
67
+ CD: "Weight and Balance",
68
+ CG: "Request Pre-departure clearance, PDC",
69
+ CM: "Crew Scheduling",
70
+ C3: "Off Message",
71
+ C4: "Flight Dispatch",
72
+ C5: "Maintenance Message",
73
+ C6: "Customer Service",
74
+ 10: "PIREP",
75
+ C11: "International PIREP",
76
+ DS: "Late Message",
77
+ D3: "Holding Pattern Message",
78
+ D6: "From-To + Date",
79
+ D7: "From-To + Alternate + Time",
80
+ EO: "In Range",
81
+ PW: "Position Weather",
82
+ RL: "Request Release",
83
+ R3: "Request HOWGOZIT Message",
84
+ R4: "Request the Latest POSBD",
85
+ TC: "From-To Fuel",
86
+ WB: "From-To",
87
+ W1: "Request Weather for City"
88
+ };
89
+ qualifiers() {
90
+ return {
91
+ labels: ["5Z"]
92
+ };
93
+ }
94
+ decode(message, options = {}) {
95
+ const decodeResult = this.defaultResult;
96
+ decodeResult.decoder.name = this.name;
97
+ decodeResult.formatted.description = "Airline Designated Downlink";
98
+ const uaRegex = /^\/(?<type>\w+) (?<remainder>.+)/;
99
+ let results = message.text.match(uaRegex);
100
+ if (results && results.length >= 2) {
101
+ const type = results.groups.type.split("/")[0];
102
+ const { remainder } = results.groups;
103
+ const typeDescription = this.descriptions[type] ? this.descriptions[type] : "Unknown";
104
+ decodeResult.raw.airline = "United Airlines";
105
+ decodeResult.formatted.items.push({
106
+ type: "airline",
107
+ label: "Airline",
108
+ value: "United Airlines"
109
+ });
110
+ decodeResult.raw.message_type = type;
111
+ decodeResult.formatted.items.push({
112
+ type: "message_type",
113
+ label: "Message Type",
114
+ value: `${typeDescription} (${type})`
115
+ });
116
+ if (type === "B3") {
117
+ const rdcRegex = /^(?<from>\w\w\w)(?<to>\w\w\w) (?<unknown1>\d\d) R(?<runway>.+) G(?<unknown2>.+)$/;
118
+ results = remainder.match(rdcRegex);
119
+ if (results) {
120
+ decodeResult.raw.origin = results.groups.from;
121
+ decodeResult.formatted.items.push({
122
+ type: "origin",
123
+ label: "Origin",
124
+ value: `${results.groups.from}`
125
+ });
126
+ decodeResult.raw.destination = results.groups.to;
127
+ decodeResult.formatted.items.push({
128
+ type: "destination",
129
+ label: "Destination",
130
+ value: `${results.groups.to}`
131
+ });
132
+ decodeResult.formatted.items.push({
133
+ type: "unknown1",
134
+ label: "Unknown Field 1",
135
+ value: `${results.groups.unknown1}`
136
+ });
137
+ decodeResult.raw.runway = results.groups.runway;
138
+ decodeResult.formatted.items.push({
139
+ type: "runway",
140
+ label: "Runway",
141
+ value: `${results.groups.runway}`
142
+ });
143
+ decodeResult.formatted.items.push({
144
+ type: "unknown2",
145
+ label: "Unknown Field 2",
146
+ value: `${results.groups.unknown2}`
147
+ });
148
+ } else {
149
+ if (options.debug) {
150
+ console.log(`Decoder: Unkown 5Z RDC format: ${remainder}`);
151
+ }
152
+ }
153
+ } else {
154
+ decodeResult.remaining.text = remainder;
155
+ }
156
+ decodeResult.decoded = true;
157
+ decodeResult.decoder.decodeLevel = "partial";
158
+ } else {
159
+ if (options.debug) {
160
+ console.log(`Decoder: Unknown 5Z message: ${message.text}`);
161
+ }
162
+ decodeResult.remaining.text = message.text;
163
+ decodeResult.decoded = false;
164
+ decodeResult.decoder.decodeLevel = "none";
165
+ }
166
+ return decodeResult;
167
+ }
168
+ };
169
+
170
+ // lib/plugins/Label_12_N_Space.ts
171
+ var Label_12_N_Space = class extends DecoderPlugin {
172
+ name = "label-12-n-space";
173
+ qualifiers() {
174
+ return {
175
+ labels: ["12"],
176
+ preambles: ["N "]
177
+ };
178
+ }
179
+ decode(message, options = {}) {
180
+ const decodeResult = this.defaultResult;
181
+ decodeResult.decoder.name = this.name;
182
+ decodeResult.formatted.description = "Position Report";
183
+ decodeResult.message = message;
184
+ const variant1Regex = /^(?<lat>[NS])\s(?<lat_coord>.*),(?<long>[EW])\s*(?<long_coord>.*),(?<alt>.*),(?<unkwn1>.*),\s*(?<unkwn2>.*),.(?<airframe>.*),(?<unkwn3>.*)$/;
185
+ let results;
186
+ if (results = message.text.match(variant1Regex)) {
187
+ if (options.debug) {
188
+ console.log(`Label 12 N : results`);
189
+ console.log(results);
190
+ }
191
+ decodeResult.raw.latitude_direction = results.groups.lat;
192
+ decodeResult.raw.latitude = Number(results.groups.lat_coord);
193
+ decodeResult.raw.longitude_direction = results.groups.long;
194
+ decodeResult.raw.longitude = Number(results.groups.long_coord);
195
+ decodeResult.raw.flight_level = results.groups.alt == "GRD" || results.groups.alt == "***" ? "0" : Number(results.groups.alt);
196
+ decodeResult.formatted.items.push({
197
+ type: "aircraft_position",
198
+ code: "POS",
199
+ label: "Aircraft Position",
200
+ value: `${results.groups.lat_coord} ${decodeResult.raw.latitude_direction}, ${results.groups.long_coord} ${decodeResult.raw.longitude_direction}`
201
+ });
202
+ decodeResult.formatted.items.push({
203
+ type: "flight_level",
204
+ code: "FL",
205
+ label: "Flight Level",
206
+ value: decodeResult.raw.flight_level
207
+ });
208
+ decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}, ${results.groups.unkwn3}`;
209
+ decodeResult.decoded = true;
210
+ decodeResult.decoder.decodeLevel = "partial";
211
+ } else {
212
+ if (options.debug) {
213
+ console.log(`Decoder: Unknown 12 message: ${message.text}`);
214
+ }
215
+ decodeResult.remaining.text = message.text;
216
+ decodeResult.decoded = false;
217
+ decodeResult.decoder.decodeLevel = "none";
218
+ }
219
+ return decodeResult;
220
+ }
221
+ };
222
+
223
+ // lib/utils/coordinate_utils.ts
224
+ var CoordinateUtils = class {
225
+ static decodeStringCoordinates(stringCoords) {
226
+ var results = {};
227
+ const firstChar = stringCoords.substring(0, 1);
228
+ let middleChar = stringCoords.substring(6, 7);
229
+ let longitudeChars = stringCoords.substring(7, 13);
230
+ if (middleChar == " ") {
231
+ middleChar = stringCoords.substring(7, 8);
232
+ longitudeChars = stringCoords.substring(8, 14);
233
+ }
234
+ if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
235
+ results.latitudeDirection = firstChar;
236
+ results.latitude = Number(stringCoords.substring(1, 6)) / 1e3 * (firstChar === "S" ? -1 : 1);
237
+ results.longitudeDirection = middleChar;
238
+ results.longitude = Number(longitudeChars) / 1e3 * (middleChar === "W" ? -1 : 1);
239
+ } else {
240
+ return;
241
+ }
242
+ return results;
243
+ }
244
+ static coordinateString(coords) {
245
+ return `${Math.abs(coords.latitude)} ${coords.latitudeDirection}, ${Math.abs(coords.longitude)} ${coords.longitudeDirection}`;
246
+ }
247
+ static latLonToCoordinateString(lat, lon) {
248
+ const latDir = lat > 0 ? "N" : "S";
249
+ const lonDir = lon > 0 ? "E" : "W";
250
+ return `${Math.abs(lat)} ${latDir}, ${Math.abs(lon)} ${lonDir}`;
251
+ }
252
+ };
253
+
254
+ // lib/plugins/Label_15.ts
255
+ var Label_15 = class extends DecoderPlugin {
256
+ name = "label-5z";
257
+ qualifiers() {
258
+ return {
259
+ labels: ["15"],
260
+ preambles: ["(2"]
261
+ };
262
+ }
263
+ decode(message, options = {}) {
264
+ const decodeResult = this.defaultResult;
265
+ decodeResult.decoder.name = this.name;
266
+ decodeResult.formatted.description = "Position Report";
267
+ const twoZeeRegex = /^\(2(?<between>.+)\(Z$/;
268
+ const results = message.text.match(twoZeeRegex);
269
+ if (results) {
270
+ decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.between.substr(0, 13));
271
+ if (decodeResult.raw.position) {
272
+ decodeResult.formatted.items.push({
273
+ type: "position",
274
+ code: "POS",
275
+ label: "Position",
276
+ value: CoordinateUtils.coordinateString(decodeResult.raw.position)
277
+ });
278
+ }
279
+ }
280
+ decodeResult.decoded = true;
281
+ decodeResult.decoder.decodeLevel = "partial";
282
+ return decodeResult;
283
+ }
284
+ };
285
+
286
+ // lib/plugins/Label_15_FST.ts
287
+ var Label_15_FST = class extends DecoderPlugin {
288
+ name = "label-15-fst";
289
+ qualifiers() {
290
+ return {
291
+ labels: ["15"],
292
+ preambles: ["FST01"]
293
+ };
294
+ }
295
+ decode(message, options = {}) {
296
+ const decodeResult = this.defaultResult;
297
+ decodeResult.decoder.name = this.name;
298
+ decodeResult.formatted.description = "Position Report";
299
+ decodeResult.message = message;
300
+ decodeResult.raw.departure_icao = message.text.substring(5, 9);
301
+ decodeResult.raw.arrival_icao = message.text.substring(9, 13);
302
+ const stringCoords = message.text.substring(13);
303
+ const firstChar = stringCoords.substring(0, 1);
304
+ const middleChar = stringCoords.substring(7, 8);
305
+ decodeResult.raw.position = {};
306
+ if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
307
+ decodeResult.raw.position.latitudeDirection = firstChar;
308
+ decodeResult.raw.position.latitude = Number(stringCoords.substring(1, 7)) / 1e4 * (firstChar === "S" ? -1 : 1);
309
+ decodeResult.raw.position.longitudeDirection = middleChar;
310
+ decodeResult.raw.position.longitude = Number(stringCoords.substring(8, 26)) / 1e5 * (middleChar === "W" ? -1 : 1);
311
+ } else {
312
+ decodeResult.decoded = false;
313
+ decodeResult.decoder.decodeLevel = "none";
314
+ return decodeResult;
315
+ }
316
+ decodeResult.formatted.items.push({
317
+ type: "position",
318
+ label: "Position",
319
+ value: CoordinateUtils.coordinateString(decodeResult.raw.position)
320
+ });
321
+ decodeResult.formatted.items.push({
322
+ type: "origin",
323
+ code: "ORG",
324
+ label: "Origin",
325
+ value: decodeResult.raw.departure_icao
326
+ });
327
+ decodeResult.formatted.items.push({
328
+ type: "destination",
329
+ code: "DST",
330
+ label: "Destination",
331
+ value: decodeResult.raw.arrival_icao
332
+ });
333
+ decodeResult.decoded = true;
334
+ decodeResult.decoder.decodeLevel = "full";
335
+ return decodeResult;
336
+ }
337
+ };
338
+
339
+ // lib/plugins/Label_16_N_Space.ts
340
+ var Label_16_N_Space = class extends DecoderPlugin {
341
+ name = "label-16-n-space";
342
+ qualifiers() {
343
+ return {
344
+ labels: ["16"],
345
+ preambles: ["N "]
346
+ };
347
+ }
348
+ decode(message, options = {}) {
349
+ const decodeResult = this.defaultResult;
350
+ decodeResult.decoder.name = this.name;
351
+ decodeResult.formatted.description = "Position Report";
352
+ decodeResult.message = message;
353
+ let variant1Regex = /^(?<lat>[NS])\s(?<lat_coord>.*),(?<long>[EW])\s*(?<long_coord>.*),(?<alt>.*),(?<unkwn1>.*),\s*(?<unkwn2>.*)$/;
354
+ let variant2Regex = /^(?<lat>[NS])\s(?<lat_coord>.*)\/(?<long>[EW])\s*(?<long_coord>.*)$/;
355
+ let results;
356
+ if (results = message.text.match(variant1Regex)) {
357
+ if (options.debug) {
358
+ console.log(`Label 16 N : results`);
359
+ console.log(results);
360
+ }
361
+ decodeResult.raw.latitude_direction = results.groups.lat;
362
+ decodeResult.raw.latitude = Number(results.groups.lat_coord);
363
+ decodeResult.raw.longitude_direction = results.groups.long;
364
+ decodeResult.raw.longitude = Number(results.groups.long_coord);
365
+ decodeResult.raw.flight_level = results.groups.alt == "GRD" || results.groups.alt == "***" ? "0" : Number(results.groups.alt);
366
+ decodeResult.formatted.items.push({
367
+ type: "aircraft_position",
368
+ code: "POS",
369
+ label: "Aircraft Position",
370
+ value: `${decodeResult.raw.latitude} ${decodeResult.raw.latitude_direction}, ${decodeResult.raw.longitude} ${decodeResult.raw.longitude_direction}`
371
+ });
372
+ decodeResult.formatted.items.push({
373
+ type: "flight_level",
374
+ code: "FL",
375
+ label: "Flight Level",
376
+ value: decodeResult.raw.flight_level
377
+ });
378
+ decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}`;
379
+ decodeResult.decoded = true;
380
+ decodeResult.decoder.decodeLevel = "partial";
381
+ } else if (results = message.text.match(variant2Regex)) {
382
+ if (options.debug) {
383
+ console.log(`Label 16 N : results`);
384
+ console.log(results);
385
+ }
386
+ decodeResult.raw.latitude_direction = results.groups.lat;
387
+ decodeResult.raw.latitude = Number(results.groups.lat_coord);
388
+ decodeResult.raw.longitude_direction = results.groups.long;
389
+ decodeResult.raw.longitude = Number(results.groups.long_coord);
390
+ decodeResult.formatted.items.push({
391
+ type: "aircraft_position",
392
+ code: "POS",
393
+ label: "Aircraft Position",
394
+ value: `${results.groups.lat_coord} ${decodeResult.raw.latitude_direction}, ${results.groups.long_coord} ${decodeResult.raw.longitude_direction}`
395
+ });
396
+ decodeResult.decoded = true;
397
+ decodeResult.decoder.decodeLevel = "full";
398
+ } else {
399
+ if (options.debug) {
400
+ console.log(`Decoder: Unknown 16 message: ${message.text}`);
401
+ }
402
+ decodeResult.remaining.text = message.text;
403
+ decodeResult.decoded = false;
404
+ decodeResult.decoder.decodeLevel = "none";
405
+ }
406
+ return decodeResult;
407
+ }
408
+ };
409
+
410
+ // lib/DateTimeUtils.ts
411
+ var DateTimeUtils = class {
412
+ // Expects a four digit UTC time string (HHMM)
413
+ static UTCToString(UTCString) {
414
+ let utcDate = /* @__PURE__ */ new Date();
415
+ utcDate.setUTCHours(+UTCString.substr(0, 2), +UTCString.substr(2, 2), 0);
416
+ return utcDate.toTimeString();
417
+ }
418
+ // Expects a six digit date string and a four digit UTC time string
419
+ // (DDMMYY) (HHMM)
420
+ static UTCDateTimeToString(dateString, timeString) {
421
+ let utcDate = /* @__PURE__ */ new Date();
422
+ utcDate.setUTCDate(+dateString.substr(0, 2));
423
+ utcDate.setUTCMonth(+dateString.substr(2, 2));
424
+ if (dateString.length === 6) {
425
+ utcDate.setUTCFullYear(2e3 + +dateString.substr(4, 2));
426
+ }
427
+ if (timeString.length === 6) {
428
+ utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), +timeString.substr(4, 2));
429
+ } else {
430
+ utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), 0);
431
+ }
432
+ return utcDate.toUTCString();
433
+ }
434
+ /**
435
+ *
436
+ * @param time HHMMSS
437
+ * @returns seconds since midnight
438
+ */
439
+ static convertHHMMSSToTod(time) {
440
+ const h = Number(time.substring(0, 2));
441
+ const m = Number(time.substring(2, 4));
442
+ const s = Number(time.substring(4, 6));
443
+ const tod = h * 3600 + m * 60 + s;
444
+ return tod;
445
+ }
446
+ /**
447
+ *
448
+ * @param time HHMMSS
449
+ * @param date MMDDYY
450
+ * @returns seconds since epoch
451
+ */
452
+ static convertDateTimeToEpoch(time, date) {
453
+ const timestamp = `20${date.substring(4, 6)}-${date.substring(0, 2)}-${date.substring(2, 4)}T${time.substring(0, 2)}:${time.substring(2, 4)}:${time.substring(4, 6)}.000Z`;
454
+ const millis = Date.parse(timestamp);
455
+ return millis / 1e3;
456
+ }
457
+ };
458
+
459
+ // lib/plugins/Label_1M_Slash.ts
460
+ var Label_1M_Slash = class extends DecoderPlugin {
461
+ name = "label-1m-slash";
462
+ qualifiers() {
463
+ return {
464
+ labels: ["1M"],
465
+ preambles: ["/"]
466
+ };
467
+ }
468
+ decode(message, options = {}) {
469
+ const decodeResult = this.defaultResult;
470
+ decodeResult.decoder.name = this.name;
471
+ decodeResult.formatted.description = "ETA Report";
472
+ decodeResult.message = message;
473
+ const results = message.text.split(/\n|\//).slice(1);
474
+ if (results) {
475
+ if (options.debug) {
476
+ console.log(`Label 1M ETA: results`);
477
+ console.log(results);
478
+ }
479
+ decodeResult.raw.flight_number = results[0];
480
+ decodeResult.raw.departure_icao = results[3];
481
+ decodeResult.raw.arrival_icao = results[4];
482
+ decodeResult.raw.alternate_icao = results[5];
483
+ decodeResult.raw.arrival_runway = results[8].replace(decodeResult.raw.arrival_icao, "");
484
+ decodeResult.formatted.items.push({
485
+ type: "eta",
486
+ code: "ETA",
487
+ label: "Estimated Time of Arrival",
488
+ value: DateTimeUtils.UTCDateTimeToString(results[2], results[7])
489
+ });
490
+ decodeResult.formatted.items.push({
491
+ type: "destination",
492
+ code: "DST",
493
+ label: "Destination",
494
+ value: decodeResult.raw.arrival_icao
495
+ });
496
+ decodeResult.formatted.items.push({
497
+ type: "origin",
498
+ code: "ORG",
499
+ label: "Origin",
500
+ value: decodeResult.raw.departure_icao
501
+ });
502
+ }
503
+ decodeResult.decoded = true;
504
+ decodeResult.decoder.decodeLevel = "partial";
505
+ return decodeResult;
506
+ }
507
+ };
508
+
509
+ // lib/plugins/Label_20_POS.ts
510
+ var Label_20_POS = class extends DecoderPlugin {
511
+ name = "label-20-pos";
512
+ qualifiers() {
513
+ return {
514
+ labels: ["20"],
515
+ preambles: ["POS"]
516
+ };
517
+ }
518
+ decode(message, options = {}) {
519
+ const decodeResult = this.defaultResult;
520
+ decodeResult.decoder.name = this.name;
521
+ decodeResult.formatted.description = "Position Report";
522
+ decodeResult.message = message;
523
+ decodeResult.raw.preamble = message.text.substring(0, 3);
524
+ const content = message.text.substring(3);
525
+ console.log("Content: " + content);
526
+ const fields = content.split(",");
527
+ console.log("Field Count: " + fields.length);
528
+ if (fields.length == 11) {
529
+ console.log(`DEBUG: ${this.name}: Variation 1 detected`);
530
+ const rawCoords = fields[0];
531
+ decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
532
+ if (decodeResult.raw.position) {
533
+ decodeResult.formatted.items.push({
534
+ type: "position",
535
+ label: "Position",
536
+ value: CoordinateUtils.coordinateString(decodeResult.raw.position)
537
+ });
538
+ }
539
+ decodeResult.decoded = true;
540
+ decodeResult.decoder.decodeLevel = "full";
541
+ } else if (fields.length == 5) {
542
+ console.log(`DEBUG: ${this.name}: Variation 2 detected`);
543
+ const rawCoords = fields[0];
544
+ decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
545
+ decodeResult.formatted.items.push({
546
+ type: "position",
547
+ label: "Position",
548
+ value: CoordinateUtils.coordinateString(decodeResult.raw.position)
549
+ });
550
+ decodeResult.decoded = true;
551
+ decodeResult.decoder.decodeLevel = "full";
552
+ } else {
553
+ console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
554
+ decodeResult.decoded = false;
555
+ decodeResult.decoder.decodeLevel = "none";
556
+ }
557
+ return decodeResult;
558
+ }
559
+ };
560
+
561
+ // lib/plugins/Label_30_Slash_EA.ts
562
+ var Label_30_Slash_EA = class extends DecoderPlugin {
563
+ name = "label-30-slash-ea";
564
+ qualifiers() {
565
+ return {
566
+ labels: ["30"],
567
+ preambles: ["/EA"]
568
+ };
569
+ }
570
+ decode(message, options = {}) {
571
+ const decodeResult = this.defaultResult;
572
+ decodeResult.decoder.name = this.name;
573
+ decodeResult.formatted.description = "ETA Report";
574
+ decodeResult.message = message;
575
+ const results = message.text.split(/\n|\//).slice(1);
576
+ if (results) {
577
+ if (options.debug) {
578
+ console.log(`Label 30 EA: results`);
579
+ console.log(results);
580
+ }
581
+ }
582
+ decodeResult.formatted.items.push({
583
+ type: "eta",
584
+ code: "ETA",
585
+ label: "Estimated Time of Arrival",
586
+ value: DateTimeUtils.UTCToString(results[0].substr(2, 4))
587
+ });
588
+ if (results[1].substr(0, 2) === "DS") {
589
+ decodeResult.raw.arrival_icao = results[1].substr(2, 4);
590
+ decodeResult.formatted.items.push({
591
+ type: "destination",
592
+ code: "DST",
593
+ label: "Destination",
594
+ value: decodeResult.raw.arrival_icao
595
+ });
596
+ decodeResult.remaining.text = "/".concat(results[2]);
597
+ } else {
598
+ decodeResult.remaining.text = "/".concat(results[1], "/", results[2]);
599
+ }
600
+ decodeResult.decoded = true;
601
+ decodeResult.decoder.decodeLevel = "partial";
602
+ return decodeResult;
603
+ }
604
+ };
605
+
606
+ // lib/plugins/Label_44_ETA.ts
607
+ var Label_44_ETA = class extends DecoderPlugin {
608
+ name = "label-44-eta";
609
+ qualifiers() {
610
+ return {
611
+ labels: ["44"],
612
+ preambles: ["00ETA01", "00ETA02", "00ETA03", "ETA01", "ETA02", "ETA03"]
613
+ };
614
+ }
615
+ decode(message, options = {}) {
616
+ const decodeResult = this.defaultResult;
617
+ decodeResult.decoder.name = this.name;
618
+ decodeResult.formatted.description = "ETA Report";
619
+ decodeResult.message = message;
620
+ const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
621
+ const results = message.text.match(regex);
622
+ if (results) {
623
+ if (options.debug) {
624
+ console.log(`Label 44 ETA Report: groups`);
625
+ console.log(results.groups);
626
+ }
627
+ decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
628
+ decodeResult.raw.departure_icao = results.groups.departure_icao;
629
+ decodeResult.raw.arrival_icao = results.groups.arrival_icao;
630
+ decodeResult.raw.current_time = Date.parse(
631
+ (/* @__PURE__ */ 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"
632
+ );
633
+ if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
634
+ decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
635
+ }
636
+ if (decodeResult.raw.position) {
637
+ decodeResult.formatted.items.push({
638
+ type: "position",
639
+ code: "POS",
640
+ label: "Position",
641
+ value: CoordinateUtils.coordinateString(decodeResult.raw.position)
642
+ });
643
+ }
644
+ decodeResult.formatted.items.push({
645
+ type: "origin",
646
+ code: "ORG",
647
+ label: "Origin",
648
+ value: decodeResult.raw.departure_icao
649
+ });
650
+ decodeResult.formatted.items.push({
651
+ type: "destination",
652
+ code: "DST",
653
+ label: "Destination",
654
+ value: decodeResult.raw.arrival_icao
655
+ });
656
+ }
657
+ decodeResult.decoded = true;
658
+ decodeResult.decoder.decodeLevel = "full";
659
+ return decodeResult;
660
+ }
661
+ };
662
+
663
+ // lib/plugins/Label_44_IN.ts
664
+ var Label_44_IN = class extends DecoderPlugin {
665
+ name = "label-44-in";
666
+ qualifiers() {
667
+ return {
668
+ labels: ["44"],
669
+ preambles: ["00IN01", "00IN02", "00IN03", "IN01", "IN02", "IN03"]
670
+ };
671
+ }
672
+ decode(message, options = {}) {
673
+ const decodeResult = this.defaultResult;
674
+ decodeResult.decoder.name = this.name;
675
+ decodeResult.formatted.description = "In Air Report";
676
+ decodeResult.message = message;
677
+ const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
678
+ const results = message.text.match(regex);
679
+ if (results) {
680
+ if (options.debug) {
681
+ console.log(`Label 44 In Air Report: groups`);
682
+ console.log(results.groups);
683
+ }
684
+ decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
685
+ decodeResult.raw.departure_icao = results.groups.departure_icao;
686
+ decodeResult.raw.arrival_icao = results.groups.arrival_icao;
687
+ decodeResult.raw.current_time = Date.parse(
688
+ (/* @__PURE__ */ 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"
689
+ );
690
+ if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
691
+ decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
692
+ }
693
+ if (decodeResult.raw.position) {
694
+ decodeResult.formatted.items.push({
695
+ type: "position",
696
+ code: "POS",
697
+ label: "Position",
698
+ value: CoordinateUtils.coordinateString(decodeResult.raw.position)
699
+ });
700
+ }
701
+ decodeResult.formatted.items.push({
702
+ type: "origin",
703
+ code: "ORG",
704
+ label: "Origin",
705
+ value: decodeResult.raw.departure_icao
706
+ });
707
+ decodeResult.formatted.items.push({
708
+ type: "destination",
709
+ code: "DST",
710
+ label: "Destination",
711
+ value: decodeResult.raw.arrival_icao
712
+ });
713
+ }
714
+ decodeResult.decoded = true;
715
+ decodeResult.decoder.decodeLevel = "full";
716
+ return decodeResult;
717
+ }
718
+ };
719
+
720
+ // lib/plugins/Label_44_OFF.ts
721
+ var Label_44_OFF = class extends DecoderPlugin {
722
+ name = "label-44-off";
723
+ qualifiers() {
724
+ return {
725
+ labels: ["44"],
726
+ preambles: ["00OFF01", "00OFF02", "00OFF03", "OFF01", "OFF02", "OFF03"]
727
+ };
728
+ }
729
+ decode(message, options = {}) {
730
+ const decodeResult = this.defaultResult;
731
+ decodeResult.decoder.name = this.name;
732
+ decodeResult.formatted.description = "Off Runway Report";
733
+ decodeResult.message = message;
734
+ const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<eta_time>.*),(?<fuel_in_tons>.*)$/;
735
+ const results = message.text.match(regex);
736
+ if (results) {
737
+ if (options.debug) {
738
+ console.log(`Label 44 Off Runway Report: groups`);
739
+ console.log(results.groups);
740
+ }
741
+ decodeResult.raw.departure_icao = results.groups.departure_icao;
742
+ decodeResult.raw.arrival_icao = results.groups.arrival_icao;
743
+ decodeResult.raw.current_time = Date.parse(
744
+ (/* @__PURE__ */ 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"
745
+ );
746
+ decodeResult.raw.eta_time = Date.parse(
747
+ (/* @__PURE__ */ 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"
748
+ );
749
+ if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
750
+ decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
751
+ }
752
+ decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
753
+ if (decodeResult.raw.position) {
754
+ decodeResult.formatted.items.push({
755
+ type: "position",
756
+ code: "POS",
757
+ label: "Position",
758
+ value: CoordinateUtils.coordinateString(decodeResult.raw.position)
759
+ });
760
+ }
761
+ decodeResult.formatted.items.push({
762
+ type: "origin",
763
+ code: "ORG",
764
+ label: "Origin",
765
+ value: decodeResult.raw.departure_icao
766
+ });
767
+ decodeResult.formatted.items.push({
768
+ type: "destination",
769
+ code: "DST",
770
+ label: "Destination",
771
+ value: decodeResult.raw.arrival_icao
772
+ });
773
+ }
774
+ decodeResult.decoded = true;
775
+ decodeResult.decoder.decodeLevel = "full";
776
+ return decodeResult;
777
+ }
778
+ };
779
+
780
+ // lib/plugins/Label_44_ON.ts
781
+ var Label_44_ON = class extends DecoderPlugin {
782
+ name = "label-44-on";
783
+ qualifiers() {
784
+ return {
785
+ labels: ["44"],
786
+ preambles: ["00ON01", "00ON02", "00ON03", "ON01", "ON02", "ON03"]
787
+ };
788
+ }
789
+ decode(message, options = {}) {
790
+ const decodeResult = this.defaultResult;
791
+ decodeResult.decoder.name = this.name;
792
+ decodeResult.formatted.description = "On Runway Report";
793
+ decodeResult.message = message;
794
+ const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
795
+ const results = message.text.match(regex);
796
+ if (results) {
797
+ if (options.debug) {
798
+ console.log(`Label 44 On Runway Report: groups`);
799
+ console.log(results.groups);
800
+ }
801
+ decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
802
+ decodeResult.raw.departure_icao = results.groups.departure_icao;
803
+ decodeResult.raw.arrival_icao = results.groups.arrival_icao;
804
+ decodeResult.raw.current_time = Date.parse(
805
+ (/* @__PURE__ */ 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"
806
+ );
807
+ if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
808
+ decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
809
+ }
810
+ if (decodeResult.raw.position) {
811
+ decodeResult.formatted.items.push({
812
+ type: "position",
813
+ code: "POS",
814
+ label: "Position",
815
+ value: CoordinateUtils.coordinateString(decodeResult.raw.position)
816
+ });
817
+ }
818
+ decodeResult.formatted.items.push({
819
+ type: "origin",
820
+ code: "ORG",
821
+ label: "Origin",
822
+ value: decodeResult.raw.departure_icao
823
+ });
824
+ decodeResult.formatted.items.push({
825
+ type: "destination",
826
+ code: "DST",
827
+ label: "Destination",
828
+ value: decodeResult.raw.arrival_icao
829
+ });
830
+ }
831
+ decodeResult.decoded = true;
832
+ decodeResult.decoder.decodeLevel = "full";
833
+ return decodeResult;
834
+ }
835
+ };
836
+
837
+ // lib/plugins/Label_44_POS.ts
838
+ var Label_44_POS = class extends DecoderPlugin {
839
+ name = "label-44-pos";
840
+ qualifiers() {
841
+ return {
842
+ labels: ["44"],
843
+ preambles: ["00POS01", "00POS02", "00POS03", "POS01", "POS02", "POS03"]
844
+ };
845
+ }
846
+ decode(message, options = {}) {
847
+ const decodeResult = this.defaultResult;
848
+ decodeResult.decoder.name = this.name;
849
+ decodeResult.formatted.description = "Position Report";
850
+ decodeResult.message = message;
851
+ const regex = /^.*,(?<unsplit_coords>.*),(?<flight_level_or_ground>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<eta_time>.*),(?<fuel_in_tons>.*)$/;
852
+ const results = message.text.match(regex);
853
+ if (results) {
854
+ if (options.debug) {
855
+ console.log(`Label 44 Position Report: groups`);
856
+ console.log(results.groups);
857
+ }
858
+ decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
859
+ decodeResult.raw.flight_level = results.groups.flight_level_or_ground == "GRD" || results.groups.flight_level_or_ground == "***" ? "0" : Number(results.groups.flight_level_or_ground);
860
+ decodeResult.raw.departure_icao = results.groups.departure_icao;
861
+ decodeResult.raw.arrival_icao = results.groups.arrival_icao;
862
+ decodeResult.raw.current_time = Date.parse(
863
+ (/* @__PURE__ */ 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"
864
+ );
865
+ decodeResult.raw.eta_time = Date.parse(
866
+ (/* @__PURE__ */ 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"
867
+ );
868
+ if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
869
+ decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
870
+ }
871
+ if (decodeResult.raw.position) {
872
+ decodeResult.formatted.items.push({
873
+ type: "position",
874
+ code: "POS",
875
+ label: "Position",
876
+ value: CoordinateUtils.coordinateString(decodeResult.raw.position)
877
+ });
878
+ }
879
+ decodeResult.formatted.items.push({
880
+ type: "origin",
881
+ code: "ORG",
882
+ label: "Origin",
883
+ value: decodeResult.raw.departure_icao
884
+ });
885
+ decodeResult.formatted.items.push({
886
+ type: "destination",
887
+ code: "DST",
888
+ label: "Destination",
889
+ value: decodeResult.raw.arrival_icao
890
+ });
891
+ decodeResult.formatted.items.push({
892
+ type: "flight_level",
893
+ code: "FL",
894
+ label: "Flight Level",
895
+ value: decodeResult.raw.flight_level
896
+ });
897
+ }
898
+ decodeResult.decoded = true;
899
+ decodeResult.decoder.decodeLevel = "full";
900
+ return decodeResult;
901
+ }
902
+ };
903
+
904
+ // lib/plugins/Label_80.ts
905
+ var Label_80 = class extends DecoderPlugin {
906
+ name = "label-80";
907
+ descriptions = {
908
+ ALT: "Altitude",
909
+ DWND: "Wind Direction",
910
+ ETA: "Estimated Time of Arrival",
911
+ FOB: "Fuel on Board",
912
+ FL: "Flight Level",
913
+ HDG: "Heading",
914
+ MCH: "Aircraft Speed",
915
+ NWYP: "Next Waypoint",
916
+ POS: "Aircraft Position",
917
+ SAT: "Static Air Temperature",
918
+ SWND: "Wind Speed",
919
+ TAS: "True Airspeed",
920
+ WYP: "Waypoint"
921
+ };
922
+ qualifiers() {
923
+ return {
924
+ labels: ["80"],
925
+ preambles: ["3N01 POSRPT"]
926
+ };
927
+ }
928
+ decode(message, options = {}) {
929
+ const decodeResult = this.defaultResult;
930
+ decodeResult.decoder.name = this.name;
931
+ decodeResult.formatted.description = "Airline Defined Position Report";
932
+ const parts = message.text.split("\n");
933
+ let posRptRegex = /^3N01 POSRPT \d\d\d\d\/\d\d (?<orig>\w+)\/(?<dest>\w+) \.(?<tail>[\w-]+)(\/(?<agate>.+) (?<sta>\w+:\w+))*/;
934
+ let results = parts[0].match(posRptRegex);
935
+ if (results && results.length > 0) {
936
+ decodeResult.raw.origin = results.groups.orig;
937
+ decodeResult.formatted.items.push({
938
+ type: "origin",
939
+ code: "ORG",
940
+ label: "Origin",
941
+ value: `${results.groups.orig}`
942
+ });
943
+ decodeResult.raw.destination = results.groups.dest;
944
+ decodeResult.formatted.items.push({
945
+ type: "destination",
946
+ code: "DST",
947
+ label: "Destination",
948
+ value: `${results.groups.dest}`
949
+ });
950
+ decodeResult.raw.tail = results.groups.tail;
951
+ decodeResult.formatted.items.push({
952
+ type: "tail",
953
+ label: "Tail",
954
+ value: `${results.groups.tail}`
955
+ });
956
+ if (results.groups.agate) {
957
+ decodeResult.raw.arrival_gate = results.groups.agate;
958
+ decodeResult.formatted.items.push({
959
+ type: "arrival_gate",
960
+ code: "ARG",
961
+ label: "Arrival Gate",
962
+ value: `${results.groups.agate}`
963
+ });
964
+ decodeResult.raw.scheduled_time_of_arrival = results.groups.sta;
965
+ decodeResult.formatted.items.push({
966
+ type: "scheduled_time_of_arrival",
967
+ code: "STA",
968
+ label: "Scheduled Time of Arrival",
969
+ value: `${results.groups.sta}`
970
+ });
971
+ }
972
+ posRptRegex = /\/(?<field>\w+)\s(?<value>[\w\+\-:\.]+)\s*/gi;
973
+ const remainingParts = parts.slice(1);
974
+ for (const part of remainingParts) {
975
+ const matches = part.matchAll(posRptRegex);
976
+ for (const match of matches) {
977
+ switch (match.groups.field) {
978
+ case "ALT": {
979
+ decodeResult.raw.altitude = match.groups.value;
980
+ decodeResult.formatted.items.push({
981
+ type: "altitude",
982
+ code: "ALT",
983
+ label: this.descriptions[match.groups.field],
984
+ value: `${decodeResult.raw.altitude} feet`
985
+ });
986
+ break;
987
+ }
988
+ case "DWND": {
989
+ decodeResult.raw.wind_direction = Number(match.groups.value);
990
+ decodeResult.formatted.items.push({
991
+ type: "wind_direction",
992
+ code: "DWND",
993
+ label: this.descriptions[match.groups.field],
994
+ value: decodeResult.raw.wind_direction
995
+ });
996
+ break;
997
+ }
998
+ case "FL": {
999
+ decodeResult.raw.flight_level = match.groups.value;
1000
+ decodeResult.formatted.items.push({
1001
+ type: "flight_level",
1002
+ code: "FL",
1003
+ label: this.descriptions[match.groups.field],
1004
+ value: decodeResult.raw.flight_level
1005
+ });
1006
+ break;
1007
+ }
1008
+ case "FOB": {
1009
+ decodeResult.raw.fuel_on_board = match.groups.value;
1010
+ decodeResult.formatted.items.push({
1011
+ type: "fuel_on_board",
1012
+ code: "FOB",
1013
+ label: this.descriptions[match.groups.field],
1014
+ value: decodeResult.raw.fuel_on_board
1015
+ });
1016
+ break;
1017
+ }
1018
+ case "HDG": {
1019
+ decodeResult.raw.heading = Number(match.groups.value);
1020
+ decodeResult.formatted.items.push({
1021
+ type: "heading",
1022
+ code: "HDG",
1023
+ label: this.descriptions[match.groups.field],
1024
+ value: decodeResult.raw.heading
1025
+ });
1026
+ break;
1027
+ }
1028
+ case "MCH": {
1029
+ decodeResult.raw.mach = match.groups.value / 1e3;
1030
+ decodeResult.formatted.items.push({
1031
+ type: "mach",
1032
+ code: "MCH",
1033
+ label: this.descriptions[match.groups.field],
1034
+ value: `${decodeResult.raw.mach} Mach`
1035
+ });
1036
+ break;
1037
+ }
1038
+ case "NWYP": {
1039
+ decodeResult.raw.next_waypoint = match.groups.value;
1040
+ decodeResult.formatted.items.push({
1041
+ type: "next_waypoint",
1042
+ code: "NWYP",
1043
+ label: this.descriptions[match.groups.field],
1044
+ value: decodeResult.raw.next_waypoint
1045
+ });
1046
+ break;
1047
+ }
1048
+ case "POS": {
1049
+ const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
1050
+ const posResult = match.groups.value.match(posRegex);
1051
+ const lat = Number(posResult.groups.lat) * (posResult.groups.lngd === "S" ? -1 : 1);
1052
+ const lon = Number(posResult.groups.lng) * (posResult.groups.lngd === "W" ? -1 : 1);
1053
+ const latitude = Number.isInteger(lat) ? lat / 1e3 : lat / 100;
1054
+ const longitude = Number.isInteger(lon) ? lon / 1e3 : lon / 100;
1055
+ decodeResult.raw.aircraft_position = {
1056
+ latitude,
1057
+ longitude
1058
+ };
1059
+ decodeResult.formatted.items.push({
1060
+ type: "position",
1061
+ code: "POS",
1062
+ label: "Position",
1063
+ value: `${Math.abs(latitude).toPrecision(5)} ${posResult.groups.latd}, ${Math.abs(longitude).toPrecision(5)} ${posResult.groups.lngd}`
1064
+ });
1065
+ break;
1066
+ }
1067
+ case "SWND": {
1068
+ decodeResult.raw.wind_speed = Number(match.groups.value);
1069
+ decodeResult.formatted.items.push({
1070
+ type: "wind_speed",
1071
+ code: "SWND",
1072
+ label: this.descriptions[match.groups.field],
1073
+ value: decodeResult.raw.wind_speed
1074
+ });
1075
+ break;
1076
+ }
1077
+ default: {
1078
+ if (match.groups.field != void 0) {
1079
+ const description = this.descriptions[match.groups.field] ? this.descriptions[match.groups.field] : "Unknown";
1080
+ decodeResult.formatted.items.push({
1081
+ type: match.groups.field,
1082
+ code: match.groups.field,
1083
+ label: description || `Unknown (${match.groups.field})`,
1084
+ value: `${match.groups.value}`
1085
+ });
1086
+ }
1087
+ }
1088
+ }
1089
+ }
1090
+ }
1091
+ decodeResult.decoded = true;
1092
+ decodeResult.decodeLevel = "partial";
1093
+ }
1094
+ return decodeResult;
1095
+ }
1096
+ };
1097
+
1098
+ // lib/plugins/Label_8E.ts
1099
+ var Label_8E = class extends DecoderPlugin {
1100
+ name = "label-8e";
1101
+ qualifiers() {
1102
+ return {
1103
+ labels: ["8E"]
1104
+ };
1105
+ }
1106
+ decode(message, options = {}) {
1107
+ const decodeResult = this.defaultResult;
1108
+ decodeResult.decoder.name = this.name;
1109
+ decodeResult.formatted.description = "ETA Report";
1110
+ decodeResult.message = message;
1111
+ const regex = /^(?<arrival_icao>\w{4}),(?<arrival_eta>\d{4})$/;
1112
+ const results = message.text.match(regex);
1113
+ if (results) {
1114
+ if (options.debug) {
1115
+ console.log(`Label 8E ETA: groups`);
1116
+ console.log(results.groups);
1117
+ }
1118
+ decodeResult.formatted.items.push({
1119
+ type: "eta",
1120
+ code: "ETA",
1121
+ label: "Estimated Time of Arrival",
1122
+ value: DateTimeUtils.UTCToString(results.groups.arrival_eta)
1123
+ });
1124
+ decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1125
+ decodeResult.formatted.items.push({
1126
+ type: "destination",
1127
+ code: "DST",
1128
+ label: "Destination",
1129
+ value: decodeResult.raw.arrival_icao
1130
+ });
1131
+ }
1132
+ decodeResult.decoded = true;
1133
+ decodeResult.decoder.decodeLevel = "full";
1134
+ return decodeResult;
1135
+ }
1136
+ };
1137
+
1138
+ // lib/plugins/Label_B6.ts
1139
+ var Label_B6_Forwardslash = class extends DecoderPlugin {
1140
+ name = "label-b6-forwardslash";
1141
+ qualifiers() {
1142
+ return {
1143
+ labels: ["B6"],
1144
+ preambles: ["/"]
1145
+ };
1146
+ }
1147
+ decode(message, options = {}) {
1148
+ const decodeResult = this.defaultResult;
1149
+ decodeResult.decoder.name = this.name;
1150
+ decodeResult.formatted.description = "CPDLC Message";
1151
+ decodeResult.message = message;
1152
+ if (options.debug) {
1153
+ console.log("CPDLC: " + message);
1154
+ }
1155
+ return decodeResult;
1156
+ }
1157
+ };
1158
+
1159
+ // lib/plugins/Label_ColonComma.ts
1160
+ var Label_ColonComma = class extends DecoderPlugin {
1161
+ name = "label-colon-comma";
1162
+ qualifiers() {
1163
+ return {
1164
+ labels: [":;"]
1165
+ };
1166
+ }
1167
+ decode(message, options = {}) {
1168
+ const decodeResult = this.defaultResult;
1169
+ decodeResult.decoder.name = this.name;
1170
+ decodeResult.raw.frequency = Number(message.text) / 1e3;
1171
+ decodeResult.formatted.description = "Aircraft Transceiver Frequency Change";
1172
+ decodeResult.formatted.items.push({
1173
+ type: "frequency",
1174
+ label: "Frequency",
1175
+ value: `${decodeResult.raw.frequency} MHz`
1176
+ });
1177
+ decodeResult.decoded = true;
1178
+ decodeResult.decoder.decodeLevel = "full";
1179
+ return decodeResult;
1180
+ }
1181
+ };
1182
+
1183
+ // lib/utils/route_utils.ts
1184
+ var RouteUtils = class _RouteUtils {
1185
+ static routeToString(route) {
1186
+ let str = "";
1187
+ if (route.name) {
1188
+ str += route.name;
1189
+ }
1190
+ if (route.runway) {
1191
+ str += `(${route.runway})`;
1192
+ }
1193
+ if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
1194
+ str += " starting at ";
1195
+ } else if (str.length !== 0 && route.waypoints) {
1196
+ str += ": ";
1197
+ }
1198
+ if (route.waypoints) {
1199
+ str += _RouteUtils.waypointsToString(route.waypoints);
1200
+ }
1201
+ return str;
1202
+ }
1203
+ static waypointToString(waypoint) {
1204
+ let s = waypoint.name;
1205
+ if (waypoint.latitude && waypoint.longitude) {
1206
+ s += `(${CoordinateUtils.latLonToCoordinateString(waypoint.latitude, waypoint.longitude)})`;
1207
+ }
1208
+ if (waypoint.time && waypoint.timeFormat) {
1209
+ s += `@${_RouteUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
1210
+ }
1211
+ return s;
1212
+ }
1213
+ static getWaypoint(leg) {
1214
+ const waypoint = leg.split(",");
1215
+ if (waypoint.length == 2) {
1216
+ const position = CoordinateUtils.decodeStringCoordinates(waypoint[1]);
1217
+ return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
1218
+ }
1219
+ if (leg.length == 14) {
1220
+ const position = CoordinateUtils.decodeStringCoordinates(leg);
1221
+ return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
1222
+ }
1223
+ return { name: leg };
1224
+ }
1225
+ // move out if we want public
1226
+ static timestampToString(time, format) {
1227
+ const date = new Date(time * 1e3);
1228
+ if (format == "tod") {
1229
+ return date.toISOString().slice(11, 19);
1230
+ }
1231
+ return date.toISOString().slice(0, -5) + "Z";
1232
+ }
1233
+ static waypointsToString(waypoints) {
1234
+ let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
1235
+ if (str.startsWith(" > ")) {
1236
+ str = ">>" + str.slice(2);
1237
+ }
1238
+ return str;
1239
+ }
1240
+ };
1241
+
1242
+ // lib/utils/flight_plan_utils.ts
1243
+ var FlightPlanUtils = class {
1244
+ /**
1245
+ * Processes flight plan data
1246
+ *
1247
+ * Expected format is [header, key1, val1, ... keyN, valN]
1248
+ *
1249
+ * @param decodeResult - results
1250
+ * @param data - original message split by ':'
1251
+ * @returns whether all fields were processed or not
1252
+ */
1253
+ static processFlightPlan(decodeResult, data) {
1254
+ let allKnownFields = parseHeader(decodeResult, data[0]);
1255
+ for (let i = 1; i < data.length; i += 2) {
1256
+ const key = data[i];
1257
+ const value = data[i + 1];
1258
+ switch (key) {
1259
+ case "A":
1260
+ addProcedure(decodeResult, value, "arrival");
1261
+ break;
1262
+ case "AA":
1263
+ addArrivalAirport(decodeResult, value);
1264
+ break;
1265
+ case "AP":
1266
+ addProcedure(decodeResult, value, "approach");
1267
+ break;
1268
+ case "CR":
1269
+ addCompanyRoute(decodeResult, value);
1270
+ break;
1271
+ case "D":
1272
+ addProcedure(decodeResult, value, "departure");
1273
+ break;
1274
+ case "DA":
1275
+ addDepartureAirport(decodeResult, value);
1276
+ break;
1277
+ case "F":
1278
+ addRoute(decodeResult, value);
1279
+ break;
1280
+ case "R":
1281
+ addDepartureRunway(decodeResult, value);
1282
+ break;
1283
+ default:
1284
+ if (allKnownFields) {
1285
+ decodeResult.remaining.text = "";
1286
+ allKnownFields = false;
1287
+ }
1288
+ decodeResult.remaining.text += `:${key}:${value}`;
1289
+ decodeResult.decoder.decodeLevel = "partial";
1290
+ }
1291
+ }
1292
+ return allKnownFields;
1293
+ }
1294
+ };
1295
+ function parseHeader(decodeResult, header) {
1296
+ let allKnownFields = true;
1297
+ const fields = header.split("/");
1298
+ for (let i = 1; i < fields.length - 1; ++i) {
1299
+ if (fields[i].startsWith("FN")) {
1300
+ decodeResult.raw.flight_number = fields[i].substring(2);
1301
+ } else if (fields[i].startsWith("SN")) {
1302
+ decodeResult.raw.serial_number = fields[i].substring(2);
1303
+ } else if (fields[i].startsWith("TS")) {
1304
+ const ts = fields[i].substring(2).split(",");
1305
+ decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(ts[0], ts[1]);
1306
+ } else {
1307
+ decodeResult.remaining.text += "/" + fields[i];
1308
+ allKnownFields = false;
1309
+ }
1310
+ }
1311
+ decodeResult.raw.route_status = fields[fields.length - 1];
1312
+ var text;
1313
+ if (decodeResult.raw.route_status == "RP") {
1314
+ text = "Route Planned";
1315
+ } else if (decodeResult.raw.route_status == "RI") {
1316
+ text = "Route Inactive";
1317
+ } else if (decodeResult.raw.route_status == "RF") {
1318
+ text = "Route Filed";
1319
+ } else {
1320
+ text = decodeResult.raw.route_status;
1321
+ }
1322
+ decodeResult.formatted.items.push({
1323
+ type: "status",
1324
+ code: "ROUTE_STATUS",
1325
+ label: "Route Status",
1326
+ value: text
1327
+ });
1328
+ return allKnownFields;
1329
+ }
1330
+ function addArrivalAirport(decodeResult, value) {
1331
+ decodeResult.raw.arrival_icao = value;
1332
+ decodeResult.formatted.items.push({
1333
+ type: "destination",
1334
+ code: "DST",
1335
+ label: "Destination",
1336
+ value: decodeResult.raw.arrival_icao
1337
+ });
1338
+ }
1339
+ function addDepartureAirport(decodeResult, value) {
1340
+ decodeResult.raw.departure_icao = value;
1341
+ decodeResult.formatted.items.push({
1342
+ type: "origin",
1343
+ code: "ORG",
1344
+ label: "Origin",
1345
+ value: decodeResult.raw.departure_icao
1346
+ });
1347
+ }
1348
+ function addDepartureRunway(decodeResult, value) {
1349
+ decodeResult.raw.runway = value;
1350
+ decodeResult.formatted.items.push({
1351
+ type: "runway",
1352
+ label: "Runway",
1353
+ value: decodeResult.raw.runway
1354
+ });
1355
+ }
1356
+ function addRoute(decodeResult, value) {
1357
+ const route = value.split(".");
1358
+ decodeResult.raw.route = { waypoints: route.map((leg) => RouteUtils.getWaypoint(leg)) };
1359
+ decodeResult.formatted.items.push({
1360
+ type: "aircraft_route",
1361
+ code: "ROUTE",
1362
+ label: "Aircraft Route",
1363
+ value: RouteUtils.routeToString(decodeResult.raw.route)
1364
+ });
1365
+ }
1366
+ function addProcedure(decodeResult, value, type) {
1367
+ if (decodeResult.raw.procedures === void 0) {
1368
+ decodeResult.raw.procedures = [];
1369
+ }
1370
+ const data = value.split(".");
1371
+ let waypoints;
1372
+ if (data.length > 1) {
1373
+ waypoints = data.slice(1).map((leg) => RouteUtils.getWaypoint(leg));
1374
+ }
1375
+ const route = { name: data[0], waypoints };
1376
+ decodeResult.raw.procedures.push({ type, route });
1377
+ const procedureName = type.substring(0, 1).toUpperCase() + type.slice(1);
1378
+ let procedureValue = route.name;
1379
+ decodeResult.formatted.items.push({
1380
+ type: `procedure`,
1381
+ code: "proc",
1382
+ label: `${procedureName} Procedure`,
1383
+ value: RouteUtils.routeToString(route)
1384
+ });
1385
+ }
1386
+ function addCompanyRoute(decodeResult, value) {
1387
+ const segments = value.split(".");
1388
+ const parens_idx = segments[0].indexOf("(");
1389
+ let name;
1390
+ let runway;
1391
+ if (parens_idx === -1) {
1392
+ name = segments[0];
1393
+ } else {
1394
+ name = segments[0].slice(0, parens_idx);
1395
+ runway = segments[0].slice(parens_idx + 1, segments[0].indexOf(")"));
1396
+ }
1397
+ let waypoints;
1398
+ if (segments.length > 1) {
1399
+ waypoints = segments.slice(1).map((leg) => RouteUtils.getWaypoint(leg));
1400
+ }
1401
+ decodeResult.raw.company_route = {
1402
+ name,
1403
+ runway,
1404
+ waypoints
1405
+ };
1406
+ decodeResult.formatted.items.push({
1407
+ type: "company_route",
1408
+ code: "CR",
1409
+ label: "Company Route",
1410
+ value: RouteUtils.routeToString(decodeResult.raw.company_route)
1411
+ });
1412
+ }
1413
+
1414
+ // lib/plugins/Label_H1_FPN.ts
1415
+ var Label_H1_FPN = class extends DecoderPlugin {
1416
+ name = "label-h1-fpn";
1417
+ qualifiers() {
1418
+ return {
1419
+ labels: ["H1"],
1420
+ preambles: ["FPN", "#M1BFPN"]
1421
+ };
1422
+ }
1423
+ decode(message, options = {}) {
1424
+ let decodeResult = this.defaultResult;
1425
+ decodeResult.decoder.name = this.name;
1426
+ decodeResult.formatted.description = "Flight Plan";
1427
+ decodeResult.message = message;
1428
+ const msg = message.text.replace(/\n|\r/g, "");
1429
+ const checksum = msg.slice(-4);
1430
+ const data = msg.slice(0, msg.length - 4).split(":");
1431
+ if (data.length > 1) {
1432
+ const fulllyDecoded = FlightPlanUtils.processFlightPlan(decodeResult, data);
1433
+ addChecksum(decodeResult, checksum);
1434
+ decodeResult.decoded = true;
1435
+ decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
1436
+ } else {
1437
+ if (options?.debug) {
1438
+ console.log(`Decoder: Unknown H1 message: ${message.text}`);
1439
+ }
1440
+ decodeResult.remaining.text = message.text;
1441
+ decodeResult.decoded = false;
1442
+ decodeResult.decoder.decodeLevel = "none";
1443
+ }
1444
+ return decodeResult;
1445
+ }
1446
+ };
1447
+ function addChecksum(decodeResult, value) {
1448
+ decodeResult.raw.checksum = Number("0x" + value);
1449
+ decodeResult.formatted.items.push({
1450
+ type: "message_checksum",
1451
+ code: "CHECKSUM",
1452
+ label: "Message Checksum",
1453
+ value: "0x" + ("0000" + decodeResult.raw.checksum.toString(16)).slice(-4)
1454
+ });
1455
+ }
1456
+
1457
+ // lib/plugins/Label_H1_POS.ts
1458
+ var Label_H1_POS = class extends DecoderPlugin {
1459
+ name = "label-h1-pos";
1460
+ qualifiers() {
1461
+ return {
1462
+ labels: ["H1"],
1463
+ preambles: ["POS", "#M1BPOS"]
1464
+ //TODO - support data before #
1465
+ };
1466
+ }
1467
+ decode(message, options = {}) {
1468
+ let decodeResult = this.defaultResult;
1469
+ decodeResult.decoder.name = this.name;
1470
+ decodeResult.formatted.description = "Position Report";
1471
+ decodeResult.message = message;
1472
+ const checksum = message.text.slice(-4);
1473
+ const parts = message.text.replace("#M1B", "").replace("POS", "").slice(0, -4).split(",");
1474
+ console.log(parts);
1475
+ if (parts.length == 1 && parts[0].startsWith("/RF")) {
1476
+ decodeResult.raw.route_status == "RF";
1477
+ decodeResult.formatted.items.push({
1478
+ type: "status",
1479
+ code: "ROUTE_STATUS",
1480
+ label: "Route Status",
1481
+ value: "Route Filed"
1482
+ });
1483
+ decodeResult.raw.route = { waypoints: parts[0].substring(3, parts[0].length).split(".").map((leg) => RouteUtils.getWaypoint(leg)) };
1484
+ decodeResult.formatted.items.push({
1485
+ type: "aircraft_route",
1486
+ code: "ROUTE",
1487
+ label: "Aircraft Route",
1488
+ value: RouteUtils.routeToString(decodeResult.raw.route)
1489
+ });
1490
+ processChecksum(decodeResult, checksum);
1491
+ decodeResult.decoded = true;
1492
+ decodeResult.decoder.decodeLevel = "full";
1493
+ } else if (parts.length === 10) {
1494
+ decodeResult.remaining.text = "";
1495
+ processPosition(decodeResult, parts[0]);
1496
+ processAlt(decodeResult, parts[3]);
1497
+ processRoute(decodeResult, parts[1], parts[2], parts[4], parts[5], parts[6]);
1498
+ processTemp(decodeResult, parts[7]);
1499
+ processUnknown(decodeResult, parts[8]);
1500
+ processUnknown(decodeResult, parts[9]);
1501
+ processChecksum(decodeResult, checksum);
1502
+ decodeResult.decoded = true;
1503
+ decodeResult.decoder.decodeLevel = "partial";
1504
+ } else if (parts.length === 11) {
1505
+ decodeResult.remaining.text = "";
1506
+ processPosition(decodeResult, parts[0]);
1507
+ processAlt(decodeResult, parts[3]);
1508
+ processRoute(decodeResult, parts[1], parts[2], parts[4], parts[5], parts[6], parts[10]);
1509
+ processTemp(decodeResult, parts[7]);
1510
+ processUnknown(decodeResult, parts[8]);
1511
+ processUnknown(decodeResult, parts[9]);
1512
+ processChecksum(decodeResult, checksum);
1513
+ decodeResult.decoded = true;
1514
+ decodeResult.decoder.decodeLevel = "partial";
1515
+ } else if (parts.length === 14) {
1516
+ decodeResult.remaining.text = "";
1517
+ processPosition(decodeResult, parts[0]);
1518
+ processAlt(decodeResult, parts[3]);
1519
+ processRoute(decodeResult, parts[1], parts[2], parts[4], parts[5], parts[6]);
1520
+ processTemp(decodeResult, parts[7]);
1521
+ processUnknown(decodeResult, parts[8]);
1522
+ processUnknown(decodeResult, parts[9]);
1523
+ processGndspd(decodeResult, parts[10]);
1524
+ processUnknown(decodeResult, parts[11]);
1525
+ processUnknown(decodeResult, parts[12]);
1526
+ processUnknown(decodeResult, parts[13]);
1527
+ processChecksum(decodeResult, checksum);
1528
+ decodeResult.decoded = true;
1529
+ decodeResult.decoder.decodeLevel = "partial";
1530
+ } else if (parts.length === 32) {
1531
+ decodeResult.remaining.text = "";
1532
+ processPosition(decodeResult, parts[0]);
1533
+ processRunway(decodeResult, parts[1]);
1534
+ const time = parts[2];
1535
+ processUnknown(decodeResult, parts[3]);
1536
+ const past = parts[4];
1537
+ processUnknown(decodeResult, parts[5]);
1538
+ const eta = parts[6];
1539
+ const next = parts[7];
1540
+ processUnknown(decodeResult, parts.slice(8, 14).join(","));
1541
+ processUnknown(decodeResult, parts[16]);
1542
+ processUnknown(decodeResult, parts[17]);
1543
+ processUnknown(decodeResult, parts[18]);
1544
+ processGndspd(decodeResult, parts[19]);
1545
+ processUnknown(decodeResult, parts[20]);
1546
+ processUnknown(decodeResult, parts[21]);
1547
+ processAlt(decodeResult, parts[22]);
1548
+ processUnknown(decodeResult, parts.slice(23, 31).join(","));
1549
+ const allProcessed = FlightPlanUtils.processFlightPlan(decodeResult, (parts[31] + checksum).split(":"));
1550
+ processRoute(decodeResult, past, time, next, eta, "?");
1551
+ decodeResult.decoded = true;
1552
+ decodeResult.decoder.decodeLevel = "partial";
1553
+ } else {
1554
+ if (options.debug) {
1555
+ console.log(`Decoder: Unknown H1 message: ${message.text}`);
1556
+ }
1557
+ decodeResult.remaining.text = message.text;
1558
+ decodeResult.decoded = false;
1559
+ decodeResult.decoder.decodeLevel = "none";
1560
+ }
1561
+ return decodeResult;
1562
+ }
1563
+ };
1564
+ function processUnknown(decodeResult, value) {
1565
+ decodeResult.remaining.text += "," + value;
1566
+ }
1567
+ function processPosition(decodeResult, value) {
1568
+ const position = CoordinateUtils.decodeStringCoordinates(value);
1569
+ decodeResult.raw.latitude_direction = position.latitudeDirection;
1570
+ decodeResult.raw.latitude = Math.abs(position.latitude);
1571
+ decodeResult.raw.longitude_direction = position.longitudeDirection;
1572
+ decodeResult.raw.longitude = Math.abs(position.longitude);
1573
+ decodeResult.formatted.items.push({
1574
+ type: "aircraft_position",
1575
+ code: "POS",
1576
+ label: "Aircraft Position",
1577
+ value: CoordinateUtils.coordinateString(position)
1578
+ });
1579
+ }
1580
+ function processAlt(decodeResult, value) {
1581
+ decodeResult.raw.altitude = Number(value) * 100;
1582
+ decodeResult.formatted.items.push({
1583
+ type: "altitude",
1584
+ code: "ALT",
1585
+ label: "Altitude",
1586
+ value: `${decodeResult.raw.altitude} feet`
1587
+ });
1588
+ }
1589
+ function processTemp(decodeResult, value) {
1590
+ decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
1591
+ decodeResult.formatted.items.push({
1592
+ type: "outside_air_temperature",
1593
+ code: "OATEMP",
1594
+ label: "Outside Air Temperature (C)",
1595
+ value: `${decodeResult.raw.outside_air_temperature}`
1596
+ });
1597
+ }
1598
+ function processRunway(decodeResult, value) {
1599
+ decodeResult.raw.runway = value.replace("RW", "");
1600
+ decodeResult.formatted.items.push({
1601
+ type: "runway",
1602
+ label: "Runway",
1603
+ value: decodeResult.raw.runway
1604
+ });
1605
+ }
1606
+ function processGndspd(decodeResult, value) {
1607
+ decodeResult.raw.groundspeed = Number(value);
1608
+ decodeResult.formatted.items.push({
1609
+ type: "aircraft_groundspeed",
1610
+ code: "GSPD",
1611
+ label: "Aircraft Groundspeed",
1612
+ value: `${decodeResult.raw.groundspeed}`
1613
+ });
1614
+ }
1615
+ function processRoute(decodeResult, last, time, next, eta, then, date) {
1616
+ let waypoints;
1617
+ waypoints = date === void 0 ? [
1618
+ { name: last || "?,", time: DateTimeUtils.convertHHMMSSToTod(time), timeFormat: "tod" },
1619
+ { name: next || "?", time: DateTimeUtils.convertHHMMSSToTod(eta), timeFormat: "tod" },
1620
+ { name: then || "?" }
1621
+ ] : [
1622
+ { name: last || "?,", time: DateTimeUtils.convertDateTimeToEpoch(time, date), timeFormat: "epoch" },
1623
+ { name: next || "?", time: DateTimeUtils.convertDateTimeToEpoch(eta, date), timeFormat: "epoch" },
1624
+ { name: then || "?" }
1625
+ ];
1626
+ decodeResult.raw.route = { waypoints };
1627
+ decodeResult.formatted.items.push({
1628
+ type: "aircraft_route",
1629
+ code: "ROUTE",
1630
+ label: "Aircraft Route",
1631
+ value: RouteUtils.routeToString(decodeResult.raw.route)
1632
+ });
1633
+ }
1634
+ function processChecksum(decodeResult, value) {
1635
+ decodeResult.raw.checksum = Number("0x" + value);
1636
+ decodeResult.formatted.items.push({
1637
+ type: "message_checksum",
1638
+ code: "CHECKSUM",
1639
+ label: "Message Checksum",
1640
+ value: "0x" + ("0000" + decodeResult.raw.checksum.toString(16)).slice(-4)
1641
+ });
1642
+ }
1643
+
1644
+ // lib/plugins/Label_SQ.ts
1645
+ var Label_SQ = class extends DecoderPlugin {
1646
+ name = "label-sq";
1647
+ qualifiers() {
1648
+ return {
1649
+ labels: ["SQ"]
1650
+ };
1651
+ }
1652
+ decode(message, options = {}) {
1653
+ const decodeResult = this.defaultResult;
1654
+ decodeResult.decoder.name = this.name;
1655
+ decodeResult.raw.preamble = message.text.substring(0, 4);
1656
+ decodeResult.raw.version = message.text.substring(1, 2);
1657
+ decodeResult.raw.network = message.text.substring(3, 4);
1658
+ if (decodeResult.raw.version === "2") {
1659
+ const regex = /0(\d)X(?<org>\w)(?<iata>\w\w\w)(?<icao>\w\w\w\w)(?<station>\d)(?<lat>\d+)(?<latd>[NS])(?<lng>\d+)(?<lngd>[EW])V(?<vfreq>\d+)\/.*/;
1660
+ const result = message.text.match(regex);
1661
+ if (result && result.length >= 8) {
1662
+ decodeResult.raw.groundStation = {
1663
+ number: result.groups.station,
1664
+ iataCode: result.groups.iata,
1665
+ icaoCode: result.groups.icao,
1666
+ coordinates: {
1667
+ latitude: Number(result.groups.lat) / 100 * (result.groups.latd === "S" ? -1 : 1),
1668
+ longitude: Number(result.groups.lng) / 100 * (result.groups.lngd === "W" ? -1 : 1)
1669
+ }
1670
+ };
1671
+ decodeResult.raw.vdlFrequency = result.groups.vfreq / 1e3;
1672
+ }
1673
+ }
1674
+ decodeResult.formatted.description = "Ground Station Squitter";
1675
+ var formattedNetwork = "Unknown";
1676
+ if (decodeResult.raw.network == "A") {
1677
+ formattedNetwork = "ARINC";
1678
+ } else if (decodeResult.raw.network == "S") {
1679
+ formattedNetwork = "SITA";
1680
+ }
1681
+ decodeResult.formatted.items = [
1682
+ {
1683
+ type: "network",
1684
+ label: "Network",
1685
+ value: formattedNetwork
1686
+ },
1687
+ {
1688
+ type: "version",
1689
+ label: "Version",
1690
+ value: decodeResult.raw.version
1691
+ }
1692
+ ];
1693
+ if (decodeResult.raw.groundStation) {
1694
+ if (decodeResult.raw.groundStation.icaoCode && decodeResult.raw.groundStation.number) {
1695
+ decodeResult.formatted.items.push({
1696
+ type: "ground_station",
1697
+ label: "Ground Station",
1698
+ value: `${decodeResult.raw.groundStation.icaoCode}${decodeResult.raw.groundStation.number}`
1699
+ });
1700
+ }
1701
+ if (decodeResult.raw.groundStation.iataCode) {
1702
+ decodeResult.formatted.items.push({
1703
+ type: "iataCode",
1704
+ label: "IATA",
1705
+ value: decodeResult.raw.groundStation.iataCode
1706
+ });
1707
+ }
1708
+ if (decodeResult.raw.groundStation.icaoCode) {
1709
+ decodeResult.formatted.items.push({
1710
+ type: "icaoCode",
1711
+ label: "ICAO",
1712
+ value: decodeResult.raw.groundStation.icaoCode
1713
+ });
1714
+ }
1715
+ if (decodeResult.raw.groundStation.coordinates.latitude) {
1716
+ decodeResult.formatted.items.push({
1717
+ type: "coordinates",
1718
+ label: "Ground Station Location",
1719
+ value: `${decodeResult.raw.groundStation.coordinates.latitude}, ${decodeResult.raw.groundStation.coordinates.longitude}`
1720
+ });
1721
+ }
1722
+ if (decodeResult.raw.groundStation.airport) {
1723
+ decodeResult.formatted.items.push({
1724
+ type: "airport",
1725
+ label: "Airport",
1726
+ value: `${decodeResult.raw.groundStation.airport.name} (${decodeResult.raw.groundStation.airport.icao}) in ${decodeResult.raw.groundStation.airport.location}`
1727
+ });
1728
+ }
1729
+ }
1730
+ if (decodeResult.raw.vdlFrequency) {
1731
+ decodeResult.formatted.items.push({
1732
+ type: "vdlFrequency",
1733
+ label: "VDL Frequency",
1734
+ value: `${decodeResult.raw.vdlFrequency} MHz`
1735
+ });
1736
+ }
1737
+ decodeResult.decoded = true;
1738
+ decodeResult.decoder.decodeLevel = "full";
1739
+ return decodeResult;
1740
+ }
1741
+ };
1742
+
1743
+ // lib/plugins/Label_QR.ts
1744
+ var Label_QR = class extends DecoderPlugin {
1745
+ name = "label-qr";
1746
+ qualifiers() {
1747
+ return {
1748
+ labels: ["QR"]
1749
+ };
1750
+ }
1751
+ decode(message, options = {}) {
1752
+ const decodeResult = this.defaultResult;
1753
+ decodeResult.decoder.name = this.name;
1754
+ decodeResult.raw.origin = message.text.substring(0, 4);
1755
+ decodeResult.raw.destination = message.text.substring(4, 8);
1756
+ decodeResult.raw.wheels_on = message.text.substring(8, 12);
1757
+ decodeResult.remaining.text = message.text.substring(12);
1758
+ decodeResult.formatted.description = "ON Report";
1759
+ decodeResult.formatted.items = [
1760
+ {
1761
+ type: "origin",
1762
+ code: "ORG",
1763
+ label: "Origin",
1764
+ value: decodeResult.raw.origin
1765
+ },
1766
+ {
1767
+ type: "destination",
1768
+ code: "DST",
1769
+ label: "Destination",
1770
+ value: decodeResult.raw.destination
1771
+ },
1772
+ {
1773
+ type: "wheels_on",
1774
+ code: "WON",
1775
+ label: "Wheels ON",
1776
+ value: decodeResult.raw.wheels_on
1777
+ }
1778
+ ];
1779
+ decodeResult.decoded = true;
1780
+ if (decodeResult.remaining.text === "")
1781
+ decodeResult.decoder.decodeLevel = "full";
1782
+ else
1783
+ decodeResult.decoder.decodeLevel = "partial";
1784
+ return decodeResult;
1785
+ }
1786
+ };
1787
+
1788
+ // lib/plugins/Label_QP.ts
1789
+ var Label_QP = class extends DecoderPlugin {
1790
+ name = "label-qp";
1791
+ qualifiers() {
1792
+ return {
1793
+ labels: ["QP"]
1794
+ };
1795
+ }
1796
+ decode(message, options = {}) {
1797
+ const decodeResult = this.defaultResult;
1798
+ decodeResult.decoder.name = this.name;
1799
+ decodeResult.raw.origin = message.text.substring(0, 4);
1800
+ decodeResult.raw.destination = message.text.substring(4, 8);
1801
+ decodeResult.raw.gate_out = message.text.substring(8, 12);
1802
+ decodeResult.remaining.text = message.text.substring(12);
1803
+ decodeResult.formatted.description = "OUT Report";
1804
+ decodeResult.formatted.items = [
1805
+ {
1806
+ type: "origin",
1807
+ code: "ORG",
1808
+ label: "Origin",
1809
+ value: decodeResult.raw.origin
1810
+ },
1811
+ {
1812
+ type: "destination",
1813
+ code: "DST",
1814
+ label: "Destination",
1815
+ value: decodeResult.raw.destination
1816
+ },
1817
+ {
1818
+ type: "gate_out",
1819
+ code: "GOUT",
1820
+ label: "Gate OUT",
1821
+ value: decodeResult.raw.gate_out
1822
+ }
1823
+ ];
1824
+ decodeResult.decoded = true;
1825
+ if (decodeResult.remaining.text === "")
1826
+ decodeResult.decoder.decodeLevel = "full";
1827
+ else
1828
+ decodeResult.decoder.decodeLevel = "partial";
1829
+ return decodeResult;
1830
+ }
1831
+ };
1832
+
1833
+ // lib/plugins/Label_QS.ts
1834
+ var Label_QS = class extends DecoderPlugin {
1835
+ name = "label-qs";
1836
+ qualifiers() {
1837
+ return {
1838
+ labels: ["QS"]
1839
+ };
1840
+ }
1841
+ decode(message, options = {}) {
1842
+ const decodeResult = this.defaultResult;
1843
+ decodeResult.decoder.name = this.name;
1844
+ decodeResult.raw.origin = message.text.substring(0, 4);
1845
+ decodeResult.raw.destination = message.text.substring(4, 8);
1846
+ decodeResult.raw.gate_in = message.text.substring(8, 12);
1847
+ decodeResult.remaining.text = message.text.substring(12);
1848
+ decodeResult.formatted.description = "IN Report";
1849
+ decodeResult.formatted.items = [
1850
+ {
1851
+ type: "origin",
1852
+ code: "ORG",
1853
+ label: "Origin",
1854
+ value: decodeResult.raw.origin
1855
+ },
1856
+ {
1857
+ type: "destination",
1858
+ code: "DST",
1859
+ label: "Destination",
1860
+ value: decodeResult.raw.destination
1861
+ },
1862
+ {
1863
+ type: "gate_in",
1864
+ code: "GIN",
1865
+ label: "Gate IN",
1866
+ value: decodeResult.raw.gate_in
1867
+ }
1868
+ ];
1869
+ decodeResult.decoded = true;
1870
+ if (decodeResult.remaining.text === "")
1871
+ decodeResult.decoder.decodeLevel = "full";
1872
+ else
1873
+ decodeResult.decoder.decodeLevel = "partial";
1874
+ return decodeResult;
1875
+ }
1876
+ };
1877
+
1878
+ // lib/plugins/Label_QQ.ts
1879
+ var Label_QQ = class extends DecoderPlugin {
1880
+ name = "label-qq";
1881
+ qualifiers() {
1882
+ return {
1883
+ labels: ["QQ"]
1884
+ };
1885
+ }
1886
+ decode(message, options = {}) {
1887
+ const decodeResult = this.defaultResult;
1888
+ decodeResult.decoder.name = this.name;
1889
+ decodeResult.raw.origin = message.text.substring(0, 4);
1890
+ decodeResult.raw.destination = message.text.substring(4, 8);
1891
+ decodeResult.raw.wheels_off = message.text.substring(8, 12);
1892
+ decodeResult.remaining.text = message.text.substring(12);
1893
+ decodeResult.formatted.description = "OFF Report";
1894
+ decodeResult.formatted.items = [
1895
+ {
1896
+ type: "origin",
1897
+ code: "ORG",
1898
+ label: "Origin",
1899
+ value: decodeResult.raw.origin
1900
+ },
1901
+ {
1902
+ type: "destination",
1903
+ code: "DST",
1904
+ label: "Destination",
1905
+ value: decodeResult.raw.destination
1906
+ },
1907
+ {
1908
+ type: "wheels_off",
1909
+ code: "WOFF",
1910
+ label: "Wheels OFF",
1911
+ value: decodeResult.raw.wheels_off
1912
+ }
1913
+ ];
1914
+ decodeResult.decoded = true;
1915
+ if (decodeResult.remaining.text === "")
1916
+ decodeResult.decoder.decodeLevel = "full";
1917
+ else
1918
+ decodeResult.decoder.decodeLevel = "partial";
1919
+ return decodeResult;
1920
+ }
1921
+ };
1922
+
1923
+ // lib/utils/miam.ts
1924
+ import * as Base85 from "base85";
1925
+ import * as Zlib from "zlib";
1926
+ var MIAMCoreV1CRCLength = 4;
1927
+ var MIAMCoreV2CRCLength = 2;
1928
+ var MIAMCoreUtils = class {
1929
+ static AppTypeToAppIdLenTable = {
1930
+ 1: {
1931
+ [0 /* ACARS2Char */]: 2,
1932
+ [1 /* ACARS4Char */]: 4,
1933
+ [2 /* ACARS6Char */]: 6,
1934
+ [3 /* NonACARS6Char */]: 6
1935
+ },
1936
+ 2: {
1937
+ [0 /* ACARS2Char */]: 2,
1938
+ [1 /* ACARS4Char */]: 4,
1939
+ [2 /* ACARS6Char */]: 6,
1940
+ [3 /* NonACARS6Char */]: 6
1941
+ }
1942
+ };
1943
+ static FidHandlerTable = {
1944
+ ["T" /* SingleTransfer */]: (txt) => {
1945
+ if (txt.length < 3) {
1946
+ return {
1947
+ decoded: false,
1948
+ error: "Raw MIAM message too short (" + txt.length + " < 3) "
1949
+ };
1950
+ }
1951
+ let bpad = txt[0];
1952
+ if ("0123-.".indexOf(bpad) === -1) {
1953
+ return {
1954
+ decoded: false,
1955
+ error: "Invalid body padding value: '" + bpad + "'"
1956
+ };
1957
+ }
1958
+ if ("0123".indexOf(txt[1]) === -1) {
1959
+ return {
1960
+ decoded: false,
1961
+ error: "Invalid header padding value: '" + txt[1] + "'"
1962
+ };
1963
+ }
1964
+ const hpad = parseInt(txt[1]);
1965
+ const delimIdx = txt.indexOf("|");
1966
+ if (delimIdx === -1) {
1967
+ return {
1968
+ decoded: false,
1969
+ error: "Raw MIAM message missing header-body delimiter"
1970
+ };
1971
+ }
1972
+ const rawHdr = txt.substring(2, delimIdx);
1973
+ if (rawHdr.length === 0) {
1974
+ return {
1975
+ decoded: false,
1976
+ error: "Empty MIAM message header"
1977
+ };
1978
+ }
1979
+ let hdr = Base85.decode("<~" + rawHdr + "~>", "ascii85");
1980
+ if (!hdr || hdr.length < hpad) {
1981
+ return {
1982
+ decoded: false,
1983
+ error: "Ascii85 decode failed for MIAM message header"
1984
+ };
1985
+ }
1986
+ let body = void 0;
1987
+ const rawBody = txt.substring(delimIdx + 1);
1988
+ if (rawBody.length > 0) {
1989
+ if ("0123".indexOf(bpad) >= 0) {
1990
+ const bpadValue = parseInt(bpad);
1991
+ body = Base85.decode("<~" + rawBody + "~>", "ascii85") || void 0;
1992
+ if (body && body.length >= bpadValue) {
1993
+ body = body.subarray(0, body.length - bpadValue);
1994
+ }
1995
+ } else if (bpad === "-") {
1996
+ body = Buffer.from(rawBody);
1997
+ }
1998
+ }
1999
+ hdr = hdr.subarray(0, hdr.length - hpad);
2000
+ const version = hdr.readUInt8(0) & 15;
2001
+ const pduType = hdr.readUInt8(0) >> 4 & 15;
2002
+ const versionPduHandler = this.VersionPduHandlerTable[version][pduType];
2003
+ if (versionPduHandler === void 0) {
2004
+ return {
2005
+ decoded: false,
2006
+ error: "Invalid version and PDU type combination: v=" + version + ", pdu=" + pduType
2007
+ };
2008
+ }
2009
+ return versionPduHandler(hdr, body);
2010
+ },
2011
+ ["F" /* FileTransferRequest */]: void 0,
2012
+ ["K" /* FileTransferAccept */]: void 0,
2013
+ ["S" /* FileSegment */]: void 0,
2014
+ ["A" /* FileTransferAbort */]: void 0,
2015
+ ["Y" /* XOFFIndication */]: void 0,
2016
+ ["X" /* XONIndication */]: void 0
2017
+ };
2018
+ static arincCrc16(buf, seed) {
2019
+ const crctable = [
2020
+ 0,
2021
+ 4129,
2022
+ 8258,
2023
+ 12387,
2024
+ 16516,
2025
+ 20645,
2026
+ 24774,
2027
+ 28903,
2028
+ 33032,
2029
+ 37161,
2030
+ 41290,
2031
+ 45419,
2032
+ 49548,
2033
+ 53677,
2034
+ 57806,
2035
+ 61935,
2036
+ 4657,
2037
+ 528,
2038
+ 12915,
2039
+ 8786,
2040
+ 21173,
2041
+ 17044,
2042
+ 29431,
2043
+ 25302,
2044
+ 37689,
2045
+ 33560,
2046
+ 45947,
2047
+ 41818,
2048
+ 54205,
2049
+ 50076,
2050
+ 62463,
2051
+ 58334,
2052
+ 9314,
2053
+ 13379,
2054
+ 1056,
2055
+ 5121,
2056
+ 25830,
2057
+ 29895,
2058
+ 17572,
2059
+ 21637,
2060
+ 42346,
2061
+ 46411,
2062
+ 34088,
2063
+ 38153,
2064
+ 58862,
2065
+ 62927,
2066
+ 50604,
2067
+ 54669,
2068
+ 13907,
2069
+ 9842,
2070
+ 5649,
2071
+ 1584,
2072
+ 30423,
2073
+ 26358,
2074
+ 22165,
2075
+ 18100,
2076
+ 46939,
2077
+ 42874,
2078
+ 38681,
2079
+ 34616,
2080
+ 63455,
2081
+ 59390,
2082
+ 55197,
2083
+ 51132,
2084
+ 18628,
2085
+ 22757,
2086
+ 26758,
2087
+ 30887,
2088
+ 2112,
2089
+ 6241,
2090
+ 10242,
2091
+ 14371,
2092
+ 51660,
2093
+ 55789,
2094
+ 59790,
2095
+ 63919,
2096
+ 35144,
2097
+ 39273,
2098
+ 43274,
2099
+ 47403,
2100
+ 23285,
2101
+ 19156,
2102
+ 31415,
2103
+ 27286,
2104
+ 6769,
2105
+ 2640,
2106
+ 14899,
2107
+ 10770,
2108
+ 56317,
2109
+ 52188,
2110
+ 64447,
2111
+ 60318,
2112
+ 39801,
2113
+ 35672,
2114
+ 47931,
2115
+ 43802,
2116
+ 27814,
2117
+ 31879,
2118
+ 19684,
2119
+ 23749,
2120
+ 11298,
2121
+ 15363,
2122
+ 3168,
2123
+ 7233,
2124
+ 60846,
2125
+ 64911,
2126
+ 52716,
2127
+ 56781,
2128
+ 44330,
2129
+ 48395,
2130
+ 36200,
2131
+ 40265,
2132
+ 32407,
2133
+ 28342,
2134
+ 24277,
2135
+ 20212,
2136
+ 15891,
2137
+ 11826,
2138
+ 7761,
2139
+ 3696,
2140
+ 65439,
2141
+ 61374,
2142
+ 57309,
2143
+ 53244,
2144
+ 48923,
2145
+ 44858,
2146
+ 40793,
2147
+ 36728,
2148
+ 37256,
2149
+ 33193,
2150
+ 45514,
2151
+ 41451,
2152
+ 53516,
2153
+ 49453,
2154
+ 61774,
2155
+ 57711,
2156
+ 4224,
2157
+ 161,
2158
+ 12482,
2159
+ 8419,
2160
+ 20484,
2161
+ 16421,
2162
+ 28742,
2163
+ 24679,
2164
+ 33721,
2165
+ 37784,
2166
+ 41979,
2167
+ 46042,
2168
+ 49981,
2169
+ 54044,
2170
+ 58239,
2171
+ 62302,
2172
+ 689,
2173
+ 4752,
2174
+ 8947,
2175
+ 13010,
2176
+ 16949,
2177
+ 21012,
2178
+ 25207,
2179
+ 29270,
2180
+ 46570,
2181
+ 42443,
2182
+ 38312,
2183
+ 34185,
2184
+ 62830,
2185
+ 58703,
2186
+ 54572,
2187
+ 50445,
2188
+ 13538,
2189
+ 9411,
2190
+ 5280,
2191
+ 1153,
2192
+ 29798,
2193
+ 25671,
2194
+ 21540,
2195
+ 17413,
2196
+ 42971,
2197
+ 47098,
2198
+ 34713,
2199
+ 38840,
2200
+ 59231,
2201
+ 63358,
2202
+ 50973,
2203
+ 55100,
2204
+ 9939,
2205
+ 14066,
2206
+ 1681,
2207
+ 5808,
2208
+ 26199,
2209
+ 30326,
2210
+ 17941,
2211
+ 22068,
2212
+ 55628,
2213
+ 51565,
2214
+ 63758,
2215
+ 59695,
2216
+ 39368,
2217
+ 35305,
2218
+ 47498,
2219
+ 43435,
2220
+ 22596,
2221
+ 18533,
2222
+ 30726,
2223
+ 26663,
2224
+ 6336,
2225
+ 2273,
2226
+ 14466,
2227
+ 10403,
2228
+ 52093,
2229
+ 56156,
2230
+ 60223,
2231
+ 64286,
2232
+ 35833,
2233
+ 39896,
2234
+ 43963,
2235
+ 48026,
2236
+ 19061,
2237
+ 23124,
2238
+ 27191,
2239
+ 31254,
2240
+ 2801,
2241
+ 6864,
2242
+ 10931,
2243
+ 14994,
2244
+ 64814,
2245
+ 60687,
2246
+ 56684,
2247
+ 52557,
2248
+ 48554,
2249
+ 44427,
2250
+ 40424,
2251
+ 36297,
2252
+ 31782,
2253
+ 27655,
2254
+ 23652,
2255
+ 19525,
2256
+ 15522,
2257
+ 11395,
2258
+ 7392,
2259
+ 3265,
2260
+ 61215,
2261
+ 65342,
2262
+ 53085,
2263
+ 57212,
2264
+ 44955,
2265
+ 49082,
2266
+ 36825,
2267
+ 40952,
2268
+ 28183,
2269
+ 32310,
2270
+ 20053,
2271
+ 24180,
2272
+ 11923,
2273
+ 16050,
2274
+ 3793,
2275
+ 7920
2276
+ ];
2277
+ let crc = (seed || 0) & 65535;
2278
+ for (let i = 0; i < buf.length; i++) {
2279
+ crc = (crc << 8 >>> 0 ^ crctable[(crc >>> 8 ^ buf.readUInt8(i)) >>> 0 & 255]) >>> 0;
2280
+ }
2281
+ return crc & 65535;
2282
+ }
2283
+ static arinc665Crc32(buf, seed) {
2284
+ const crctable = [
2285
+ 0,
2286
+ 79764919,
2287
+ 159529838,
2288
+ 222504665,
2289
+ 319059676,
2290
+ 398814059,
2291
+ 445009330,
2292
+ 507990021,
2293
+ 638119352,
2294
+ 583659535,
2295
+ 797628118,
2296
+ 726387553,
2297
+ 890018660,
2298
+ 835552979,
2299
+ 1015980042,
2300
+ 944750013,
2301
+ 1276238704,
2302
+ 1221641927,
2303
+ 1167319070,
2304
+ 1095957929,
2305
+ 1595256236,
2306
+ 1540665371,
2307
+ 1452775106,
2308
+ 1381403509,
2309
+ 1780037320,
2310
+ 1859660671,
2311
+ 1671105958,
2312
+ 1733955601,
2313
+ 2031960084,
2314
+ 2111593891,
2315
+ 1889500026,
2316
+ 1952343757,
2317
+ 2552477408,
2318
+ 2632100695,
2319
+ 2443283854,
2320
+ 2506133561,
2321
+ 2334638140,
2322
+ 2414271883,
2323
+ 2191915858,
2324
+ 2254759653,
2325
+ 3190512472,
2326
+ 3135915759,
2327
+ 3081330742,
2328
+ 3009969537,
2329
+ 2905550212,
2330
+ 2850959411,
2331
+ 2762807018,
2332
+ 2691435357,
2333
+ 3560074640,
2334
+ 3505614887,
2335
+ 3719321342,
2336
+ 3648080713,
2337
+ 3342211916,
2338
+ 3287746299,
2339
+ 3467911202,
2340
+ 3396681109,
2341
+ 4063920168,
2342
+ 4143685023,
2343
+ 4223187782,
2344
+ 4286162673,
2345
+ 3779000052,
2346
+ 3858754371,
2347
+ 3904687514,
2348
+ 3967668269,
2349
+ 881225847,
2350
+ 809987520,
2351
+ 1023691545,
2352
+ 969234094,
2353
+ 662832811,
2354
+ 591600412,
2355
+ 771767749,
2356
+ 717299826,
2357
+ 311336399,
2358
+ 374308984,
2359
+ 453813921,
2360
+ 533576470,
2361
+ 25881363,
2362
+ 88864420,
2363
+ 134795389,
2364
+ 214552010,
2365
+ 2023205639,
2366
+ 2086057648,
2367
+ 1897238633,
2368
+ 1976864222,
2369
+ 1804852699,
2370
+ 1867694188,
2371
+ 1645340341,
2372
+ 1724971778,
2373
+ 1587496639,
2374
+ 1516133128,
2375
+ 1461550545,
2376
+ 1406951526,
2377
+ 1302016099,
2378
+ 1230646740,
2379
+ 1142491917,
2380
+ 1087903418,
2381
+ 2896545431,
2382
+ 2825181984,
2383
+ 2770861561,
2384
+ 2716262478,
2385
+ 3215044683,
2386
+ 3143675388,
2387
+ 3055782693,
2388
+ 3001194130,
2389
+ 2326604591,
2390
+ 2389456536,
2391
+ 2200899649,
2392
+ 2280525302,
2393
+ 2578013683,
2394
+ 2640855108,
2395
+ 2418763421,
2396
+ 2498394922,
2397
+ 3769900519,
2398
+ 3832873040,
2399
+ 3912640137,
2400
+ 3992402750,
2401
+ 4088425275,
2402
+ 4151408268,
2403
+ 4197601365,
2404
+ 4277358050,
2405
+ 3334271071,
2406
+ 3263032808,
2407
+ 3476998961,
2408
+ 3422541446,
2409
+ 3585640067,
2410
+ 3514407732,
2411
+ 3694837229,
2412
+ 3640369242,
2413
+ 1762451694,
2414
+ 1842216281,
2415
+ 1619975040,
2416
+ 1682949687,
2417
+ 2047383090,
2418
+ 2127137669,
2419
+ 1938468188,
2420
+ 2001449195,
2421
+ 1325665622,
2422
+ 1271206113,
2423
+ 1183200824,
2424
+ 1111960463,
2425
+ 1543535498,
2426
+ 1489069629,
2427
+ 1434599652,
2428
+ 1363369299,
2429
+ 622672798,
2430
+ 568075817,
2431
+ 748617968,
2432
+ 677256519,
2433
+ 907627842,
2434
+ 853037301,
2435
+ 1067152940,
2436
+ 995781531,
2437
+ 51762726,
2438
+ 131386257,
2439
+ 177728840,
2440
+ 240578815,
2441
+ 269590778,
2442
+ 349224269,
2443
+ 429104020,
2444
+ 491947555,
2445
+ 4046411278,
2446
+ 4126034873,
2447
+ 4172115296,
2448
+ 4234965207,
2449
+ 3794477266,
2450
+ 3874110821,
2451
+ 3953728444,
2452
+ 4016571915,
2453
+ 3609705398,
2454
+ 3555108353,
2455
+ 3735388376,
2456
+ 3664026991,
2457
+ 3290680682,
2458
+ 3236090077,
2459
+ 3449943556,
2460
+ 3378572211,
2461
+ 3174993278,
2462
+ 3120533705,
2463
+ 3032266256,
2464
+ 2961025959,
2465
+ 2923101090,
2466
+ 2868635157,
2467
+ 2813903052,
2468
+ 2742672763,
2469
+ 2604032198,
2470
+ 2683796849,
2471
+ 2461293480,
2472
+ 2524268063,
2473
+ 2284983834,
2474
+ 2364738477,
2475
+ 2175806836,
2476
+ 2238787779,
2477
+ 1569362073,
2478
+ 1498123566,
2479
+ 1409854455,
2480
+ 1355396672,
2481
+ 1317987909,
2482
+ 1246755826,
2483
+ 1192025387,
2484
+ 1137557660,
2485
+ 2072149281,
2486
+ 2135122070,
2487
+ 1912620623,
2488
+ 1992383480,
2489
+ 1753615357,
2490
+ 1816598090,
2491
+ 1627664531,
2492
+ 1707420964,
2493
+ 295390185,
2494
+ 358241886,
2495
+ 404320391,
2496
+ 483945776,
2497
+ 43990325,
2498
+ 106832002,
2499
+ 186451547,
2500
+ 266083308,
2501
+ 932423249,
2502
+ 861060070,
2503
+ 1041341759,
2504
+ 986742920,
2505
+ 613929101,
2506
+ 542559546,
2507
+ 756411363,
2508
+ 701822548,
2509
+ 3316196985,
2510
+ 3244833742,
2511
+ 3425377559,
2512
+ 3370778784,
2513
+ 3601682597,
2514
+ 3530312978,
2515
+ 3744426955,
2516
+ 3689838204,
2517
+ 3819031489,
2518
+ 3881883254,
2519
+ 3928223919,
2520
+ 4007849240,
2521
+ 4037393693,
2522
+ 4100235434,
2523
+ 4180117107,
2524
+ 4259748804,
2525
+ 2310601993,
2526
+ 2373574846,
2527
+ 2151335527,
2528
+ 2231098320,
2529
+ 2596047829,
2530
+ 2659030626,
2531
+ 2470359227,
2532
+ 2550115596,
2533
+ 2947551409,
2534
+ 2876312838,
2535
+ 2788305887,
2536
+ 2733848168,
2537
+ 3165939309,
2538
+ 3094707162,
2539
+ 3040238851,
2540
+ 2985771188
2541
+ ];
2542
+ let crc = seed || 0;
2543
+ for (let i = 0; i < buf.length; i++) {
2544
+ crc = (crc << 8 >>> 0 ^ crctable[(crc >>> 24 ^ buf.readUInt8(i)) >>> 0]) >>> 0;
2545
+ }
2546
+ return crc;
2547
+ }
2548
+ static parse(txt) {
2549
+ const fidType = txt[0];
2550
+ const handler = this.FidHandlerTable[fidType];
2551
+ if (handler === void 0) {
2552
+ return {
2553
+ decoded: false,
2554
+ error: "Unsupported FID type: " + fidType
2555
+ };
2556
+ }
2557
+ return handler(txt.substring(1));
2558
+ }
2559
+ static corePduDataHandler(version, minHdrSize, crcLen, hdr, body) {
2560
+ if (hdr.length < minHdrSize) {
2561
+ return {
2562
+ decoded: false,
2563
+ error: "v" + version + " header size too short; expected >= " + minHdrSize + ", got " + hdr.length
2564
+ };
2565
+ }
2566
+ let pduSize = void 0;
2567
+ let pduCompression = 0;
2568
+ let pduEncoding = 0;
2569
+ let pduAppType = 0;
2570
+ let pduAppId = "";
2571
+ let pduCrc = 0;
2572
+ let pduData = void 0;
2573
+ let pduCrcIsOk = false;
2574
+ let pduIsComplete = true;
2575
+ let pduErrors = [];
2576
+ let tail = void 0;
2577
+ let msgNum = 0;
2578
+ let ackOptions = 0;
2579
+ if (version === 1) {
2580
+ pduSize = hdr.readUInt8(1) << 16 | hdr.readUInt8(2) << 8 | hdr.readUInt8(3);
2581
+ const msgSize = hdr.length + (body === void 0 ? 0 : body.length);
2582
+ if (pduSize > msgSize) {
2583
+ pduIsComplete = false;
2584
+ pduErrors.push("v1 PDU truncated: expecting " + pduSize + ", got " + msgSize);
2585
+ }
2586
+ hdr = hdr.subarray(4);
2587
+ tail = hdr.subarray(0, 7).toString("ascii");
2588
+ hdr = hdr.subarray(7);
2589
+ } else if (version === 2) {
2590
+ hdr = hdr.subarray(1);
2591
+ }
2592
+ msgNum = hdr.readUInt8(0) >> 1 & 127;
2593
+ ackOptions = hdr.readUInt8(0) & 1;
2594
+ hdr = hdr.subarray(1);
2595
+ pduCompression = (hdr.readUInt8(0) << 2 | hdr.readUInt8(1) >> 6 & 3) & 7;
2596
+ pduEncoding = hdr.readUInt8(1) >> 4 & 3;
2597
+ pduAppType = hdr.readUInt8(1) & 15;
2598
+ hdr = hdr.subarray(2);
2599
+ let appIdLen = this.AppTypeToAppIdLenTable[version][pduAppType];
2600
+ if (appIdLen === void 0) {
2601
+ if (version === 2 && (pduAppType & 8) !== 0 && pduAppType !== 13) {
2602
+ appIdLen = (pduAppType & 7) + 1;
2603
+ } else {
2604
+ return {
2605
+ decoded: false,
2606
+ error: "Invalid v" + version + " appType: " + pduAppType
2607
+ };
2608
+ }
2609
+ }
2610
+ const pduIsACARS = [
2611
+ 0 /* ACARS2Char */,
2612
+ 1 /* ACARS4Char */,
2613
+ 2 /* ACARS6Char */,
2614
+ 0 /* ACARS2Char */,
2615
+ 1 /* ACARS4Char */,
2616
+ 2 /* ACARS6Char */
2617
+ ].indexOf(pduAppType) >= 0;
2618
+ if (hdr.length < appIdLen + crcLen) {
2619
+ return {
2620
+ decoded: false,
2621
+ error: "Header too short for v" + version + " appType: " + pduAppType
2622
+ };
2623
+ }
2624
+ pduAppId = hdr.subarray(0, appIdLen).toString("ascii");
2625
+ hdr = hdr.subarray(appIdLen);
2626
+ if (crcLen === 4) {
2627
+ pduCrc = hdr.readUInt8(0) << 24 | hdr.readUInt8(1) << 16 | hdr.readUInt8(2) << 8 | hdr.readUInt8(3);
2628
+ } else if (crcLen === 2) {
2629
+ pduCrc = hdr.readUInt8(0) << 8 | hdr.readUInt8(1);
2630
+ }
2631
+ hdr = hdr.subarray(crcLen);
2632
+ if (body !== void 0 && body.length > 0) {
2633
+ if ([1 /* Deflate */, 1 /* Deflate */].indexOf(pduCompression) >= 0) {
2634
+ try {
2635
+ pduData = Zlib.inflateRawSync(body, { windowBits: 15 });
2636
+ } catch (e) {
2637
+ pduErrors.push("Inflation failed for body: " + e);
2638
+ }
2639
+ } else if ([0 /* None */, 0 /* None */].indexOf(pduCompression) >= 0) {
2640
+ pduData = body;
2641
+ } else {
2642
+ pduErrors.push("Unsupported v" + version + " compression type: " + pduCompression);
2643
+ }
2644
+ if (pduData !== void 0) {
2645
+ const crcAlgoHandlerByVersion = {
2646
+ 1: (buf, seed) => {
2647
+ return ~this.arinc665Crc32(buf, seed);
2648
+ },
2649
+ 2: this.arincCrc16
2650
+ };
2651
+ const crcAlgoHandler = crcAlgoHandlerByVersion[version];
2652
+ if (crcAlgoHandler === void 0) {
2653
+ return {
2654
+ decoded: false,
2655
+ errors: "No CRC handler for v" + version
2656
+ };
2657
+ }
2658
+ const crcCheck = crcAlgoHandler(pduData, 4294967295);
2659
+ if (crcCheck === pduCrc) {
2660
+ pduCrcIsOk = true;
2661
+ } else {
2662
+ pduErrors.push("Body failed CRC check: provided=" + pduCrc + ", generated=" + crcCheck);
2663
+ }
2664
+ }
2665
+ } else {
2666
+ pduCrcIsOk = true;
2667
+ }
2668
+ let pdu = {
2669
+ version,
2670
+ crc: pduCrc,
2671
+ crcOk: pduCrcIsOk,
2672
+ complete: pduIsComplete,
2673
+ compression: pduCompression,
2674
+ encoding: pduEncoding,
2675
+ msgNum,
2676
+ ackOptions
2677
+ };
2678
+ if (pduIsACARS) {
2679
+ const label = pduAppId.substring(0, 2);
2680
+ const sublabel = appIdLen >= 4 ? pduAppId.substring(2, 4) : void 0;
2681
+ const mfi = appIdLen >= 6 ? pduAppId.substring(4, 6) : void 0;
2682
+ pdu.acars = {
2683
+ ...tail ? { tail } : {},
2684
+ label,
2685
+ ...sublabel ? { sublabel } : {},
2686
+ ...mfi ? { mfi } : {},
2687
+ ...pduData ? { text: pduData.toString("ascii") } : {}
2688
+ };
2689
+ } else {
2690
+ pdu.non_acars = {
2691
+ appId: pduAppId,
2692
+ ...pduData ? { text: pduData.toString("ascii") } : {}
2693
+ };
2694
+ }
2695
+ return {
2696
+ decoded: true,
2697
+ message: {
2698
+ data: pdu
2699
+ }
2700
+ };
2701
+ }
2702
+ static VersionPduHandlerTable = {
2703
+ 1: {
2704
+ [0 /* Data */]: (hdr, body) => {
2705
+ return this.corePduDataHandler(1, 20, MIAMCoreV1CRCLength, hdr, body);
2706
+ },
2707
+ [1 /* Ack */]: void 0,
2708
+ [2 /* Aloha */]: void 0,
2709
+ [3 /* AlohaReply */]: void 0
2710
+ },
2711
+ 2: {
2712
+ [0 /* Data */]: (hdr, body) => {
2713
+ return this.corePduDataHandler(2, 7, MIAMCoreV2CRCLength, hdr, body);
2714
+ },
2715
+ [1 /* Ack */]: void 0,
2716
+ [2 /* Aloha */]: void 0,
2717
+ [3 /* AlohaReply */]: void 0
2718
+ }
2719
+ };
2720
+ };
2721
+
2722
+ // lib/MessageDecoder.ts
2723
+ var MessageDecoder = class {
2724
+ name;
2725
+ plugins;
2726
+ debug;
2727
+ constructor() {
2728
+ this.name = "acars-decoder-typescript";
2729
+ this.plugins = [];
2730
+ this.debug = false;
2731
+ this.registerPlugin(new Label_ColonComma(this));
2732
+ this.registerPlugin(new Label_5Z(this));
2733
+ this.registerPlugin(new Label_12_N_Space(this));
2734
+ this.registerPlugin(new Label_15(this));
2735
+ this.registerPlugin(new Label_15_FST(this));
2736
+ this.registerPlugin(new Label_16_N_Space(this));
2737
+ this.registerPlugin(new Label_20_POS(this));
2738
+ this.registerPlugin(new Label_30_Slash_EA(this));
2739
+ this.registerPlugin(new Label_44_ETA(this));
2740
+ this.registerPlugin(new Label_44_IN(this));
2741
+ this.registerPlugin(new Label_44_OFF(this));
2742
+ this.registerPlugin(new Label_44_ON(this));
2743
+ this.registerPlugin(new Label_44_POS(this));
2744
+ this.registerPlugin(new Label_B6_Forwardslash(this));
2745
+ this.registerPlugin(new Label_H1_FPN(this));
2746
+ this.registerPlugin(new Label_H1_POS(this));
2747
+ this.registerPlugin(new Label_80(this));
2748
+ this.registerPlugin(new Label_8E(this));
2749
+ this.registerPlugin(new Label_1M_Slash(this));
2750
+ this.registerPlugin(new Label_SQ(this));
2751
+ this.registerPlugin(new Label_QP(this));
2752
+ this.registerPlugin(new Label_QQ(this));
2753
+ this.registerPlugin(new Label_QR(this));
2754
+ this.registerPlugin(new Label_QS(this));
2755
+ }
2756
+ registerPlugin(plugin) {
2757
+ const pluginInstance = plugin;
2758
+ this.plugins.push(plugin);
2759
+ return true;
2760
+ }
2761
+ decode(message, options = {}) {
2762
+ if (message.label === "MA") {
2763
+ const decodeResult = MIAMCoreUtils.parse(message.text);
2764
+ if (decodeResult.decoded && decodeResult.message.data !== void 0 && decodeResult.message.data.crcOk && decodeResult.message.data.complete && decodeResult.message.data.acars !== void 0) {
2765
+ message = {
2766
+ ...message,
2767
+ label: decodeResult.message.data.acars.label,
2768
+ ...decodeResult.message.data.acars.sublabel ? { sublabel: decodeResult.message.data.acars.sublabel } : {},
2769
+ ...decodeResult.message.data.acars.mfi ? { mfi: decodeResult.message.data.acars.mfi } : {},
2770
+ ...decodeResult.message.data.acars.text ? { text: decodeResult.message.data.acars.text } : {}
2771
+ };
2772
+ }
2773
+ }
2774
+ const usablePlugins = this.plugins.filter((plugin) => {
2775
+ const qualifiers = plugin.qualifiers();
2776
+ if (qualifiers.labels.includes(message.label)) {
2777
+ if (qualifiers.preambles && qualifiers.preambles.length > 0) {
2778
+ const matching = qualifiers.preambles.filter((preamble) => {
2779
+ return message.text.substring(0, preamble.length) === preamble;
2780
+ });
2781
+ return matching.length >= 1;
2782
+ } else {
2783
+ return true;
2784
+ }
2785
+ }
2786
+ return false;
2787
+ });
2788
+ if (options.debug) {
2789
+ console.log("Usable plugins");
2790
+ console.log(usablePlugins);
2791
+ }
2792
+ let result;
2793
+ if (usablePlugins.length > 0) {
2794
+ const plugin = usablePlugins[0];
2795
+ result = plugin.decode(message);
2796
+ } else {
2797
+ result = {
2798
+ decoded: false,
2799
+ error: "No known decoder plugin for this message",
2800
+ decoder: {
2801
+ name: "none",
2802
+ type: "none",
2803
+ decodeLevel: "none"
2804
+ },
2805
+ message,
2806
+ remaining: {
2807
+ text: message.text
2808
+ },
2809
+ raw: {},
2810
+ formatted: {
2811
+ description: "Not Decoded",
2812
+ items: []
2813
+ }
2814
+ };
2815
+ }
2816
+ if (options.debug) {
2817
+ console.log("Result");
2818
+ console.log(result);
2819
+ }
2820
+ return result;
2821
+ }
2822
+ lookupAirportByIata(iata) {
2823
+ const airportsArray = [];
2824
+ const airport = airportsArray.filter((e) => e.iata === iata);
2825
+ return airport;
2826
+ }
2827
+ };
2828
+ export {
2829
+ IcaoDecoder,
2830
+ MessageDecoder
2831
+ };
2832
+ //# sourceMappingURL=index.mjs.map