@airframes/acars-decoder 1.6.10 → 1.6.12

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.js CHANGED
@@ -49,6 +49,74 @@ var IcaoDecoder = class {
49
49
  }
50
50
  };
51
51
 
52
+ // lib/DateTimeUtils.ts
53
+ var DateTimeUtils = class {
54
+ // Expects a four digit UTC time string (HHMM)
55
+ static UTCToString(UTCString) {
56
+ let utcDate = /* @__PURE__ */ new Date();
57
+ utcDate.setUTCHours(+UTCString.substr(0, 2), +UTCString.substr(2, 2), 0);
58
+ return utcDate.toTimeString();
59
+ }
60
+ // Expects a six digit date string and a four digit UTC time string
61
+ // (DDMMYY) (HHMM)
62
+ static UTCDateTimeToString(dateString, timeString) {
63
+ let utcDate = /* @__PURE__ */ new Date();
64
+ utcDate.setUTCDate(+dateString.substr(0, 2));
65
+ utcDate.setUTCMonth(+dateString.substr(2, 2));
66
+ if (dateString.length === 6) {
67
+ utcDate.setUTCFullYear(2e3 + +dateString.substr(4, 2));
68
+ }
69
+ if (timeString.length === 6) {
70
+ utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), +timeString.substr(4, 2));
71
+ } else {
72
+ utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), 0);
73
+ }
74
+ return utcDate.toUTCString();
75
+ }
76
+ /**
77
+ *
78
+ * @param time HHMMSS
79
+ * @returns seconds since midnight
80
+ */
81
+ static convertHHMMSSToTod(time) {
82
+ const h = Number(time.substring(0, 2));
83
+ const m = Number(time.substring(2, 4));
84
+ const s = Number(time.substring(4, 6));
85
+ const tod = h * 3600 + m * 60 + s;
86
+ return tod;
87
+ }
88
+ /**
89
+ *
90
+ * @param time HHMMSS
91
+ * @param date MMDDYY or MMDDYYYY
92
+ * @returns seconds since epoch
93
+ */
94
+ static convertDateTimeToEpoch(time, date) {
95
+ if (date.length === 6) {
96
+ date = date.substring(0, 4) + `20${date.substring(4, 6)}`;
97
+ }
98
+ const timestamp = `${date.substring(4, 8)}-${date.substring(0, 2)}-${date.substring(2, 4)}T${time.substring(0, 2)}:${time.substring(2, 4)}:${time.substring(4, 6)}.000Z`;
99
+ const millis = Date.parse(timestamp);
100
+ return millis / 1e3;
101
+ }
102
+ /**
103
+ * Converts a timestamp to a string
104
+ *
105
+ * ISO-8601 format for 'epoch'
106
+ * HH:MM:SS for 'tod'
107
+ * @param time
108
+ * @param format
109
+ * @returns
110
+ */
111
+ static timestampToString(time, format) {
112
+ const date = new Date(time * 1e3);
113
+ if (format == "tod") {
114
+ return date.toISOString().slice(11, 19);
115
+ }
116
+ return date.toISOString().slice(0, -5) + "Z";
117
+ }
118
+ };
119
+
52
120
  // lib/DecoderPlugin.ts
53
121
  var DecoderPlugin = class {
54
122
  decoder;
@@ -154,10 +222,137 @@ var CoordinateUtils = class {
154
222
  const lonDir = coords.longitude > 0 ? "E" : "W";
155
223
  return `${Math.abs(coords.latitude).toFixed(3)} ${latDir}, ${Math.abs(coords.longitude).toFixed(3)} ${lonDir}`;
156
224
  }
225
+ static getDirection(coord) {
226
+ if (coord.startsWith("N") || coord.startsWith("E")) {
227
+ return 1;
228
+ } else if (coord.startsWith("S") || coord.startsWith("W")) {
229
+ return -1;
230
+ }
231
+ return NaN;
232
+ }
233
+ static dmsToDecimalDegrees(degrees, minutes, seconds) {
234
+ return degrees + minutes / 60 + seconds / 3600;
235
+ }
236
+ };
237
+
238
+ // lib/utils/route_utils.ts
239
+ var RouteUtils = class _RouteUtils {
240
+ static formatFlightState(state) {
241
+ switch (state) {
242
+ case "TO":
243
+ return "Takeoff";
244
+ case "IC":
245
+ return "Initial Climb";
246
+ case "CL":
247
+ return "Climb";
248
+ case "ER":
249
+ return "En Route";
250
+ case "DC":
251
+ return "Descent";
252
+ case "AP":
253
+ return "Approach";
254
+ default:
255
+ return `Unknown ${state}`;
256
+ }
257
+ }
258
+ static routeToString(route) {
259
+ let str = "";
260
+ if (route.name) {
261
+ str += route.name;
262
+ }
263
+ if (route.runway) {
264
+ str += `(${route.runway})`;
265
+ }
266
+ if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
267
+ str += " starting at ";
268
+ } else if (str.length !== 0 && route.waypoints) {
269
+ str += ": ";
270
+ }
271
+ if (route.waypoints) {
272
+ str += _RouteUtils.waypointsToString(route.waypoints);
273
+ }
274
+ return str;
275
+ }
276
+ static waypointToString(waypoint) {
277
+ let s = waypoint.name;
278
+ if (waypoint.latitude && waypoint.longitude) {
279
+ s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
280
+ }
281
+ if (waypoint.offset) {
282
+ s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
283
+ }
284
+ if (waypoint.time && waypoint.timeFormat) {
285
+ s += `@${DateTimeUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
286
+ }
287
+ return s;
288
+ }
289
+ static getWaypoint(leg) {
290
+ const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
291
+ if (regex?.length == 4) {
292
+ return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
293
+ }
294
+ const waypoint = leg.split(",");
295
+ if (waypoint.length == 2) {
296
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
297
+ if (position) {
298
+ return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
299
+ }
300
+ }
301
+ if (leg.length == 13 || leg.length == 14) {
302
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
303
+ const name = waypoint.length == 2 ? waypoint[0] : "";
304
+ if (position) {
305
+ return { name, latitude: position.latitude, longitude: position.longitude };
306
+ }
307
+ }
308
+ return { name: leg };
309
+ }
310
+ static waypointsToString(waypoints) {
311
+ let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
312
+ if (str.startsWith(" > ")) {
313
+ str = ">>" + str.slice(2);
314
+ }
315
+ return str;
316
+ }
157
317
  };
158
318
 
159
319
  // lib/utils/result_formatter.ts
160
320
  var ResultFormatter = class {
321
+ static state_change(decodeResult, from, to) {
322
+ decodeResult.raw.state_change = {
323
+ from,
324
+ to
325
+ };
326
+ from = RouteUtils.formatFlightState(from);
327
+ to = RouteUtils.formatFlightState(to);
328
+ decodeResult.formatted.items.push({
329
+ type: "state_change",
330
+ code: "STATE_CHANGE",
331
+ label: "State Change",
332
+ value: `${from} -> ${to}`
333
+ });
334
+ }
335
+ static freetext(decodeResult, value) {
336
+ decodeResult.raw.freetext = value;
337
+ decodeResult.formatted.items.push({
338
+ type: "freetext",
339
+ code: "FREE_TEXT",
340
+ label: "Free Text",
341
+ value
342
+ });
343
+ }
344
+ static door_event(decodeResult, name, state) {
345
+ decodeResult.raw.door_event = {
346
+ door: name,
347
+ state
348
+ };
349
+ decodeResult.formatted.items.push({
350
+ type: "door_event",
351
+ code: "DOOR",
352
+ label: "Door Event",
353
+ value: `${name} ${state}`
354
+ });
355
+ }
161
356
  static position(decodeResult, value) {
162
357
  decodeResult.raw.position = value;
163
358
  decodeResult.formatted.items.push({
@@ -178,16 +373,41 @@ var ResultFormatter = class {
178
373
  }
179
374
  static flightNumber(decodeResult, value) {
180
375
  decodeResult.raw.flight_number = value;
376
+ decodeResult.formatted.items.push({
377
+ type: "flight_number",
378
+ code: "FLIGHT",
379
+ label: "Flight Number",
380
+ value: decodeResult.raw.flight_number
381
+ });
181
382
  }
182
- static departureAirport(decodeResult, value) {
183
- decodeResult.raw.departure_icao = value;
383
+ static callsign(decodeResult, value) {
384
+ decodeResult.raw.callsign = value;
184
385
  decodeResult.formatted.items.push({
185
- type: "origin",
186
- code: "ORG",
187
- label: "Origin",
188
- value: decodeResult.raw.departure_icao
386
+ type: "callsign",
387
+ code: "CALLSIGN",
388
+ label: "Callsign",
389
+ value: decodeResult.raw.callsign
189
390
  });
190
391
  }
392
+ static departureAirport(decodeResult, value, type = "ICAO") {
393
+ if (type === "ICAO") {
394
+ decodeResult.raw.departure_icao = value;
395
+ decodeResult.formatted.items.push({
396
+ type: "icao",
397
+ code: "ORG",
398
+ label: "Origin",
399
+ value
400
+ });
401
+ } else {
402
+ decodeResult.raw.departure_iata = value;
403
+ decodeResult.formatted.items.push({
404
+ type: "iata",
405
+ code: "ORG",
406
+ label: "Origin",
407
+ value
408
+ });
409
+ }
410
+ }
191
411
  static departureRunway(decodeResult, value) {
192
412
  decodeResult.raw.departure_runway = value;
193
413
  decodeResult.formatted.items.push({
@@ -197,24 +417,53 @@ var ResultFormatter = class {
197
417
  value: decodeResult.raw.departure_runway
198
418
  });
199
419
  }
200
- static arrivalAirport(decodeResult, value) {
201
- decodeResult.raw.arrival_icao = value;
202
- decodeResult.formatted.items.push({
203
- type: "destination",
204
- code: "DST",
205
- label: "Destination",
206
- value: decodeResult.raw.arrival_icao
207
- });
420
+ static arrivalAirport(decodeResult, value, type = "ICAO") {
421
+ if (type === "ICAO") {
422
+ decodeResult.raw.arrival_icao = value;
423
+ decodeResult.formatted.items.push({
424
+ type: "icao",
425
+ code: "DST",
426
+ label: "Destination",
427
+ value
428
+ });
429
+ } else {
430
+ decodeResult.raw.arrival_iata = value;
431
+ decodeResult.formatted.items.push({
432
+ type: "iata",
433
+ code: "DST",
434
+ label: "Destination",
435
+ value
436
+ });
437
+ }
208
438
  }
209
- static eta(decodeResult, value) {
210
- decodeResult.raw.eta_time = value;
439
+ static alternateAirport(decodeResult, value) {
440
+ decodeResult.raw.alternate_icao = value;
211
441
  decodeResult.formatted.items.push({
212
- type: "eta",
213
- code: "ETA",
214
- label: "Estimated Time of Arrival",
215
- value: value.substring(0, 2) + ":" + value.substring(2, 4) + ":" + value.substring(4, 6)
442
+ type: "icao",
443
+ code: "ALT_DST",
444
+ label: "Alternate Destination",
445
+ value: decodeResult.raw.alternate_icao
216
446
  });
217
447
  }
448
+ static eta(decodeResult, time, type = "tod") {
449
+ if (type === "tod") {
450
+ decodeResult.raw.eta_time = time;
451
+ decodeResult.formatted.items.push({
452
+ type: "time_of_day",
453
+ code: "ETA",
454
+ label: "Estimated Time of Arrival",
455
+ value: DateTimeUtils.timestampToString(time, "tod")
456
+ });
457
+ } else {
458
+ decodeResult.raw.eta_date = time;
459
+ decodeResult.formatted.items.push({
460
+ type: "epoch",
461
+ code: "ETA",
462
+ label: "Estimated Time of Arrival",
463
+ value: DateTimeUtils.timestampToString(time, "epoch")
464
+ });
465
+ }
466
+ }
218
467
  static arrivalRunway(decodeResult, value) {
219
468
  decodeResult.raw.arrival_runway = value;
220
469
  decodeResult.formatted.items.push({
@@ -224,6 +473,15 @@ var ResultFormatter = class {
224
473
  value: decodeResult.raw.arrival_runway
225
474
  });
226
475
  }
476
+ static alternateRunway(decodeResult, value) {
477
+ decodeResult.raw.alternate_runway = value;
478
+ decodeResult.formatted.items.push({
479
+ type: "runway",
480
+ code: "ALT_ARWY",
481
+ label: "Alternate Runway",
482
+ value: decodeResult.raw.alternate_runway
483
+ });
484
+ }
227
485
  static currentFuel(decodeResult, value) {
228
486
  decodeResult.raw.fuel_on_board = value;
229
487
  decodeResult.formatted.items.push({
@@ -257,16 +515,16 @@ var ResultFormatter = class {
257
515
  type: "aircraft_groundspeed",
258
516
  code: "GSPD",
259
517
  label: "Aircraft Groundspeed",
260
- value: `${decodeResult.raw.groundspeed}`
518
+ value: `${decodeResult.raw.groundspeed} knots`
261
519
  });
262
520
  }
263
521
  static temperature(decodeResult, value) {
264
- decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
522
+ decodeResult.raw.outside_air_temperature = Number(value.replace("M", "-").replace("P", "+"));
265
523
  decodeResult.formatted.items.push({
266
524
  type: "outside_air_temperature",
267
525
  code: "OATEMP",
268
526
  label: "Outside Air Temperature (C)",
269
- value: `${decodeResult.raw.outside_air_temperature}`
527
+ value: `${decodeResult.raw.outside_air_temperature} degrees`
270
528
  });
271
529
  }
272
530
  static heading(decodeResult, value) {
@@ -278,14 +536,77 @@ var ResultFormatter = class {
278
536
  value: `${decodeResult.raw.heading}`
279
537
  });
280
538
  }
539
+ static tail(decodeResult, value) {
540
+ decodeResult.raw.tail = value;
541
+ decodeResult.formatted.items.push({
542
+ type: "tail",
543
+ code: "TAIL",
544
+ label: "Tail",
545
+ value: decodeResult.raw.tail
546
+ });
547
+ }
548
+ static out(decodeResult, time) {
549
+ decodeResult.raw.out_time = time;
550
+ decodeResult.formatted.items.push({
551
+ type: "time_of_day",
552
+ code: "OUT",
553
+ label: "Out of Gate Time",
554
+ value: DateTimeUtils.timestampToString(time, "tod")
555
+ });
556
+ }
557
+ static off(decodeResult, time) {
558
+ decodeResult.raw.off_time = time;
559
+ decodeResult.formatted.items.push({
560
+ type: "time_of_day",
561
+ code: "OFF",
562
+ label: "Takeoff Time",
563
+ value: DateTimeUtils.timestampToString(time, "tod")
564
+ });
565
+ }
566
+ static on(decodeResult, time) {
567
+ decodeResult.raw.on_time = time;
568
+ decodeResult.formatted.items.push({
569
+ type: "time_of_day",
570
+ code: "ON",
571
+ label: "Landing Time",
572
+ value: DateTimeUtils.timestampToString(time, "tod")
573
+ });
574
+ }
575
+ static in(decodeResult, time) {
576
+ decodeResult.raw.in_time = time;
577
+ decodeResult.formatted.items.push({
578
+ type: "time_of_day",
579
+ code: "IN",
580
+ label: "In Gate Time",
581
+ value: DateTimeUtils.timestampToString(time, "tod")
582
+ });
583
+ }
584
+ static time_of_day(decodeResult, time) {
585
+ decodeResult.raw.time_of_day = time;
586
+ decodeResult.formatted.items.push({
587
+ type: "time_of_day",
588
+ code: "MSG_TOD",
589
+ label: "Message Timestamp",
590
+ value: DateTimeUtils.timestampToString(time, "tod")
591
+ });
592
+ }
593
+ static text(decodeResult, text2) {
594
+ decodeResult.raw.text = text2;
595
+ decodeResult.formatted.items.push({
596
+ type: "text",
597
+ code: "TEXT",
598
+ label: "Text Message",
599
+ value: text2
600
+ });
601
+ }
281
602
  static unknown(decodeResult, value) {
282
603
  decodeResult.remaining.text += "," + value;
283
604
  }
284
605
  };
285
606
 
286
- // lib/plugins/Label_5Z.ts
287
- var Label_5Z = class extends DecoderPlugin {
288
- name = "label-5z";
607
+ // lib/plugins/Label_5Z_Slash.ts
608
+ var Label_5Z_Slash = class extends DecoderPlugin {
609
+ name = "label-5z-slash";
289
610
  descriptions = {
290
611
  B1: "Request Weight and Balance",
291
612
  B3: "Request Departure Clearance",
@@ -303,6 +624,7 @@ var Label_5Z = class extends DecoderPlugin {
303
624
  D6: "From-To + Date",
304
625
  D7: "From-To + Alternate + Time",
305
626
  EO: "In Range",
627
+ ET: "Expected Time",
306
628
  PW: "Position Weather",
307
629
  RL: "Request Release",
308
630
  R3: "Request HOWGOZIT Message",
@@ -313,48 +635,82 @@ var Label_5Z = class extends DecoderPlugin {
313
635
  };
314
636
  qualifiers() {
315
637
  return {
316
- labels: ["5Z"]
638
+ labels: ["5Z"],
639
+ preambles: ["/"]
317
640
  };
318
641
  }
319
642
  decode(message, options = {}) {
320
643
  const decodeResult = this.defaultResult();
321
644
  decodeResult.decoder.name = this.name;
322
645
  decodeResult.formatted.description = "Airline Designated Downlink";
323
- const uaRegex = /^\/(?<type>\w+) (?<remainder>.+)/;
324
- let results = message.text.match(uaRegex);
325
- if (results && results.length >= 2) {
326
- const type = results.groups.type.split("/")[0];
327
- const { remainder } = results.groups;
328
- const typeDescription = this.descriptions[type] ? this.descriptions[type] : "Unknown";
646
+ const lines = message.text.split("\r\n");
647
+ if (lines[0] === "/TXT") {
648
+ ResultFormatter.text(decodeResult, lines.slice(1).join("\r\n"));
649
+ decodeResult.decoded = true;
650
+ decodeResult.decoder.decodeLevel = "full";
651
+ return decodeResult;
652
+ }
653
+ const data = lines[0].split("/");
654
+ const header = data[1].split(" ");
655
+ const type = header[0];
656
+ const typeDescription = this.descriptions[type];
657
+ if (typeDescription) {
329
658
  decodeResult.raw.airline = "United Airlines";
330
659
  decodeResult.formatted.items.push({
331
660
  type: "airline",
661
+ code: "AIRLINE",
332
662
  label: "Airline",
333
663
  value: "United Airlines"
334
664
  });
335
665
  decodeResult.raw.message_type = type;
336
666
  decodeResult.formatted.items.push({
337
667
  type: "message_type",
668
+ code: "MSG_TYPE",
338
669
  label: "Message Type",
339
670
  value: `${typeDescription} (${type})`
340
671
  });
341
- if (type === "B3") {
342
- const rdcRegex = /^(?<from>\w\w\w)(?<to>\w\w\w) (?<unknown1>\d\d) R(?<runway>.+) G(?<unknown2>.+)$/;
343
- results = remainder.match(rdcRegex);
344
- if (results) {
345
- ResultFormatter.departureAirport(decodeResult, results.groups.from);
346
- ResultFormatter.arrivalAirport(decodeResult, results.groups.to);
347
- ResultFormatter.arrivalRunway(decodeResult, results.groups.runway);
348
- } else {
349
- if (options.debug) {
350
- console.log(`Decoder: Unkown 5Z RDC format: ${remainder}`);
351
- }
672
+ if (type === "B3" && data[1] === "B3 TO DATA REQ ") {
673
+ const info = data[2].split(" ");
674
+ ResultFormatter.departureAirport(decodeResult, info[1]);
675
+ ResultFormatter.arrivalAirport(decodeResult, info[2]);
676
+ decodeResult.raw.day_of_month = Number(info[3]);
677
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
678
+ ResultFormatter.arrivalRunway(decodeResult, info[5].slice(1));
679
+ decodeResult.remaining.text = data.slice(3).join("/");
680
+ } else if (type === "B3") {
681
+ ResultFormatter.departureAirport(decodeResult, header[1].substring(0, 3), "IATA");
682
+ ResultFormatter.arrivalAirport(decodeResult, header[1].substring(3), "IATA");
683
+ decodeResult.raw.day_of_month = Number(header[2]);
684
+ ResultFormatter.arrivalRunway(decodeResult, header[3].slice(1));
685
+ if (header.length > 4) {
686
+ decodeResult.remaining.text = header.slice(4).join(" ");
352
687
  }
688
+ } else if (type === "C3" && data[1] === "C3 GATE REQ ") {
689
+ const info = data[2].split(" ");
690
+ ResultFormatter.departureAirport(decodeResult, info[1]);
691
+ ResultFormatter.arrivalAirport(decodeResult, info[2]);
692
+ decodeResult.raw.day_of_month = Number(info[3]);
693
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
694
+ decodeResult.remaining.text = info.slice(5).join(" ");
695
+ } else if (type === "C3") {
696
+ ResultFormatter.departureAirport(decodeResult, header[1].substring(0, 3), "IATA");
697
+ ResultFormatter.arrivalAirport(decodeResult, header[1].substring(3), "IATA");
698
+ } else if (type === "ET") {
699
+ const airports = data[2].split(" ");
700
+ ResultFormatter.departureAirport(decodeResult, airports[1]);
701
+ ResultFormatter.arrivalAirport(decodeResult, airports[2]);
702
+ decodeResult.raw.day_of_month = Number(airports[3]);
703
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(airports[4]));
704
+ const estimates = data[3].split(" ");
705
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(estimates[1] + "00"));
706
+ decodeResult.remaining.text = estimates[2];
353
707
  } else {
354
- decodeResult.remaining.text = remainder;
708
+ if (options.debug) {
709
+ console.log(`Decoder: Unkown 5Z RDC format: ${message.text}`);
710
+ }
355
711
  }
356
712
  decodeResult.decoded = true;
357
- decodeResult.decoder.decodeLevel = "partial";
713
+ decodeResult.decoder.decodeLevel = decodeResult.remaining.text ? "partial" : "full";
358
714
  } else {
359
715
  if (options.debug) {
360
716
  console.log(`Decoder: Unknown 5Z message: ${message.text}`);
@@ -384,7 +740,7 @@ var Label_10_LDR = class extends DecoderPlugin {
384
740
  decodeResult.message = message;
385
741
  const parts = message.text.split(",");
386
742
  if (parts.length < 17) {
387
- if (options?.debug) {
743
+ if (options.debug) {
388
744
  console.log(`Decoder: Unknown 10 message: ${message.text}`);
389
745
  }
390
746
  decodeResult.remaining.text = message.text;
@@ -402,8 +758,13 @@ var Label_10_LDR = class extends DecoderPlugin {
402
758
  ResultFormatter.altitude(decodeResult, Number(parts[7]));
403
759
  ResultFormatter.departureAirport(decodeResult, parts[9]);
404
760
  ResultFormatter.arrivalAirport(decodeResult, parts[10]);
761
+ ResultFormatter.alternateAirport(decodeResult, parts[11]);
405
762
  ResultFormatter.arrivalRunway(decodeResult, parts[12].split("/")[0]);
406
- decodeResult.remaining.text = [...parts.slice(0, 5), parts[11], ...parts.slice(13)].join(",");
763
+ const altRwy = [parts[13].split("/")[0], parts[14].split("/")[0]].filter((r) => r != "").join(",");
764
+ if (altRwy != "") {
765
+ ResultFormatter.alternateRunway(decodeResult, altRwy);
766
+ }
767
+ decodeResult.remaining.text = [...parts.slice(0, 5), ...parts.slice(15)].join(",");
407
768
  decodeResult.decoded = true;
408
769
  decodeResult.decoder.decodeLevel = "partial";
409
770
  return decodeResult;
@@ -427,7 +788,7 @@ var Label_10_POS = class extends DecoderPlugin {
427
788
  decodeResult.message = message;
428
789
  const parts = message.text.split(",");
429
790
  if (parts.length !== 12) {
430
- if (options?.debug) {
791
+ if (options.debug) {
431
792
  console.log(`Decoder: Unknown 10 message: ${message.text}`);
432
793
  }
433
794
  decodeResult.remaining.text = message.text;
@@ -450,153 +811,30 @@ var Label_10_POS = class extends DecoderPlugin {
450
811
  }
451
812
  };
452
813
 
453
- // lib/DateTimeUtils.ts
454
- var DateTimeUtils = class {
455
- // Expects a four digit UTC time string (HHMM)
456
- static UTCToString(UTCString) {
457
- let utcDate = /* @__PURE__ */ new Date();
458
- utcDate.setUTCHours(+UTCString.substr(0, 2), +UTCString.substr(2, 2), 0);
459
- return utcDate.toTimeString();
814
+ // lib/plugins/Label_10_Slash.ts
815
+ var Label_10_Slash = class extends DecoderPlugin {
816
+ // eslint-disable-line camelcase
817
+ name = "label-10-slash";
818
+ qualifiers() {
819
+ return {
820
+ labels: ["10"],
821
+ preambles: ["/"]
822
+ };
460
823
  }
461
- // Expects a six digit date string and a four digit UTC time string
462
- // (DDMMYY) (HHMM)
463
- static UTCDateTimeToString(dateString, timeString) {
464
- let utcDate = /* @__PURE__ */ new Date();
465
- utcDate.setUTCDate(+dateString.substr(0, 2));
466
- utcDate.setUTCMonth(+dateString.substr(2, 2));
467
- if (dateString.length === 6) {
468
- utcDate.setUTCFullYear(2e3 + +dateString.substr(4, 2));
469
- }
470
- if (timeString.length === 6) {
471
- utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), +timeString.substr(4, 2));
472
- } else {
473
- utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), 0);
474
- }
475
- return utcDate.toUTCString();
476
- }
477
- /**
478
- *
479
- * @param time HHMMSS
480
- * @returns seconds since midnight
481
- */
482
- static convertHHMMSSToTod(time) {
483
- const h = Number(time.substring(0, 2));
484
- const m = Number(time.substring(2, 4));
485
- const s = Number(time.substring(4, 6));
486
- const tod = h * 3600 + m * 60 + s;
487
- return tod;
488
- }
489
- /**
490
- *
491
- * @param time HHMMSS
492
- * @param date MMDDYY or MMDDYYYY
493
- * @returns seconds since epoch
494
- */
495
- static convertDateTimeToEpoch(time, date) {
496
- if (date.length === 6) {
497
- date = date.substring(0, 4) + `20${date.substring(4, 6)}`;
498
- }
499
- const timestamp = `${date.substring(4, 8)}-${date.substring(0, 2)}-${date.substring(2, 4)}T${time.substring(0, 2)}:${time.substring(2, 4)}:${time.substring(4, 6)}.000Z`;
500
- const millis = Date.parse(timestamp);
501
- return millis / 1e3;
502
- }
503
- };
504
-
505
- // lib/utils/route_utils.ts
506
- var RouteUtils = class _RouteUtils {
507
- static routeToString(route) {
508
- let str = "";
509
- if (route.name) {
510
- str += route.name;
511
- }
512
- if (route.runway) {
513
- str += `(${route.runway})`;
514
- }
515
- if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
516
- str += " starting at ";
517
- } else if (str.length !== 0 && route.waypoints) {
518
- str += ": ";
519
- }
520
- if (route.waypoints) {
521
- str += _RouteUtils.waypointsToString(route.waypoints);
522
- }
523
- return str;
524
- }
525
- static waypointToString(waypoint) {
526
- let s = waypoint.name;
527
- if (waypoint.latitude && waypoint.longitude) {
528
- s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
529
- }
530
- if (waypoint.offset) {
531
- s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
532
- }
533
- if (waypoint.time && waypoint.timeFormat) {
534
- s += `@${_RouteUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
535
- }
536
- return s;
537
- }
538
- static getWaypoint(leg) {
539
- const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
540
- if (regex?.length == 4) {
541
- return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
542
- }
543
- const waypoint = leg.split(",");
544
- if (waypoint.length == 2) {
545
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
546
- if (position) {
547
- return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
548
- }
549
- }
550
- if (leg.length == 13 || leg.length == 14) {
551
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
552
- const name = waypoint.length == 2 ? waypoint[0] : "";
553
- if (position) {
554
- return { name, latitude: position.latitude, longitude: position.longitude };
555
- }
556
- }
557
- return { name: leg };
558
- }
559
- // move out if we want public
560
- static timestampToString(time, format) {
561
- const date = new Date(time * 1e3);
562
- if (format == "tod") {
563
- return date.toISOString().slice(11, 19);
564
- }
565
- return date.toISOString().slice(0, -5) + "Z";
566
- }
567
- static waypointsToString(waypoints) {
568
- let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
569
- if (str.startsWith(" > ")) {
570
- str = ">>" + str.slice(2);
571
- }
572
- return str;
573
- }
574
- };
575
-
576
- // lib/plugins/Label_10_Slash.ts
577
- var Label_10_Slash = class extends DecoderPlugin {
578
- // eslint-disable-line camelcase
579
- name = "label-10-slash";
580
- qualifiers() {
581
- return {
582
- labels: ["10"],
583
- preambles: ["/"]
584
- };
585
- }
586
- decode(message, options = {}) {
587
- const decodeResult = this.defaultResult();
588
- decodeResult.decoder.name = this.name;
589
- decodeResult.formatted.description = "Position Report";
590
- decodeResult.message = message;
591
- const parts = message.text.split("/");
592
- if (parts.length < 17) {
593
- if (options?.debug) {
594
- console.log(`Decoder: Unknown 10 message: ${message.text}`);
595
- }
596
- decodeResult.remaining.text = message.text;
597
- decodeResult.decoded = false;
598
- decodeResult.decoder.decodeLevel = "none";
599
- return decodeResult;
824
+ decode(message, options = {}) {
825
+ const decodeResult = this.defaultResult();
826
+ decodeResult.decoder.name = this.name;
827
+ decodeResult.formatted.description = "Position Report";
828
+ decodeResult.message = message;
829
+ const parts = message.text.split("/");
830
+ if (parts.length < 17) {
831
+ if (options.debug) {
832
+ console.log(`Decoder: Unknown 10 message: ${message.text}`);
833
+ }
834
+ decodeResult.remaining.text = message.text;
835
+ decodeResult.decoded = false;
836
+ decodeResult.decoder.decodeLevel = "none";
837
+ return decodeResult;
600
838
  }
601
839
  const lat = parts[1];
602
840
  const lon = parts[2];
@@ -608,7 +846,7 @@ var Label_10_Slash = class extends DecoderPlugin {
608
846
  ResultFormatter.heading(decodeResult, Number(parts[5]));
609
847
  ResultFormatter.altitude(decodeResult, 100 * Number(parts[6]));
610
848
  ResultFormatter.arrivalAirport(decodeResult, parts[7]);
611
- ResultFormatter.eta(decodeResult, parts[8] + "00");
849
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[8] + "00"));
612
850
  const waypoints = [{
613
851
  name: parts[11]
614
852
  }, {
@@ -685,6 +923,97 @@ var Label_12_N_Space = class extends DecoderPlugin {
685
923
  }
686
924
  };
687
925
 
926
+ // lib/plugins/Label_13Through18_Slash.ts
927
+ var Label_13Through18_Slash = class extends DecoderPlugin {
928
+ // eslint-disable-line camelcase
929
+ name = "label-13-18-slash";
930
+ qualifiers() {
931
+ return {
932
+ labels: ["13", "14", "15", "16", "17", "18"],
933
+ preambles: ["/"]
934
+ };
935
+ }
936
+ decode(message, options = {}) {
937
+ const decodeResult = this.defaultResult();
938
+ decodeResult.decoder.name = this.name;
939
+ decodeResult.message = message;
940
+ const lines = message.text.split("\r\n");
941
+ const parts = lines[0].split("/");
942
+ const labelNumber = Number(parts[1].substring(0, 2));
943
+ decodeResult.formatted.description = getMsgType(labelNumber);
944
+ if (labelNumber !== 18 && parts.length !== 4 || labelNumber === 18 && parts.length !== 7) {
945
+ if (options?.debug) {
946
+ console.log(`Decoder: Unknown OOOI message: ${message.text}`);
947
+ }
948
+ decodeResult.remaining.text = message.text;
949
+ decodeResult.decoded = false;
950
+ decodeResult.decoder.decodeLevel = "none";
951
+ return decodeResult;
952
+ }
953
+ decodeResult.remaining.text = "";
954
+ const data = parts[2].split(" ");
955
+ ResultFormatter.departureAirport(decodeResult, data[1]);
956
+ ResultFormatter.arrivalAirport(decodeResult, data[2]);
957
+ decodeResult.raw.day_of_month = Number(data[3]);
958
+ const time = DateTimeUtils.convertHHMMSSToTod(data[4]);
959
+ if (labelNumber === 13) {
960
+ ResultFormatter.out(decodeResult, time);
961
+ } else if (labelNumber === 14) {
962
+ ResultFormatter.off(decodeResult, time);
963
+ } else if (labelNumber === 15) {
964
+ ResultFormatter.on(decodeResult, time);
965
+ } else if (labelNumber === 16) {
966
+ ResultFormatter.in(decodeResult, time);
967
+ }
968
+ if (parts.length === 7) {
969
+ decodeResult.remaining.text += parts.slice(4).join("/");
970
+ }
971
+ for (let i = 1; i < lines.length; i++) {
972
+ if (lines[i].startsWith("/LOC")) {
973
+ const location = lines[i].substring(5).split(",");
974
+ let position;
975
+ if (location[0].startsWith("+") || location[0].startsWith("-")) {
976
+ position = { latitude: Number(location[0]), longitude: Number(location[1]) };
977
+ } else {
978
+ position = {
979
+ latitude: CoordinateUtils.getDirection(location[0][0]) * CoordinateUtils.dmsToDecimalDegrees(Number(location[0].substring(1, 3)), Number(location[0].substring(3, 5)), Number(location[0].substring(5, 7))),
980
+ longitude: CoordinateUtils.getDirection(location[1][0]) * CoordinateUtils.dmsToDecimalDegrees(Number(location[1].substring(1, 4)), Number(location[1].substring(4, 6)), Number(location[1].substring(6, 8)))
981
+ };
982
+ }
983
+ if (!isNaN(position.latitude) && !isNaN(position.longitude)) {
984
+ ResultFormatter.position(decodeResult, position);
985
+ }
986
+ } else {
987
+ decodeResult.remaining.text += "\r\n" + lines[i];
988
+ }
989
+ }
990
+ decodeResult.decoded = true;
991
+ decodeResult.decoder.decodeLevel = decodeResult.remaining.text ? "partial" : "full";
992
+ return decodeResult;
993
+ }
994
+ };
995
+ function getMsgType(labelNumber) {
996
+ if (labelNumber === 13) {
997
+ return "Out of Gate Report";
998
+ }
999
+ if (labelNumber === 14) {
1000
+ return "Takeoff Report";
1001
+ }
1002
+ if (labelNumber === 15) {
1003
+ return "On Ground Report";
1004
+ }
1005
+ if (labelNumber === 16) {
1006
+ return "In Gate Report";
1007
+ }
1008
+ if (labelNumber === 17) {
1009
+ return "Post Report";
1010
+ }
1011
+ if (labelNumber === 18) {
1012
+ return "Post Times Report";
1013
+ }
1014
+ return "Unknown";
1015
+ }
1016
+
688
1017
  // lib/plugins/Label_15.ts
689
1018
  var Label_15 = class extends DecoderPlugin {
690
1019
  name = "label-5z";
@@ -851,28 +1180,12 @@ var Label_1M_Slash = class extends DecoderPlugin {
851
1180
  console.log(results);
852
1181
  }
853
1182
  decodeResult.raw.flight_number = results[0];
854
- decodeResult.raw.departure_icao = results[3];
855
- decodeResult.raw.arrival_icao = results[4];
856
- decodeResult.raw.alternate_icao = results[5];
857
- decodeResult.raw.arrival_runway = results[8].replace(decodeResult.raw.arrival_icao, "");
858
- decodeResult.formatted.items.push({
859
- type: "eta",
860
- code: "ETA",
861
- label: "Estimated Time of Arrival",
862
- value: DateTimeUtils.UTCDateTimeToString(results[2], results[7])
863
- });
864
- decodeResult.formatted.items.push({
865
- type: "destination",
866
- code: "DST",
867
- label: "Destination",
868
- value: decodeResult.raw.arrival_icao
869
- });
870
- decodeResult.formatted.items.push({
871
- type: "origin",
872
- code: "ORG",
873
- label: "Origin",
874
- value: decodeResult.raw.departure_icao
875
- });
1183
+ ResultFormatter.departureAirport(decodeResult, results[3]);
1184
+ ResultFormatter.arrivalAirport(decodeResult, results[4]);
1185
+ ResultFormatter.alternateAirport(decodeResult, results[5]);
1186
+ ResultFormatter.arrivalRunway(decodeResult, results[8].replace(results[4], ""));
1187
+ const yymmdd = results[2];
1188
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertDateTimeToEpoch(results[7] + "00", yymmdd.substring(2, 4) + yymmdd.substring(4, 6) + yymmdd.substring(0, 2)), "epoch");
876
1189
  }
877
1190
  decodeResult.decoded = true;
878
1191
  decodeResult.decoder.decodeLevel = "partial";
@@ -896,11 +1209,11 @@ var Label_20_POS = class extends DecoderPlugin {
896
1209
  decodeResult.message = message;
897
1210
  decodeResult.raw.preamble = message.text.substring(0, 3);
898
1211
  const content = message.text.substring(3);
899
- console.log("Content: " + content);
900
1212
  const fields = content.split(",");
901
- console.log("Field Count: " + fields.length);
902
1213
  if (fields.length == 11) {
903
- console.log(`DEBUG: ${this.name}: Variation 1 detected`);
1214
+ if (options.debug) {
1215
+ console.log(`DEBUG: ${this.name}: Variation 1 detected`);
1216
+ }
904
1217
  const rawCoords = fields[0];
905
1218
  decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
906
1219
  if (decodeResult.raw.position) {
@@ -914,7 +1227,9 @@ var Label_20_POS = class extends DecoderPlugin {
914
1227
  decodeResult.decoded = true;
915
1228
  decodeResult.decoder.decodeLevel = "full";
916
1229
  } else if (fields.length == 5) {
917
- console.log(`DEBUG: ${this.name}: Variation 2 detected`);
1230
+ if (options.debug) {
1231
+ console.log(`DEBUG: ${this.name}: Variation 2 detected`);
1232
+ }
918
1233
  const rawCoords = fields[0];
919
1234
  decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
920
1235
  if (decodeResult.raw.position) {
@@ -928,7 +1243,9 @@ var Label_20_POS = class extends DecoderPlugin {
928
1243
  decodeResult.decoded = true;
929
1244
  decodeResult.decoder.decodeLevel = "full";
930
1245
  } else {
931
- console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
1246
+ if (options.debug) {
1247
+ console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
1248
+ }
932
1249
  decodeResult.decoded = false;
933
1250
  decodeResult.decoder.decodeLevel = "none";
934
1251
  }
@@ -952,25 +1269,25 @@ var Label_21_POS = class extends DecoderPlugin {
952
1269
  decodeResult.message = message;
953
1270
  decodeResult.raw.preamble = message.text.substring(0, 3);
954
1271
  const content = message.text.substring(3);
955
- console.log("Content: " + content);
956
1272
  const fields = content.split(",");
957
- console.log("Field Count: " + fields.length);
958
1273
  if (fields.length == 9) {
959
1274
  processPosition(decodeResult, fields[0].trim());
960
- processAlt(decodeResult, fields[3]);
961
- processTemp(decodeResult, fields[6]);
962
- processArrvApt(decodeResult, fields[8]);
1275
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2]));
1276
+ ResultFormatter.altitude(decodeResult, Number(fields[3]));
1277
+ ResultFormatter.temperature(decodeResult, fields[6].replace(/ /g, ""));
1278
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[7]));
1279
+ ResultFormatter.arrivalAirport(decodeResult, fields[8]);
963
1280
  decodeResult.remaining.text = [
964
1281
  fields[1],
965
- fields[2],
966
1282
  fields[4],
967
- fields[5],
968
- fields[7]
1283
+ fields[5]
969
1284
  ].join(",");
970
1285
  decodeResult.decoded = true;
971
1286
  decodeResult.decoder.decodeLevel = "partial";
972
1287
  } else {
973
- console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
1288
+ if (options.debug) {
1289
+ console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
1290
+ }
974
1291
  decodeResult.decoded = false;
975
1292
  decodeResult.decoder.decodeLevel = "none";
976
1293
  }
@@ -979,7 +1296,7 @@ var Label_21_POS = class extends DecoderPlugin {
979
1296
  };
980
1297
  function processPosition(decodeResult, value) {
981
1298
  if (value.length !== 16 && value[0] !== "N" && value[0] !== "S" && value[8] !== "W" && value[8] !== "E") {
982
- return false;
1299
+ return;
983
1300
  }
984
1301
  const latDir = value[0] === "N" ? 1 : -1;
985
1302
  const lonDir = value[8] === "E" ? 1 : -1;
@@ -987,45 +1304,52 @@ function processPosition(decodeResult, value) {
987
1304
  latitude: latDir * Number(value.substring(1, 7)),
988
1305
  longitude: lonDir * Number(value.substring(9, 15))
989
1306
  };
990
- if (position) {
991
- decodeResult.raw.position = position;
992
- decodeResult.formatted.items.push({
993
- type: "aircraft_position",
994
- code: "POS",
995
- label: "Aircraft Position",
996
- value: CoordinateUtils.coordinateString(position)
997
- });
998
- }
999
- return !!position;
1000
- }
1001
- function processAlt(decodeResult, value) {
1002
- decodeResult.raw.altitude = Number(value);
1003
- decodeResult.formatted.items.push({
1004
- type: "altitude",
1005
- code: "ALT",
1006
- label: "Altitude",
1007
- value: `${decodeResult.raw.altitude} feet`
1008
- });
1009
- }
1010
- function processTemp(decodeResult, value) {
1011
- decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
1012
- decodeResult.formatted.items.push({
1013
- type: "outside_air_temperature",
1014
- code: "OATEMP",
1015
- label: "Outside Air Temperature (C)",
1016
- value: `${decodeResult.raw.outside_air_temperature}`
1017
- });
1018
- }
1019
- function processArrvApt(decodeResult, value) {
1020
- decodeResult.raw.arrival_icao = value;
1021
- decodeResult.formatted.items.push({
1022
- type: "destination",
1023
- code: "DST",
1024
- label: "Destination",
1025
- value: decodeResult.raw.arrival_icao
1026
- });
1307
+ ResultFormatter.position(decodeResult, position);
1027
1308
  }
1028
1309
 
1310
+ // lib/plugins/Label_24_Slash.ts
1311
+ var Label_24_Slash = class extends DecoderPlugin {
1312
+ name = "label-24-slash";
1313
+ qualifiers() {
1314
+ return {
1315
+ labels: ["24"],
1316
+ preambles: ["/"]
1317
+ };
1318
+ }
1319
+ decode(message, options = {}) {
1320
+ const decodeResult = this.defaultResult();
1321
+ decodeResult.decoder.name = this.name;
1322
+ decodeResult.formatted.description = "Position Report";
1323
+ decodeResult.message = message;
1324
+ const fields = message.text.split("/");
1325
+ if (fields.length == 10 && fields[0] == "" && fields[9] == "") {
1326
+ const mmddyy = fields[1].substring(4, 6) + fields[1].substring(2, 4) + fields[1].substring(0, 2);
1327
+ const hhmmss = fields[2] + "00";
1328
+ decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(hhmmss, mmddyy);
1329
+ ResultFormatter.flightNumber(decodeResult, fields[3]);
1330
+ ResultFormatter.altitude(decodeResult, Number(fields[4]));
1331
+ const lat = fields[5];
1332
+ const lon = fields[6];
1333
+ const position = {
1334
+ latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1)),
1335
+ longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1))
1336
+ };
1337
+ ResultFormatter.position(decodeResult, position);
1338
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[8] + "00"));
1339
+ decodeResult.remaining.text = fields[7];
1340
+ decodeResult.decoded = true;
1341
+ decodeResult.decoder.decodeLevel = "partial";
1342
+ } else {
1343
+ if (options.debug) {
1344
+ console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}. Message: ${message.text}`);
1345
+ }
1346
+ decodeResult.decoded = false;
1347
+ decodeResult.decoder.decodeLevel = "none";
1348
+ }
1349
+ return decodeResult;
1350
+ }
1351
+ };
1352
+
1029
1353
  // lib/plugins/Label_30_Slash_EA.ts
1030
1354
  var Label_30_Slash_EA = class extends DecoderPlugin {
1031
1355
  name = "label-30-slash-ea";
@@ -1047,20 +1371,9 @@ var Label_30_Slash_EA = class extends DecoderPlugin {
1047
1371
  console.log(results);
1048
1372
  }
1049
1373
  }
1050
- decodeResult.formatted.items.push({
1051
- type: "eta",
1052
- code: "ETA",
1053
- label: "Estimated Time of Arrival",
1054
- value: DateTimeUtils.UTCToString(results[0].substr(2, 4))
1055
- });
1056
- if (results[1].substr(0, 2) === "DS") {
1057
- decodeResult.raw.arrival_icao = results[1].substr(2, 4);
1058
- decodeResult.formatted.items.push({
1059
- type: "destination",
1060
- code: "DST",
1061
- label: "Destination",
1062
- value: decodeResult.raw.arrival_icao
1063
- });
1374
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results[0].substr(2, 4) + "00"));
1375
+ if (results[1].substring(0, 2) === "DS") {
1376
+ ResultFormatter.arrivalAirport(decodeResult, results[1].substring(2, 6));
1064
1377
  decodeResult.remaining.text = "/".concat(results[2]);
1065
1378
  } else {
1066
1379
  decodeResult.remaining.text = "/".concat(results[1], "/", results[2]);
@@ -1352,23 +1665,296 @@ var Label_44_POS = class extends DecoderPlugin {
1352
1665
  }
1353
1666
  };
1354
1667
 
1355
- // lib/plugins/Label_80.ts
1356
- var Label_80 = class extends DecoderPlugin {
1357
- name = "label-80";
1358
- descriptions = {
1359
- ALT: "Altitude",
1360
- DWND: "Wind Direction",
1361
- ETA: "Estimated Time of Arrival",
1362
- FOB: "Fuel on Board",
1363
- FL: "Flight Level",
1364
- HDG: "Heading",
1365
- MCH: "Aircraft Speed",
1366
- NWYP: "Next Waypoint",
1367
- POS: "Aircraft Position",
1368
- SAT: "Static Air Temperature",
1369
- SWND: "Wind Speed",
1370
- TAS: "True Airspeed",
1371
- WYP: "Waypoint"
1668
+ // lib/plugins/Label_4A.ts
1669
+ var Label_4A = class extends DecoderPlugin {
1670
+ name = "label-4a";
1671
+ qualifiers() {
1672
+ return {
1673
+ labels: ["4A"]
1674
+ };
1675
+ }
1676
+ decode(message, options = {}) {
1677
+ const decodeResult = this.defaultResult();
1678
+ decodeResult.decoder.name = this.name;
1679
+ decodeResult.message = message;
1680
+ decodeResult.formatted.description = "Latest New Format";
1681
+ let text2 = message.text;
1682
+ if (text2.match(/^M\d{2}A\w{6}/)) {
1683
+ ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
1684
+ text2 = text2.substring(10);
1685
+ }
1686
+ decodeResult.decoded = true;
1687
+ const fields = text2.split(",");
1688
+ if (fields.length === 11) {
1689
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[0]));
1690
+ ResultFormatter.tail(decodeResult, fields[2].replace(".", ""));
1691
+ if (fields[3])
1692
+ ResultFormatter.callsign(decodeResult, fields[3]);
1693
+ ResultFormatter.departureAirport(decodeResult, fields[4]);
1694
+ ResultFormatter.arrivalAirport(decodeResult, fields[5]);
1695
+ ResultFormatter.altitude(decodeResult, text2.substring(48, 51) * 100);
1696
+ decodeResult.remaining.text = fields.slice(8).join(",");
1697
+ } else if (fields.length === 6) {
1698
+ if (fields[0].match(/^[NS]/)) {
1699
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(fields[0].substring(0, 13)));
1700
+ let wp1 = {
1701
+ name: fields[0].substring(13).trim(),
1702
+ time: DateTimeUtils.convertHHMMSSToTod(fields[1].substring(0, 6)),
1703
+ timeFormat: "tod"
1704
+ };
1705
+ ResultFormatter.altitude(decodeResult, fields[1].substring(6, 9) * 100);
1706
+ let wp2 = {
1707
+ name: fields[1].substring(9).trim(),
1708
+ time: DateTimeUtils.convertHHMMSSToTod(fields[2]),
1709
+ timeFormat: "tod"
1710
+ };
1711
+ decodeResult.raw.route = { waypoints: [wp1, wp2] };
1712
+ decodeResult.formatted.items.push({
1713
+ type: "aircraft_route",
1714
+ code: "ROUTE",
1715
+ label: "Aircraft Route",
1716
+ value: RouteUtils.routeToString(decodeResult.raw.route)
1717
+ });
1718
+ ResultFormatter.temperature(decodeResult, fields[3]);
1719
+ decodeResult.remaining.text = fields.slice(4).join(",");
1720
+ } else {
1721
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[0]));
1722
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1]));
1723
+ decodeResult.remaining.text = fields[2];
1724
+ ResultFormatter.altitude(decodeResult, fields[3]);
1725
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates((fields[4] + fields[5]).replace(/[ \.]/g, "")));
1726
+ }
1727
+ } else {
1728
+ decodeResult.decoded = false;
1729
+ decodeResult.remaining.text = text2;
1730
+ }
1731
+ if (decodeResult.decoded) {
1732
+ if (!decodeResult.remaining.text)
1733
+ decodeResult.decoder.decodeLevel = "full";
1734
+ else
1735
+ decodeResult.decoder.decodeLevel = "partial";
1736
+ } else {
1737
+ decodeResult.decoder.decodeLevel = "none";
1738
+ }
1739
+ return decodeResult;
1740
+ }
1741
+ };
1742
+
1743
+ // lib/plugins/Label_4A_01.ts
1744
+ var Label_4A_01 = class extends DecoderPlugin {
1745
+ name = "label-4a-01";
1746
+ qualifiers() {
1747
+ return {
1748
+ labels: ["4A"],
1749
+ preambles: ["01"]
1750
+ };
1751
+ }
1752
+ decode(message, options = {}) {
1753
+ const decodeResult = this.defaultResult();
1754
+ decodeResult.decoder.name = this.name;
1755
+ decodeResult.message = message;
1756
+ decodeResult.formatted.description = "Latest New Format";
1757
+ decodeResult.decoded = true;
1758
+ let rgx = message.text.match(/^01([A-Z]{2})([A-Z]{2})\s*(\w+)\/(\d{6})([A-Z]{4})([A-Z]{4})\r\n([+-]\s*\d+)(\d{3}\.\d)([+-]\s*\d+\.\d)/);
1759
+ if (rgx) {
1760
+ ResultFormatter.state_change(decodeResult, rgx[1], rgx[2]);
1761
+ ResultFormatter.callsign(decodeResult, rgx[3]);
1762
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(rgx[4] + "00"));
1763
+ ResultFormatter.departureAirport(decodeResult, rgx[5]);
1764
+ ResultFormatter.arrivalAirport(decodeResult, rgx[6]);
1765
+ ResultFormatter.altitude(decodeResult, Number(rgx[7].replace(/ /g, "")));
1766
+ decodeResult.remaining.text = rgx[8];
1767
+ ResultFormatter.temperature(decodeResult, rgx[9].replace(/ /g, ""));
1768
+ } else {
1769
+ decodeResult.decoded = false;
1770
+ decodeResult.remaining.text = message.text;
1771
+ }
1772
+ if (decodeResult.decoded) {
1773
+ if (!decodeResult.remaining.text)
1774
+ decodeResult.decoder.decodeLevel = "full";
1775
+ else
1776
+ decodeResult.decoder.decodeLevel = "partial";
1777
+ } else {
1778
+ decodeResult.decoder.decodeLevel = "none";
1779
+ }
1780
+ return decodeResult;
1781
+ }
1782
+ };
1783
+
1784
+ // lib/plugins/Label_4A_DIS.ts
1785
+ var Label_4A_DIS = class extends DecoderPlugin {
1786
+ name = "label-4a-dis";
1787
+ qualifiers() {
1788
+ return {
1789
+ labels: ["4A"],
1790
+ preambles: ["DIS"]
1791
+ };
1792
+ }
1793
+ decode(message, options = {}) {
1794
+ const decodeResult = this.defaultResult();
1795
+ decodeResult.decoder.name = this.name;
1796
+ decodeResult.message = message;
1797
+ decodeResult.formatted.description = "Latest New Format";
1798
+ decodeResult.decoded = true;
1799
+ const fields = message.text.split(",");
1800
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(2) + "00"));
1801
+ ResultFormatter.callsign(decodeResult, fields[2]);
1802
+ ResultFormatter.freetext(decodeResult, fields.slice(3).join(""));
1803
+ if (decodeResult.decoded) {
1804
+ if (!decodeResult.remaining.text)
1805
+ decodeResult.decoder.decodeLevel = "full";
1806
+ else
1807
+ decodeResult.decoder.decodeLevel = "partial";
1808
+ } else {
1809
+ decodeResult.decoder.decodeLevel = "none";
1810
+ }
1811
+ return decodeResult;
1812
+ }
1813
+ };
1814
+
1815
+ // lib/plugins/Label_4A_DOOR.ts
1816
+ var Label_4A_DOOR = class extends DecoderPlugin {
1817
+ name = "label-4a-door";
1818
+ qualifiers() {
1819
+ return {
1820
+ labels: ["4A"],
1821
+ preambles: ["DOOR"]
1822
+ };
1823
+ }
1824
+ decode(message, options = {}) {
1825
+ const decodeResult = this.defaultResult();
1826
+ decodeResult.decoder.name = this.name;
1827
+ decodeResult.message = message;
1828
+ decodeResult.formatted.description = "Latest New Format";
1829
+ decodeResult.decoded = true;
1830
+ const fields = message.text.split(" ");
1831
+ if (fields.length === 3) {
1832
+ ResultFormatter.door_event(decodeResult, fields[0].split("/")[1], fields[1]);
1833
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2] + "00"));
1834
+ } else {
1835
+ decodeResult.decoded = false;
1836
+ decodeResult.remaining.text = text;
1837
+ }
1838
+ if (decodeResult.decoded) {
1839
+ if (!decodeResult.remaining.text)
1840
+ decodeResult.decoder.decodeLevel = "full";
1841
+ else
1842
+ decodeResult.decoder.decodeLevel = "partial";
1843
+ } else {
1844
+ decodeResult.decoder.decodeLevel = "none";
1845
+ }
1846
+ return decodeResult;
1847
+ }
1848
+ };
1849
+
1850
+ // lib/plugins/Label_4A_Slash_01.ts
1851
+ var Label_4A_Slash_01 = class extends DecoderPlugin {
1852
+ name = "label-4a-slash-01";
1853
+ qualifiers() {
1854
+ return {
1855
+ labels: ["4A"],
1856
+ preambles: ["/01"]
1857
+ };
1858
+ }
1859
+ decode(message, options = {}) {
1860
+ const decodeResult = this.defaultResult();
1861
+ decodeResult.decoder.name = this.name;
1862
+ decodeResult.message = message;
1863
+ decodeResult.formatted.description = "Latest New Format";
1864
+ decodeResult.decoded = true;
1865
+ if (message.text.length === 5 && message.text.substring(0, 4) === "/01-") {
1866
+ decodeResult.remaining.text = message.text.substring(4);
1867
+ } else {
1868
+ decodeResult.decoded = false;
1869
+ decodeResult.remaining.text = message.text;
1870
+ }
1871
+ if (decodeResult.decoded) {
1872
+ if (!decodeResult.remaining.text)
1873
+ decodeResult.decoder.decodeLevel = "full";
1874
+ else
1875
+ decodeResult.decoder.decodeLevel = "partial";
1876
+ } else {
1877
+ decodeResult.decoder.decodeLevel = "none";
1878
+ }
1879
+ return decodeResult;
1880
+ }
1881
+ };
1882
+
1883
+ // lib/plugins/Label_4N.ts
1884
+ var Label_4N = class extends DecoderPlugin {
1885
+ name = "label-4n";
1886
+ qualifiers() {
1887
+ return {
1888
+ labels: ["4N"]
1889
+ };
1890
+ }
1891
+ decode(message, options = {}) {
1892
+ const decodeResult = this.defaultResult();
1893
+ decodeResult.decoder.name = this.name;
1894
+ decodeResult.message = message;
1895
+ decodeResult.formatted.description = "Airline Defined";
1896
+ let text2 = message.text;
1897
+ if (text2.match(/^M\d{2}A\w{6}/)) {
1898
+ ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
1899
+ text2 = text2.substring(10);
1900
+ }
1901
+ decodeResult.decoded = true;
1902
+ const fields = text2.split(",");
1903
+ if (text2.length === 51) {
1904
+ decodeResult.raw.day_of_month = text2.substring(0, 2);
1905
+ ResultFormatter.departureAirport(decodeResult, text2.substring(8, 11));
1906
+ ResultFormatter.arrivalAirport(decodeResult, text2.substring(13, 16));
1907
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text2.substring(30, 45).replace(/^(.)0/, "$1")));
1908
+ ResultFormatter.altitude(decodeResult, text2.substring(48, 51) * 100);
1909
+ decodeResult.remaining.text = [text2.substring(2, 4), text2.substring(19, 29)].join(" ");
1910
+ } else if (fields.length === 33) {
1911
+ decodeResult.raw.date = fields[3];
1912
+ if (fields[1] === "B") {
1913
+ ResultFormatter.position(decodeResult, { latitude: Number(fields[4]), longitude: Number(fields[5]) });
1914
+ ResultFormatter.altitude(decodeResult, fields[6]);
1915
+ }
1916
+ ResultFormatter.departureAirport(decodeResult, fields[8]);
1917
+ ResultFormatter.arrivalAirport(decodeResult, fields[9]);
1918
+ ResultFormatter.alternateAirport(decodeResult, fields[10]);
1919
+ ResultFormatter.arrivalRunway(decodeResult, fields[11].split("/")[0]);
1920
+ if (fields[12].length > 1) {
1921
+ ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
1922
+ }
1923
+ ResultFormatter.checksum(decodeResult, fields[32]);
1924
+ decodeResult.remaining.text = [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != "").join(",");
1925
+ } else {
1926
+ decodeResult.decoded = false;
1927
+ decodeResult.remaining.text = text2;
1928
+ }
1929
+ if (decodeResult.decoded) {
1930
+ if (!decodeResult.remaining.text)
1931
+ decodeResult.decoder.decodeLevel = "full";
1932
+ else
1933
+ decodeResult.decoder.decodeLevel = "partial";
1934
+ } else {
1935
+ decodeResult.decoder.decodeLevel = "none";
1936
+ }
1937
+ return decodeResult;
1938
+ }
1939
+ };
1940
+
1941
+ // lib/plugins/Label_80.ts
1942
+ var Label_80 = class extends DecoderPlugin {
1943
+ name = "label-80";
1944
+ descriptions = {
1945
+ ALT: "Altitude",
1946
+ DWND: "Wind Direction",
1947
+ ETA: "Estimated Time of Arrival",
1948
+ FOB: "Fuel on Board",
1949
+ FL: "Flight Level",
1950
+ HDG: "Heading",
1951
+ MCH: "Aircraft Speed",
1952
+ NWYP: "Next Waypoint",
1953
+ POS: "Aircraft Position",
1954
+ SAT: "Static Air Temperature",
1955
+ SWND: "Wind Speed",
1956
+ TAS: "True Airspeed",
1957
+ WYP: "Waypoint"
1372
1958
  };
1373
1959
  qualifiers() {
1374
1960
  return {
@@ -1383,27 +1969,15 @@ var Label_80 = class extends DecoderPlugin {
1383
1969
  const parts = message.text.split("\n");
1384
1970
  let posRptRegex = /^3N01 POSRPT \d\d\d\d\/\d\d (?<orig>\w+)\/(?<dest>\w+) \.(?<tail>[\w-]+)(\/(?<agate>.+) (?<sta>\w+:\w+))*/;
1385
1971
  let results = parts[0].match(posRptRegex);
1972
+ if (!results?.groups) {
1973
+ decodeResult.decoded = false;
1974
+ decodeResult.decoder.decodeLevel = "none";
1975
+ return decodeResult;
1976
+ }
1386
1977
  if (results && results.length > 0) {
1387
- decodeResult.raw.origin = results.groups.orig;
1388
- decodeResult.formatted.items.push({
1389
- type: "origin",
1390
- code: "ORG",
1391
- label: "Origin",
1392
- value: `${results.groups.orig}`
1393
- });
1394
- decodeResult.raw.destination = results.groups.dest;
1395
- decodeResult.formatted.items.push({
1396
- type: "destination",
1397
- code: "DST",
1398
- label: "Destination",
1399
- value: `${results.groups.dest}`
1400
- });
1401
- decodeResult.raw.tail = results.groups.tail;
1402
- decodeResult.formatted.items.push({
1403
- type: "tail",
1404
- label: "Tail",
1405
- value: `${results.groups.tail}`
1406
- });
1978
+ ResultFormatter.departureAirport(decodeResult, results.groups.orig);
1979
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.dest);
1980
+ ResultFormatter.tail(decodeResult, results.groups.tail);
1407
1981
  if (results.groups.agate) {
1408
1982
  decodeResult.raw.arrival_gate = results.groups.agate;
1409
1983
  decodeResult.formatted.items.push({
@@ -1425,15 +1999,9 @@ var Label_80 = class extends DecoderPlugin {
1425
1999
  for (const part of remainingParts) {
1426
2000
  const matches = part.matchAll(posRptRegex);
1427
2001
  for (const match of matches) {
1428
- switch (match.groups.field) {
2002
+ switch (match.groups?.field) {
1429
2003
  case "ALT": {
1430
- decodeResult.raw.altitude = match.groups.value;
1431
- decodeResult.formatted.items.push({
1432
- type: "altitude",
1433
- code: "ALT",
1434
- label: this.descriptions[match.groups.field],
1435
- value: `${decodeResult.raw.altitude} feet`
1436
- });
2004
+ ResultFormatter.altitude(decodeResult, Number(match.groups.value));
1437
2005
  break;
1438
2006
  }
1439
2007
  case "DWND": {
@@ -1447,9 +2015,8 @@ var Label_80 = class extends DecoderPlugin {
1447
2015
  break;
1448
2016
  }
1449
2017
  case "FL": {
1450
- const flight_level = match.groups.value;
1451
- decodeResult.raw.altitude = flight_level * 100;
1452
- ResultFormatter.altitude(decodeResult, decodeResult.raw.altitude);
2018
+ const flight_level = Number(match.groups.value);
2019
+ ResultFormatter.altitude(decodeResult, flight_level * 100);
1453
2020
  break;
1454
2021
  }
1455
2022
  case "FOB": {
@@ -1473,7 +2040,7 @@ var Label_80 = class extends DecoderPlugin {
1473
2040
  break;
1474
2041
  }
1475
2042
  case "MCH": {
1476
- decodeResult.raw.mach = match.groups.value / 1e3;
2043
+ decodeResult.raw.mach = Number(match.groups.value) / 1e3;
1477
2044
  decodeResult.formatted.items.push({
1478
2045
  type: "mach",
1479
2046
  code: "MCH",
@@ -1495,20 +2062,13 @@ var Label_80 = class extends DecoderPlugin {
1495
2062
  case "POS": {
1496
2063
  const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
1497
2064
  const posResult = match.groups.value.match(posRegex);
1498
- const lat = Number(posResult.groups.lat) * (posResult.groups.lngd === "S" ? -1 : 1);
1499
- const lon = Number(posResult.groups.lng) * (posResult.groups.lngd === "W" ? -1 : 1);
1500
- const latitude = Number.isInteger(lat) ? lat / 1e3 : lat / 100;
1501
- const longitude = Number.isInteger(lon) ? lon / 1e3 : lon / 100;
1502
- decodeResult.raw.position = {
1503
- latitude,
1504
- longitude
2065
+ const lat = Number(posResult?.groups?.lat) * (posResult?.groups?.lngd === "S" ? -1 : 1);
2066
+ const lon = Number(posResult?.groups?.lng) * (posResult?.groups?.lngd === "W" ? -1 : 1);
2067
+ const position = {
2068
+ latitude: Number.isInteger(lat) ? lat / 1e3 : lat / 100,
2069
+ longitude: Number.isInteger(lon) ? lon / 1e3 : lon / 100
1505
2070
  };
1506
- decodeResult.formatted.items.push({
1507
- type: "position",
1508
- code: "POS",
1509
- label: "Position",
1510
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1511
- });
2071
+ ResultFormatter.position(decodeResult, position);
1512
2072
  break;
1513
2073
  }
1514
2074
  case "SWND": {
@@ -1522,7 +2082,7 @@ var Label_80 = class extends DecoderPlugin {
1522
2082
  break;
1523
2083
  }
1524
2084
  default: {
1525
- if (match.groups.field != void 0) {
2085
+ if (match.groups?.field != void 0) {
1526
2086
  const description = this.descriptions[match.groups.field] ? this.descriptions[match.groups.field] : "Unknown";
1527
2087
  decodeResult.formatted.items.push({
1528
2088
  type: match.groups.field,
@@ -1536,7 +2096,80 @@ var Label_80 = class extends DecoderPlugin {
1536
2096
  }
1537
2097
  }
1538
2098
  decodeResult.decoded = true;
1539
- decodeResult.decodeLevel = "partial";
2099
+ decodeResult.decoder.decodeLevel = "partial";
2100
+ }
2101
+ return decodeResult;
2102
+ }
2103
+ };
2104
+
2105
+ // lib/plugins/Label_83.ts
2106
+ var Label_83 = class extends DecoderPlugin {
2107
+ name = "label-83";
2108
+ qualifiers() {
2109
+ return {
2110
+ labels: ["83"]
2111
+ };
2112
+ }
2113
+ decode(message, options = {}) {
2114
+ const decodeResult = this.defaultResult();
2115
+ decodeResult.decoder.name = this.name;
2116
+ decodeResult.message = message;
2117
+ decodeResult.formatted.description = "Airline Defined";
2118
+ let text2 = message.text;
2119
+ if (text2.match(/^M\d{2}A\w{6}/)) {
2120
+ ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
2121
+ text2 = text2.substring(10);
2122
+ }
2123
+ decodeResult.decoded = true;
2124
+ if (text2.substring(0, 10) === "4DH3 ETAT2") {
2125
+ const fields = text2.split(/\s+/);
2126
+ if (fields[2].length > 5) {
2127
+ decodeResult.raw.day_of_month = fields[2].substring(5);
2128
+ }
2129
+ decodeResult.remaining.text = fields[2].substring(0, 4);
2130
+ const subfields = fields[3].split("/");
2131
+ ResultFormatter.departureAirport(decodeResult, subfields[0]);
2132
+ ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
2133
+ ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
2134
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[6] + "00"));
2135
+ } else if (text2.substring(0, 5) === "001PR") {
2136
+ decodeResult.raw.day_of_month = text2.substring(5, 7);
2137
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text2.substring(13, 28).replace(/\./g, ""));
2138
+ if (position) {
2139
+ ResultFormatter.position(decodeResult, position);
2140
+ }
2141
+ ResultFormatter.altitude(decodeResult, Number(text2.substring(28, 33)));
2142
+ decodeResult.remaining.text = text2.substring(33);
2143
+ } else {
2144
+ const fields = text2.replace(/\s/g, "").split(",");
2145
+ if (fields.length === 9) {
2146
+ ResultFormatter.departureAirport(decodeResult, fields[0]);
2147
+ ResultFormatter.arrivalAirport(decodeResult, fields[1]);
2148
+ decodeResult.raw.day_of_month = fields[2].substring(0, 2);
2149
+ decodeResult.raw.time = fields[2].substring(2);
2150
+ ResultFormatter.position(
2151
+ decodeResult,
2152
+ {
2153
+ latitude: Number(fields[3].replace(/\s/g, "")),
2154
+ longitude: Number(fields[4].replace(/\s/g, ""))
2155
+ }
2156
+ );
2157
+ ResultFormatter.altitude(decodeResult, Number(fields[5]));
2158
+ ResultFormatter.groundspeed(decodeResult, fields[6]);
2159
+ ResultFormatter.heading(decodeResult, fields[7]);
2160
+ decodeResult.remaining.text = fields[8];
2161
+ } else {
2162
+ decodeResult.decoded = false;
2163
+ decodeResult.remaining.text = message.text;
2164
+ }
2165
+ }
2166
+ if (decodeResult.decoded) {
2167
+ if (!decodeResult.remaining.text)
2168
+ decodeResult.decoder.decodeLevel = "full";
2169
+ else
2170
+ decodeResult.decoder.decodeLevel = "partial";
2171
+ } else {
2172
+ decodeResult.decoder.decodeLevel = "none";
1540
2173
  }
1541
2174
  return decodeResult;
1542
2175
  }
@@ -1562,19 +2195,8 @@ var Label_8E = class extends DecoderPlugin {
1562
2195
  console.log(`Label 8E ETA: groups`);
1563
2196
  console.log(results.groups);
1564
2197
  }
1565
- decodeResult.formatted.items.push({
1566
- type: "eta",
1567
- code: "ETA",
1568
- label: "Estimated Time of Arrival",
1569
- value: DateTimeUtils.UTCToString(results.groups.arrival_eta)
1570
- });
1571
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1572
- decodeResult.formatted.items.push({
1573
- type: "destination",
1574
- code: "DST",
1575
- label: "Destination",
1576
- value: decodeResult.raw.arrival_icao
1577
- });
2198
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta + "00"));
2199
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1578
2200
  }
1579
2201
  decodeResult.decoded = true;
1580
2202
  decodeResult.decoder.decodeLevel = "full";
@@ -1627,44 +2249,158 @@ var Label_ColonComma = class extends DecoderPlugin {
1627
2249
  }
1628
2250
  };
1629
2251
 
1630
- // lib/plugins/Label_H1_FLR.ts
1631
- var Label_H1_FLR = class extends DecoderPlugin {
1632
- name = "label-h1-flr";
2252
+ // lib/plugins/Label_H1_FLR.ts
2253
+ var Label_H1_FLR = class extends DecoderPlugin {
2254
+ name = "label-h1-flr";
2255
+ qualifiers() {
2256
+ return {
2257
+ labels: ["H1"],
2258
+ preambles: ["FLR", "#CFBFLR"]
2259
+ };
2260
+ }
2261
+ decode(message, options = {}) {
2262
+ let decodeResult = this.defaultResult();
2263
+ decodeResult.decoder.name = this.name;
2264
+ decodeResult.formatted.description = "Fault Log Report";
2265
+ decodeResult.message = message;
2266
+ const parts = message.text.split("/FR");
2267
+ if (parts.length > 1) {
2268
+ decodeResult.remaining.text = "";
2269
+ const fields = parts[0].split("/");
2270
+ for (let i = 1; i < fields.length; i++) {
2271
+ const field = fields[i];
2272
+ if (field.startsWith("PN")) {
2273
+ processUnknown(decodeResult, "/" + field);
2274
+ } else {
2275
+ processUnknown(decodeResult, "/" + field);
2276
+ }
2277
+ }
2278
+ const data = parts[1].substring(0, 20);
2279
+ const msg = parts[1].substring(20);
2280
+ const datetime = data.substring(0, 12);
2281
+ const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
2282
+ processUnknown(decodeResult, data.substring(12));
2283
+ decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
2284
+ decodeResult.raw.fault_message = msg;
2285
+ decodeResult.formatted.items.push({
2286
+ type: "fault",
2287
+ code: "FR",
2288
+ label: "Fault Report",
2289
+ value: decodeResult.raw.fault_message
2290
+ });
2291
+ decodeResult.decoded = true;
2292
+ decodeResult.decoder.decodeLevel = "partial";
2293
+ } else {
2294
+ if (options.debug) {
2295
+ console.log(`Decoder: Unknown H1 message: ${message.text}`);
2296
+ }
2297
+ decodeResult.remaining.text = message.text;
2298
+ decodeResult.decoded = false;
2299
+ decodeResult.decoder.decodeLevel = "none";
2300
+ }
2301
+ return decodeResult;
2302
+ }
2303
+ };
2304
+ function processUnknown(decodeResult, value) {
2305
+ decodeResult.remaining.text += value;
2306
+ }
2307
+
2308
+ // lib/plugins/Label_H1_OHMA.ts
2309
+ var zlib = __toESM(require("minizlib"));
2310
+ var Label_H1_OHMA = class extends DecoderPlugin {
2311
+ name = "label-h1-ohma";
2312
+ qualifiers() {
2313
+ return {
2314
+ labels: ["H1"],
2315
+ preambles: ["OHMA", "/RTNBOCR.OHMA", "#T1B/RTNBOCR.OHMA"]
2316
+ };
2317
+ }
2318
+ decode(message, options = {}) {
2319
+ let decodeResult = this.defaultResult();
2320
+ decodeResult.decoder.name = this.name;
2321
+ decodeResult.formatted.description = "OHMA Message";
2322
+ decodeResult.message = message;
2323
+ decodeResult.remaining.text = "";
2324
+ const data = message.text.split("OHMA")[1];
2325
+ try {
2326
+ const compressedBuffer = Buffer.from(data, "base64");
2327
+ const decompress = new zlib.Inflate({ windowBits: 15 });
2328
+ decompress.write(compressedBuffer);
2329
+ decompress.flush(zlib.constants.Z_SYNC_FLUSH);
2330
+ const result = decompress.read();
2331
+ const jsonText = result.toString();
2332
+ let formattedMsg;
2333
+ let jsonMessage;
2334
+ try {
2335
+ jsonMessage = JSON.parse(jsonText).message;
2336
+ } catch {
2337
+ jsonMessage = jsonText;
2338
+ }
2339
+ try {
2340
+ const ohmaMsg = JSON.parse(jsonMessage);
2341
+ formattedMsg = JSON.stringify(ohmaMsg, null, 2);
2342
+ } catch {
2343
+ formattedMsg = jsonMessage;
2344
+ }
2345
+ decodeResult.decoded = true;
2346
+ decodeResult.decoder.decodeLevel = "full";
2347
+ decodeResult.raw.ohma = jsonText;
2348
+ decodeResult.formatted.items.push({
2349
+ type: "ohma",
2350
+ code: "OHMA",
2351
+ label: "OHMA Downlink",
2352
+ value: formattedMsg
2353
+ });
2354
+ } catch (e) {
2355
+ if (options.debug) {
2356
+ console.log(`Decoder: Unknown H1 OHMA message: ${message.text}`, e);
2357
+ }
2358
+ decodeResult.remaining.text += message.text;
2359
+ decodeResult.decoded = false;
2360
+ decodeResult.decoder.decodeLevel = "none";
2361
+ }
2362
+ return decodeResult;
2363
+ }
2364
+ };
2365
+
2366
+ // lib/plugins/Label_H1_WRN.ts
2367
+ var Label_H1_WRN = class extends DecoderPlugin {
2368
+ name = "label-h1-wrn";
1633
2369
  qualifiers() {
1634
2370
  return {
1635
2371
  labels: ["H1"],
1636
- preambles: ["FLR", "#CFBFLR"]
2372
+ preambles: ["WRN", "#CFBWRN"]
1637
2373
  };
1638
2374
  }
1639
2375
  decode(message, options = {}) {
1640
2376
  let decodeResult = this.defaultResult();
1641
2377
  decodeResult.decoder.name = this.name;
1642
- decodeResult.formatted.description = "Fault Log Report";
2378
+ decodeResult.formatted.description = "Warning Message";
1643
2379
  decodeResult.message = message;
1644
- const parts = message.text.split("/FR");
2380
+ const parts = message.text.split("/WN");
1645
2381
  if (parts.length > 1) {
1646
2382
  decodeResult.remaining.text = "";
1647
2383
  const fields = parts[0].split("/");
1648
2384
  for (let i = 1; i < fields.length; i++) {
1649
2385
  const field = fields[i];
1650
2386
  if (field.startsWith("PN")) {
1651
- processUnknown(decodeResult, "/" + field);
2387
+ processUnknown2(decodeResult, "/" + field);
1652
2388
  } else {
1653
- processUnknown(decodeResult, "/" + field);
2389
+ processUnknown2(decodeResult, "/" + field);
1654
2390
  }
1655
2391
  }
1656
2392
  const data = parts[1].substring(0, 20);
1657
2393
  const msg = parts[1].substring(20);
1658
2394
  const datetime = data.substring(0, 12);
1659
2395
  const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
1660
- processUnknown(decodeResult, data.substring(12));
2396
+ processUnknown2(decodeResult, data.substring(12));
1661
2397
  decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
1662
- decodeResult.raw.fault_message = msg;
2398
+ decodeResult.raw.warning_message = msg;
1663
2399
  decodeResult.formatted.items.push({
1664
- type: "fault",
1665
- code: "FR",
1666
- label: "Fault Report",
1667
- value: decodeResult.raw.fault_message
2400
+ type: "warning",
2401
+ code: "WRN",
2402
+ label: "Warning Message",
2403
+ value: decodeResult.raw.warning_message
1668
2404
  });
1669
2405
  decodeResult.decoded = true;
1670
2406
  decodeResult.decoder.decodeLevel = "partial";
@@ -1679,7 +2415,7 @@ var Label_H1_FLR = class extends DecoderPlugin {
1679
2415
  return decodeResult;
1680
2416
  }
1681
2417
  };
1682
- function processUnknown(decodeResult, value) {
2418
+ function processUnknown2(decodeResult, value) {
1683
2419
  decodeResult.remaining.text += value;
1684
2420
  }
1685
2421
 
@@ -1845,11 +2581,10 @@ function addCompanyRoute(decodeResult, value) {
1845
2581
  // lib/utils/h1_helper.ts
1846
2582
  var H1Helper = class {
1847
2583
  static decodeH1Message(decodeResult, message) {
1848
- let allKnownFields = true;
1849
2584
  const checksum = message.slice(-4);
1850
2585
  const data = message.slice(0, message.length - 4);
1851
2586
  const fields = data.split("/");
1852
- allKnownFields = allKnownFields && parseMessageType(decodeResult, fields[0]);
2587
+ parseMessageType(decodeResult, fields[0]);
1853
2588
  for (let i = 1; i < fields.length; ++i) {
1854
2589
  if (fields[i].startsWith("FN")) {
1855
2590
  decodeResult.raw.flight_number = fields[i].substring(2);
@@ -1868,32 +2603,22 @@ var H1Helper = class {
1868
2603
  decodeResult.raw.message_timestamp = time;
1869
2604
  } else if (fields[i].startsWith("PS")) {
1870
2605
  const pos = processPS(decodeResult, fields[i].substring(2).split(","));
1871
- allKnownFields == allKnownFields && pos;
1872
2606
  } else if (fields[i].startsWith("DT")) {
1873
2607
  const data2 = fields[i].substring(2).split(",");
1874
- const dt = processDT(decodeResult, data2);
1875
- allKnownFields = allKnownFields && dt;
2608
+ processDT(decodeResult, data2);
1876
2609
  } else if (fields[i].startsWith("ID")) {
1877
2610
  processIdentification(decodeResult, fields[i].substring(2).split(","));
1878
2611
  } else if (fields[i].startsWith("LR")) {
1879
2612
  const data2 = fields[i].substring(2).split(",");
1880
- const lr = processLR(decodeResult, data2);
1881
- allKnownFields = allKnownFields && lr;
2613
+ processLR(decodeResult, data2);
1882
2614
  } else if (fields[i].startsWith("RI") || fields[i].startsWith("RF") || fields[i].startsWith("RP")) {
1883
- const fp = FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
1884
- allKnownFields = allKnownFields && fp;
2615
+ FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
1885
2616
  } else if (fields[i].startsWith("PR")) {
1886
- allKnownFields = false;
1887
2617
  decodeResult.remaining.text += "/" + fields[i];
1888
- } else if (fields[i].startsWith("PS")) {
1889
- allKnownFields = false;
1890
- decodeResult.remaining.text += fields[i];
1891
2618
  } else if (fields[i].startsWith("AF")) {
1892
- const af = processAirField(decodeResult, fields[i].substring(2).split(","));
1893
- allKnownFields = allKnownFields && af;
2619
+ processAirField(decodeResult, fields[i].substring(2).split(","));
1894
2620
  } else if (fields[i].startsWith("TD")) {
1895
- const td = processTimeOfDeparture(decodeResult, fields[i].substring(2).split(","));
1896
- allKnownFields = allKnownFields && td;
2621
+ processTimeOfDeparture(decodeResult, fields[i].substring(2).split(","));
1897
2622
  } else if (fields[i].startsWith("FX")) {
1898
2623
  decodeResult.raw.free_text = fields[i].substring(2);
1899
2624
  decodeResult.formatted.items.push({
@@ -1904,23 +2629,21 @@ var H1Helper = class {
1904
2629
  });
1905
2630
  } else {
1906
2631
  decodeResult.remaining.text += "/" + fields[i];
1907
- allKnownFields = false;
1908
2632
  }
1909
2633
  }
1910
2634
  if (decodeResult.formatted.items.length > 0) {
1911
2635
  ResultFormatter.checksum(decodeResult, checksum);
1912
2636
  }
1913
- return allKnownFields;
2637
+ return true;
1914
2638
  }
1915
2639
  };
1916
2640
  function processAirField(decodeResult, data) {
1917
2641
  if (data.length === 2) {
1918
2642
  ResultFormatter.departureAirport(decodeResult, data[0]);
1919
2643
  ResultFormatter.arrivalAirport(decodeResult, data[1]);
1920
- return true;
2644
+ } else {
2645
+ decodeResult.remaining.text += "AF/" + data.join(",");
1921
2646
  }
1922
- decodeResult.remaining.text += "AF/" + data.join(",");
1923
- return false;
1924
2647
  }
1925
2648
  function processTimeOfDeparture(decodeResult, data) {
1926
2649
  if (data.length === 2) {
@@ -1938,19 +2661,12 @@ function processTimeOfDeparture(decodeResult, data) {
1938
2661
  label: "Estimated Departure Time",
1939
2662
  value: `${data[1].substring(0, 2)}:${data[1].substring(2)}`
1940
2663
  });
1941
- return true;
2664
+ } else {
2665
+ decodeResult.remaining.text += "/TD" + data.join(",");
1942
2666
  }
1943
- decodeResult.remaining.text += "/TD" + data.join(",");
1944
- return false;
1945
2667
  }
1946
2668
  function processIdentification(decodeResult, data) {
1947
- decodeResult.raw.tail = data[0];
1948
- decodeResult.formatted.items.push({
1949
- type: "tail",
1950
- code: "TAIL",
1951
- label: "Tail",
1952
- value: decodeResult.raw.tail
1953
- });
2669
+ ResultFormatter.tail(decodeResult, data[0]);
1954
2670
  if (data.length > 1) {
1955
2671
  decodeResult.raw.flight_number = data[1];
1956
2672
  }
@@ -1959,7 +2675,6 @@ function processIdentification(decodeResult, data) {
1959
2675
  }
1960
2676
  }
1961
2677
  function processDT(decodeResult, data) {
1962
- let allKnownFields = true;
1963
2678
  if (!decodeResult.raw.arrival_icao) {
1964
2679
  ResultFormatter.arrivalAirport(decodeResult, data[0]);
1965
2680
  } else if (decodeResult.raw.arrival_icao != data[0]) {
@@ -1972,19 +2687,16 @@ function processDT(decodeResult, data) {
1972
2687
  ResultFormatter.currentFuel(decodeResult, Number(data[2]));
1973
2688
  }
1974
2689
  if (data.length > 3) {
1975
- ResultFormatter.eta(decodeResult, data[3]);
2690
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[3]));
1976
2691
  }
1977
2692
  if (data.length > 4) {
1978
2693
  ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
1979
2694
  }
1980
2695
  if (data.length > 5) {
1981
- allKnownFields = false;
1982
2696
  decodeResult.remaining.text += "," + data.slice(5).join(",");
1983
2697
  }
1984
- return allKnownFields;
1985
2698
  }
1986
2699
  function processLR(decodeResult, data) {
1987
- let allKnownFields = true;
1988
2700
  if (data.length === 19) {
1989
2701
  ResultFormatter.unknown(decodeResult, data[1]);
1990
2702
  ResultFormatter.flightNumber(decodeResult, data[2]);
@@ -1992,34 +2704,47 @@ function processLR(decodeResult, data) {
1992
2704
  ResultFormatter.arrivalAirport(decodeResult, data[4]);
1993
2705
  ResultFormatter.arrivalRunway(decodeResult, data[5]);
1994
2706
  ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
1995
- allKnownFields = false;
1996
2707
  } else {
1997
- allKnownFields = false;
2708
+ ResultFormatter.unknown(decodeResult, data.join(","));
1998
2709
  }
1999
- return allKnownFields;
2000
2710
  }
2001
2711
  function parseMessageType(decodeResult, messageType) {
2002
- let decoded = true;
2003
2712
  const parts = messageType.split("#");
2004
2713
  if (parts.length == 1) {
2005
- if (parts[0].startsWith("POS") && parts[0].length !== 3 && !parts[0].startsWith("POS/")) {
2006
- decoded = processPosition2(decodeResult, parts[0].substring(3).split(","));
2714
+ const type = parts[0].substring(0, 3);
2715
+ if (type === "POS" && parts[0].length !== 3) {
2716
+ processPosition2(decodeResult, parts[0].substring(3).split(","));
2007
2717
  }
2008
- return decoded;
2718
+ return processMessageType(decodeResult, type);
2009
2719
  } else if (parts.length == 2) {
2010
2720
  if (parts[0].length > 0) {
2011
2721
  decodeResult.remaining.text += parts[0].substring(0, 3);
2012
2722
  decodeResult.raw.flight_number = parts[0].substring(3);
2013
- decodeResult.remaining.text += "#" + parts[1].substring(0, 3);
2723
+ decodeResult.remaining.text += "#" + (parts[1].length == 5 ? parts[1].substring(0, 2) : parts[1].substring(0, 3));
2014
2724
  }
2015
- if (parts[1].substring(3, 6) === "POS" && parts[1].length !== 6 && parts[1].substring(3, 7) !== "POS/") {
2016
- decoded = processPosition2(decodeResult, parts[1].substring(6).split(","));
2725
+ const type = parts[1].length == 5 ? parts[1].substring(2, 5) : parts[1].substring(3, 6);
2726
+ if (parts[1].substring(3, 6) === "POS" && parts[1].length > 6) {
2727
+ processPosition2(decodeResult, parts[1].substring(6).split(","));
2017
2728
  }
2018
- decodeResult.raw.message_type = messageType;
2019
- return decoded;
2729
+ processMessageType(decodeResult, type);
2730
+ } else {
2731
+ decodeResult.remaining.text += messageType;
2732
+ }
2733
+ }
2734
+ function processMessageType(decodeResult, type) {
2735
+ if (type === "FPN") {
2736
+ decodeResult.formatted.description = "Flight Plan";
2737
+ } else if (type === "FTX") {
2738
+ decodeResult.formatted.description = "Free Text";
2739
+ } else if (type === "INI") {
2740
+ decodeResult.formatted.description = "Flight Plan Initial Report";
2741
+ } else if (type === "POS") {
2742
+ decodeResult.formatted.description = "Position Report";
2743
+ } else if (type === "PRG") {
2744
+ decodeResult.formatted.description = "Progress Report";
2745
+ } else {
2746
+ decodeResult.formatted.description = "Unknown H1 Message";
2020
2747
  }
2021
- decodeResult.remaining.text += messageType;
2022
- return false;
2023
2748
  }
2024
2749
  function processDC(decodeResult, data) {
2025
2750
  decodeResult.raw.message_date = data[0];
@@ -2028,13 +2753,9 @@ function processDC(decodeResult, data) {
2028
2753
  const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
2029
2754
  const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
2030
2755
  decodeResult.raw.message_timestamp = time;
2031
- } else {
2032
- return false;
2033
2756
  }
2034
- return true;
2035
2757
  }
2036
2758
  function processPS(decodeResult, data) {
2037
- let allKnownFields = true;
2038
2759
  const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2039
2760
  if (position) {
2040
2761
  decodeResult.raw.position = position;
@@ -2044,11 +2765,7 @@ function processPS(decodeResult, data) {
2044
2765
  label: "Aircraft Position",
2045
2766
  value: CoordinateUtils.coordinateString(position)
2046
2767
  });
2047
- } else {
2048
- allKnownFields = false;
2049
2768
  }
2050
- console.log("PS data.length: ", data.length);
2051
- console.log("PS data: ", data);
2052
2769
  if (data.length === 9) {
2053
2770
  processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
2054
2771
  ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
@@ -2066,11 +2783,8 @@ function processPS(decodeResult, data) {
2066
2783
  ResultFormatter.unknown(decodeResult, data[9]);
2067
2784
  ResultFormatter.unknown(decodeResult, data.slice(11).join(","));
2068
2785
  }
2069
- allKnownFields = false;
2070
- return allKnownFields;
2071
2786
  }
2072
2787
  function processPosition2(decodeResult, data) {
2073
- let allKnownFields = true;
2074
2788
  const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2075
2789
  if (position) {
2076
2790
  decodeResult.raw.position = position;
@@ -2080,11 +2794,7 @@ function processPosition2(decodeResult, data) {
2080
2794
  label: "Aircraft Position",
2081
2795
  value: CoordinateUtils.coordinateString(position)
2082
2796
  });
2083
- } else {
2084
- allKnownFields = false;
2085
2797
  }
2086
- console.log("data.length: ", data.length);
2087
- console.log("data: ", data);
2088
2798
  if (data.length >= 10) {
2089
2799
  ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2090
2800
  processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
@@ -2098,8 +2808,6 @@ function processPosition2(decodeResult, data) {
2098
2808
  ResultFormatter.unknown(decodeResult, data[12]);
2099
2809
  ResultFormatter.unknown(decodeResult, data[13]);
2100
2810
  }
2101
- allKnownFields = false;
2102
- return allKnownFields;
2103
2811
  }
2104
2812
  function processRoute(decodeResult, last, time, next, eta, then, date) {
2105
2813
  const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
@@ -2122,229 +2830,24 @@ function processRoute(decodeResult, last, time, next, eta, then, date) {
2122
2830
  });
2123
2831
  }
2124
2832
 
2125
- // lib/plugins/Label_H1_FPN.ts
2126
- var Label_H1_FPN = class extends DecoderPlugin {
2127
- name = "label-h1-fpn";
2833
+ // lib/plugins/Label_H1.ts
2834
+ var Label_H1 = class extends DecoderPlugin {
2835
+ name = "label-h1";
2128
2836
  qualifiers() {
2129
2837
  return {
2130
- labels: ["H1"],
2131
- preambles: ["FPN", "#M1BFPN"]
2838
+ labels: ["H1"]
2132
2839
  };
2133
2840
  }
2134
2841
  decode(message, options = {}) {
2135
2842
  let decodeResult = this.defaultResult();
2136
2843
  decodeResult.decoder.name = this.name;
2137
- decodeResult.formatted.description = "Flight Plan";
2138
2844
  decodeResult.message = message;
2139
2845
  decodeResult.remaining.text = "";
2140
2846
  const msg = message.text.replace(/\n|\r/g, "");
2141
- const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, msg);
2142
- decodeResult.decoded = true;
2143
- decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
2144
- if (decodeResult.formatted.items.length === 0) {
2145
- if (options?.debug) {
2146
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
2147
- }
2148
- decodeResult.remaining.text = message.text;
2149
- decodeResult.decoded = false;
2150
- decodeResult.decoder.decodeLevel = "none";
2151
- }
2152
- return decodeResult;
2153
- }
2154
- };
2155
-
2156
- // lib/plugins/Label_H1_FTX.ts
2157
- var Label_H1_FTX = class extends DecoderPlugin {
2158
- name = "label-h1-ftx";
2159
- qualifiers() {
2160
- return {
2161
- labels: ["H1"],
2162
- preambles: ["FTX", "- #MDFTX"]
2163
- };
2164
- }
2165
- decode(message, options = {}) {
2166
- let decodeResult = this.defaultResult();
2167
- decodeResult.decoder.name = this.name;
2168
- decodeResult.formatted.description = "Free Text";
2169
- decodeResult.message = message;
2170
- decodeResult.remaining.text = "";
2171
- const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
2172
- decodeResult.decoded = true;
2173
- decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
2174
- if (decodeResult.formatted.items.length === 0) {
2175
- if (options?.debug) {
2176
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
2177
- }
2178
- decodeResult.remaining.text = message.text;
2179
- decodeResult.decoded = false;
2180
- decodeResult.decoder.decodeLevel = "none";
2181
- }
2182
- return decodeResult;
2183
- }
2184
- };
2185
-
2186
- // lib/plugins/Label_H1_INI.ts
2187
- var Label_H1_INI = class extends DecoderPlugin {
2188
- // eslint-disable-line camelcase
2189
- name = "label-h1-ini";
2190
- qualifiers() {
2191
- return {
2192
- labels: ["H1"],
2193
- preambles: ["INI", "- #MDINI"]
2194
- };
2195
- }
2196
- decode(message, options = {}) {
2197
- const decodeResult = this.defaultResult();
2198
- decodeResult.decoder.name = this.name;
2199
- decodeResult.formatted.description = "Flight Plan Initial Report";
2200
- decodeResult.message = message;
2201
- decodeResult.remaining.text = "";
2202
- const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
2203
- decodeResult.decoded = true;
2204
- decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
2205
- if (decodeResult.formatted.items.length === 0) {
2206
- if (options?.debug) {
2207
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
2208
- }
2209
- decodeResult.remaining.text = message.text;
2210
- decodeResult.decoded = false;
2211
- decodeResult.decoder.decodeLevel = "none";
2212
- }
2213
- return decodeResult;
2214
- }
2215
- };
2216
-
2217
- // lib/plugins/Label_H1_OHMA.ts
2218
- var zlib = __toESM(require("minizlib"));
2219
- var Label_H1_OHMA = class extends DecoderPlugin {
2220
- name = "label-h1-ohma";
2221
- qualifiers() {
2222
- return {
2223
- labels: ["H1"],
2224
- preambles: ["OHMA", "/RTNBOCR.OHMA", "#T1B/RTNBOCR.OHMA"]
2225
- };
2226
- }
2227
- decode(message, options = {}) {
2228
- let decodeResult = this.defaultResult();
2229
- decodeResult.decoder.name = this.name;
2230
- decodeResult.formatted.description = "OHMA Message";
2231
- decodeResult.message = message;
2232
- decodeResult.remaining.text = "";
2233
- const data = message.text.split("OHMA")[1];
2234
- try {
2235
- const compressedBuffer = Buffer.from(data, "base64");
2236
- const decompress = new zlib.Inflate({ windowBits: 15 });
2237
- decompress.write(compressedBuffer);
2238
- decompress.flush(zlib.constants.Z_SYNC_FLUSH);
2239
- const result = decompress.read();
2240
- const jsonText = result.toString();
2241
- let formattedMsg;
2242
- let jsonMessage;
2243
- try {
2244
- jsonMessage = JSON.parse(jsonText).message;
2245
- } catch {
2246
- jsonMessage = jsonText;
2247
- }
2248
- try {
2249
- const ohmaMsg = JSON.parse(jsonMessage);
2250
- formattedMsg = JSON.stringify(ohmaMsg, null, 2);
2251
- } catch {
2252
- formattedMsg = jsonMessage;
2253
- }
2254
- decodeResult.decoded = true;
2255
- decodeResult.decoder.decodeLevel = "full";
2256
- decodeResult.raw.ohma = jsonText;
2257
- decodeResult.formatted.items.push({
2258
- type: "ohma",
2259
- code: "OHMA",
2260
- label: "OHMA Downlink",
2261
- value: formattedMsg
2262
- });
2263
- } catch (e) {
2264
- if (options.debug) {
2265
- console.log(`Decoder: Unknown H1 OHMA message: ${message.text}`, e);
2266
- }
2267
- decodeResult.remaining.text += message.text;
2268
- decodeResult.decoded = false;
2269
- decodeResult.decoder.decodeLevel = "none";
2270
- }
2271
- return decodeResult;
2272
- }
2273
- };
2274
-
2275
- // lib/plugins/Label_H1_POS.ts
2276
- var Label_H1_POS = class extends DecoderPlugin {
2277
- name = "label-h1-pos";
2278
- qualifiers() {
2279
- return {
2280
- labels: ["H1", "4J"],
2281
- preambles: ["POS", "#M1BPOS", "/.POS"]
2282
- //TODO - support data before #
2283
- };
2284
- }
2285
- decode(message, options = {}) {
2286
- let decodeResult = this.defaultResult();
2287
- decodeResult.decoder.name = this.name;
2288
- decodeResult.formatted.description = "Position Report";
2289
- decodeResult.message = message;
2290
- decodeResult.remaining.text = "";
2291
- const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
2292
- decodeResult.decoded = true;
2293
- decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
2847
+ const decoded = H1Helper.decodeH1Message(decodeResult, msg);
2848
+ decodeResult.decoded = decoded;
2849
+ decodeResult.decoder.decodeLevel = decodeResult.remaining.text.length === 0 ? "full" : "partial";
2294
2850
  if (decodeResult.formatted.items.length === 0) {
2295
- if (options?.debug) {
2296
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
2297
- }
2298
- decodeResult.remaining.text = message.text;
2299
- decodeResult.decoded = false;
2300
- decodeResult.decoder.decodeLevel = "none";
2301
- }
2302
- return decodeResult;
2303
- }
2304
- };
2305
-
2306
- // lib/plugins/Label_H1_WRN.ts
2307
- var Label_H1_WRN = class extends DecoderPlugin {
2308
- name = "label-h1-wrn";
2309
- qualifiers() {
2310
- return {
2311
- labels: ["H1"],
2312
- preambles: ["WRN", "#CFBWRN"]
2313
- };
2314
- }
2315
- decode(message, options = {}) {
2316
- let decodeResult = this.defaultResult();
2317
- decodeResult.decoder.name = this.name;
2318
- decodeResult.formatted.description = "Warning Message";
2319
- decodeResult.message = message;
2320
- const parts = message.text.split("/WN");
2321
- if (parts.length > 1) {
2322
- decodeResult.remaining.text = "";
2323
- const fields = parts[0].split("/");
2324
- for (let i = 1; i < fields.length; i++) {
2325
- const field = fields[i];
2326
- if (field.startsWith("PN")) {
2327
- processUnknown2(decodeResult, "/" + field);
2328
- } else {
2329
- processUnknown2(decodeResult, "/" + field);
2330
- }
2331
- }
2332
- const data = parts[1].substring(0, 20);
2333
- const msg = parts[1].substring(20);
2334
- const datetime = data.substring(0, 12);
2335
- const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
2336
- processUnknown2(decodeResult, data.substring(12));
2337
- decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
2338
- decodeResult.raw.warning_message = msg;
2339
- decodeResult.formatted.items.push({
2340
- type: "warning",
2341
- code: "WRN",
2342
- label: "Warning Message",
2343
- value: decodeResult.raw.warning_message
2344
- });
2345
- decodeResult.decoded = true;
2346
- decodeResult.decoder.decodeLevel = "partial";
2347
- } else {
2348
2851
  if (options.debug) {
2349
2852
  console.log(`Decoder: Unknown H1 message: ${message.text}`);
2350
2853
  }
@@ -2355,9 +2858,6 @@ var Label_H1_WRN = class extends DecoderPlugin {
2355
2858
  return decodeResult;
2356
2859
  }
2357
2860
  };
2358
- function processUnknown2(decodeResult, value) {
2359
- decodeResult.remaining.text += value;
2360
- }
2361
2861
 
2362
2862
  // lib/plugins/Label_HX.ts
2363
2863
  var Label_HX = class extends DecoderPlugin {
@@ -2402,7 +2902,7 @@ var Label_HX = class extends DecoderPlugin {
2402
2902
  });
2403
2903
  }
2404
2904
  if (decodeResult.decoded) {
2405
- if (decodeResult.remaining.text === "")
2905
+ if (!decodeResult.remaining.text)
2406
2906
  decodeResult.decoder.decodeLevel = "full";
2407
2907
  else
2408
2908
  decodeResult.decoder.decodeLevel = "partial";
@@ -2557,7 +3057,7 @@ var Label_QR = class extends DecoderPlugin {
2557
3057
  }
2558
3058
  ];
2559
3059
  decodeResult.decoded = true;
2560
- if (decodeResult.remaining.text === "")
3060
+ if (!decodeResult.remaining.text)
2561
3061
  decodeResult.decoder.decodeLevel = "full";
2562
3062
  else
2563
3063
  decodeResult.decoder.decodeLevel = "partial";
@@ -2602,7 +3102,7 @@ var Label_QP = class extends DecoderPlugin {
2602
3102
  }
2603
3103
  ];
2604
3104
  decodeResult.decoded = true;
2605
- if (decodeResult.remaining.text === "")
3105
+ if (!decodeResult.remaining.text)
2606
3106
  decodeResult.decoder.decodeLevel = "full";
2607
3107
  else
2608
3108
  decodeResult.decoder.decodeLevel = "partial";
@@ -2647,7 +3147,7 @@ var Label_QS = class extends DecoderPlugin {
2647
3147
  }
2648
3148
  ];
2649
3149
  decodeResult.decoded = true;
2650
- if (decodeResult.remaining.text === "")
3150
+ if (!decodeResult.remaining.text)
2651
3151
  decodeResult.decoder.decodeLevel = "full";
2652
3152
  else
2653
3153
  decodeResult.decoder.decodeLevel = "partial";
@@ -2709,7 +3209,7 @@ var Label_QQ = class extends DecoderPlugin {
2709
3209
  });
2710
3210
  }
2711
3211
  decodeResult.decoded = true;
2712
- if (decodeResult.remaining.text === "")
3212
+ if (!decodeResult.remaining.text)
2713
3213
  decodeResult.decoder.decodeLevel = "full";
2714
3214
  else
2715
3215
  decodeResult.decoder.decodeLevel = "partial";
@@ -3529,32 +4029,38 @@ var MessageDecoder = class {
3529
4029
  this.plugins = [];
3530
4030
  this.debug = false;
3531
4031
  this.registerPlugin(new Label_ColonComma(this));
3532
- this.registerPlugin(new Label_5Z(this));
4032
+ this.registerPlugin(new Label_5Z_Slash(this));
3533
4033
  this.registerPlugin(new Label_10_LDR(this));
3534
4034
  this.registerPlugin(new Label_10_POS(this));
3535
4035
  this.registerPlugin(new Label_10_Slash(this));
3536
4036
  this.registerPlugin(new Label_12_N_Space(this));
4037
+ this.registerPlugin(new Label_13Through18_Slash(this));
3537
4038
  this.registerPlugin(new Label_15(this));
3538
4039
  this.registerPlugin(new Label_15_FST(this));
3539
4040
  this.registerPlugin(new Label_16_N_Space(this));
3540
4041
  this.registerPlugin(new Label_20_POS(this));
3541
4042
  this.registerPlugin(new Label_21_POS(this));
4043
+ this.registerPlugin(new Label_24_Slash(this));
3542
4044
  this.registerPlugin(new Label_30_Slash_EA(this));
3543
4045
  this.registerPlugin(new Label_44_ETA(this));
3544
4046
  this.registerPlugin(new Label_44_IN(this));
3545
4047
  this.registerPlugin(new Label_44_OFF(this));
3546
4048
  this.registerPlugin(new Label_44_ON(this));
3547
4049
  this.registerPlugin(new Label_44_POS(this));
4050
+ this.registerPlugin(new Label_4A(this));
4051
+ this.registerPlugin(new Label_4A_01(this));
4052
+ this.registerPlugin(new Label_4A_DIS(this));
4053
+ this.registerPlugin(new Label_4A_DOOR(this));
4054
+ this.registerPlugin(new Label_4A_Slash_01(this));
4055
+ this.registerPlugin(new Label_4N(this));
3548
4056
  this.registerPlugin(new Label_B6_Forwardslash(this));
3549
- this.registerPlugin(new Label_H1_FPN(this));
3550
4057
  this.registerPlugin(new Label_H1_FLR(this));
3551
- this.registerPlugin(new Label_H1_FTX(this));
3552
- this.registerPlugin(new Label_H1_INI(this));
3553
4058
  this.registerPlugin(new Label_H1_OHMA(this));
3554
- this.registerPlugin(new Label_H1_POS(this));
3555
4059
  this.registerPlugin(new Label_H1_WRN(this));
4060
+ this.registerPlugin(new Label_H1(this));
3556
4061
  this.registerPlugin(new Label_HX(this));
3557
4062
  this.registerPlugin(new Label_80(this));
4063
+ this.registerPlugin(new Label_83(this));
3558
4064
  this.registerPlugin(new Label_8E(this));
3559
4065
  this.registerPlugin(new Label_1M_Slash(this));
3560
4066
  this.registerPlugin(new Label_SQ(this));
@@ -3599,29 +4105,30 @@ var MessageDecoder = class {
3599
4105
  console.log("Usable plugins");
3600
4106
  console.log(usablePlugins);
3601
4107
  }
3602
- let result;
3603
- if (usablePlugins.length > 0) {
3604
- const plugin = usablePlugins[0];
4108
+ let result = {
4109
+ decoded: false,
4110
+ error: "No known decoder plugin for this message",
4111
+ decoder: {
4112
+ name: "none",
4113
+ type: "none",
4114
+ decodeLevel: "none"
4115
+ },
4116
+ message,
4117
+ remaining: {
4118
+ text: message.text
4119
+ },
4120
+ raw: {},
4121
+ formatted: {
4122
+ description: "Not Decoded",
4123
+ items: []
4124
+ }
4125
+ };
4126
+ for (let i = 0; i < usablePlugins.length; i++) {
4127
+ const plugin = usablePlugins[i];
3605
4128
  result = plugin.decode(message);
3606
- } else {
3607
- result = {
3608
- decoded: false,
3609
- error: "No known decoder plugin for this message",
3610
- decoder: {
3611
- name: "none",
3612
- type: "none",
3613
- decodeLevel: "none"
3614
- },
3615
- message,
3616
- remaining: {
3617
- text: message.text
3618
- },
3619
- raw: {},
3620
- formatted: {
3621
- description: "Not Decoded",
3622
- items: []
3623
- }
3624
- };
4129
+ if (result.decoded) {
4130
+ break;
4131
+ }
3625
4132
  }
3626
4133
  if (options.debug) {
3627
4134
  console.log("Result");