@airframes/acars-decoder 1.6.11 → 1.6.13

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;
@@ -98,7 +166,7 @@ var DecoderPlugin = class {
98
166
  };
99
167
 
100
168
  // lib/utils/coordinate_utils.ts
101
- var CoordinateUtils = class {
169
+ var CoordinateUtils = class _CoordinateUtils {
102
170
  /**
103
171
  * Decode a string of coordinates into an object with latitude and longitude in millidegrees
104
172
  * @param stringCoords - The string of coordinates to decode
@@ -115,8 +183,8 @@ var CoordinateUtils = class {
115
183
  longitudeChars = stringCoords.substring(8, 14);
116
184
  }
117
185
  if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
118
- results.latitude = Number(stringCoords.substring(1, 6)) / 1e3 * (firstChar === "S" ? -1 : 1);
119
- results.longitude = Number(longitudeChars) / 1e3 * (middleChar === "W" ? -1 : 1);
186
+ results.latitude = Number(stringCoords.substring(1, 6)) / 1e3 * _CoordinateUtils.getDirection(firstChar);
187
+ results.longitude = Number(longitudeChars) / 1e3 * _CoordinateUtils.getDirection(middleChar);
120
188
  } else {
121
189
  return;
122
190
  }
@@ -142,8 +210,8 @@ var CoordinateUtils = class {
142
210
  const lonDeg = Math.trunc(Number(longitudeChars) / 1e3);
143
211
  const lonMin = Number(longitudeChars) % 1e3 / 10;
144
212
  if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
145
- results.latitude = (latDeg + latMin / 60) * (firstChar === "S" ? -1 : 1);
146
- results.longitude = (lonDeg + lonMin / 60) * (middleChar === "W" ? -1 : 1);
213
+ results.latitude = (latDeg + latMin / 60) * _CoordinateUtils.getDirection(firstChar);
214
+ results.longitude = (lonDeg + lonMin / 60) * _CoordinateUtils.getDirection(middleChar);
147
215
  } else {
148
216
  return;
149
217
  }
@@ -167,9 +235,137 @@ var CoordinateUtils = class {
167
235
  }
168
236
  };
169
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
+ }
317
+ };
318
+
170
319
  // lib/utils/result_formatter.ts
171
320
  var ResultFormatter = class {
321
+ static route(decodeResult, route) {
322
+ decodeResult.raw.route = route;
323
+ decodeResult.formatted.items.push({
324
+ type: "aircraft_route",
325
+ code: "ROUTE",
326
+ label: "Aircraft Route",
327
+ value: RouteUtils.routeToString(route)
328
+ });
329
+ }
330
+ static state_change(decodeResult, from, to) {
331
+ decodeResult.raw.state_change = {
332
+ from,
333
+ to
334
+ };
335
+ from = RouteUtils.formatFlightState(from);
336
+ to = RouteUtils.formatFlightState(to);
337
+ decodeResult.formatted.items.push({
338
+ type: "state_change",
339
+ code: "STATE_CHANGE",
340
+ label: "State Change",
341
+ value: `${from} -> ${to}`
342
+ });
343
+ }
344
+ static freetext(decodeResult, value) {
345
+ decodeResult.raw.freetext = value;
346
+ decodeResult.formatted.items.push({
347
+ type: "freetext",
348
+ code: "FREE_TEXT",
349
+ label: "Free Text",
350
+ value
351
+ });
352
+ }
353
+ static door_event(decodeResult, name, state) {
354
+ decodeResult.raw.door_event = {
355
+ door: name,
356
+ state
357
+ };
358
+ decodeResult.formatted.items.push({
359
+ type: "door_event",
360
+ code: "DOOR",
361
+ label: "Door Event",
362
+ value: `${name} ${state}`
363
+ });
364
+ }
172
365
  static position(decodeResult, value) {
366
+ if (!value || isNaN(value.latitude) || isNaN(value.longitude)) {
367
+ return;
368
+ }
173
369
  decodeResult.raw.position = value;
174
370
  decodeResult.formatted.items.push({
175
371
  type: "aircraft_position",
@@ -189,16 +385,41 @@ var ResultFormatter = class {
189
385
  }
190
386
  static flightNumber(decodeResult, value) {
191
387
  decodeResult.raw.flight_number = value;
388
+ decodeResult.formatted.items.push({
389
+ type: "flight_number",
390
+ code: "FLIGHT",
391
+ label: "Flight Number",
392
+ value: decodeResult.raw.flight_number
393
+ });
192
394
  }
193
- static departureAirport(decodeResult, value) {
194
- decodeResult.raw.departure_icao = value;
395
+ static callsign(decodeResult, value) {
396
+ decodeResult.raw.callsign = value;
195
397
  decodeResult.formatted.items.push({
196
- type: "origin",
197
- code: "ORG",
198
- label: "Origin",
199
- value: decodeResult.raw.departure_icao
398
+ type: "callsign",
399
+ code: "CALLSIGN",
400
+ label: "Callsign",
401
+ value: decodeResult.raw.callsign
200
402
  });
201
403
  }
404
+ static departureAirport(decodeResult, value, type = "ICAO") {
405
+ if (type === "ICAO") {
406
+ decodeResult.raw.departure_icao = value;
407
+ decodeResult.formatted.items.push({
408
+ type: "icao",
409
+ code: "ORG",
410
+ label: "Origin",
411
+ value
412
+ });
413
+ } else {
414
+ decodeResult.raw.departure_iata = value;
415
+ decodeResult.formatted.items.push({
416
+ type: "iata",
417
+ code: "ORG",
418
+ label: "Origin",
419
+ value
420
+ });
421
+ }
422
+ }
202
423
  static departureRunway(decodeResult, value) {
203
424
  decodeResult.raw.departure_runway = value;
204
425
  decodeResult.formatted.items.push({
@@ -208,33 +429,52 @@ var ResultFormatter = class {
208
429
  value: decodeResult.raw.departure_runway
209
430
  });
210
431
  }
211
- static arrivalAirport(decodeResult, value) {
212
- decodeResult.raw.arrival_icao = value;
213
- decodeResult.formatted.items.push({
214
- type: "destination",
215
- code: "DST",
216
- label: "Destination",
217
- value: decodeResult.raw.arrival_icao
218
- });
432
+ static arrivalAirport(decodeResult, value, type = "ICAO") {
433
+ if (type === "ICAO") {
434
+ decodeResult.raw.arrival_icao = value;
435
+ decodeResult.formatted.items.push({
436
+ type: "icao",
437
+ code: "DST",
438
+ label: "Destination",
439
+ value
440
+ });
441
+ } else {
442
+ decodeResult.raw.arrival_iata = value;
443
+ decodeResult.formatted.items.push({
444
+ type: "iata",
445
+ code: "DST",
446
+ label: "Destination",
447
+ value
448
+ });
449
+ }
219
450
  }
220
451
  static alternateAirport(decodeResult, value) {
221
452
  decodeResult.raw.alternate_icao = value;
222
453
  decodeResult.formatted.items.push({
223
- type: "destination",
454
+ type: "icao",
224
455
  code: "ALT_DST",
225
456
  label: "Alternate Destination",
226
457
  value: decodeResult.raw.alternate_icao
227
458
  });
228
459
  }
229
- // FIXME - make seconds since midnight for time of day
230
- static eta(decodeResult, value) {
231
- decodeResult.raw.eta_time = value;
232
- decodeResult.formatted.items.push({
233
- type: "eta",
234
- code: "ETA",
235
- label: "Estimated Time of Arrival",
236
- value: value.substring(0, 2) + ":" + value.substring(2, 4) + ":" + value.substring(4, 6)
237
- });
460
+ static eta(decodeResult, time, type = "tod") {
461
+ if (type === "tod") {
462
+ decodeResult.raw.eta_time = time;
463
+ decodeResult.formatted.items.push({
464
+ type: "time_of_day",
465
+ code: "ETA",
466
+ label: "Estimated Time of Arrival",
467
+ value: DateTimeUtils.timestampToString(time, "tod")
468
+ });
469
+ } else {
470
+ decodeResult.raw.eta_date = time;
471
+ decodeResult.formatted.items.push({
472
+ type: "epoch",
473
+ code: "ETA",
474
+ label: "Estimated Time of Arrival",
475
+ value: DateTimeUtils.timestampToString(time, "epoch")
476
+ });
477
+ }
238
478
  }
239
479
  static arrivalRunway(decodeResult, value) {
240
480
  decodeResult.raw.arrival_runway = value;
@@ -291,12 +531,12 @@ var ResultFormatter = class {
291
531
  });
292
532
  }
293
533
  static temperature(decodeResult, value) {
294
- decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
534
+ decodeResult.raw.outside_air_temperature = Number(value.replace("M", "-").replace("P", "+"));
295
535
  decodeResult.formatted.items.push({
296
536
  type: "outside_air_temperature",
297
537
  code: "OATEMP",
298
538
  label: "Outside Air Temperature (C)",
299
- value: `${decodeResult.raw.outside_air_temperature}`
539
+ value: `${decodeResult.raw.outside_air_temperature} degrees`
300
540
  });
301
541
  }
302
542
  static heading(decodeResult, value) {
@@ -319,52 +559,99 @@ var ResultFormatter = class {
319
559
  }
320
560
  static out(decodeResult, time) {
321
561
  decodeResult.raw.out_time = time;
322
- const date = new Date(time * 1e3);
323
562
  decodeResult.formatted.items.push({
324
563
  type: "time_of_day",
325
564
  code: "OUT",
326
565
  label: "Out of Gate Time",
327
- value: date.toISOString().slice(11, 19)
566
+ value: DateTimeUtils.timestampToString(time, "tod")
328
567
  });
329
568
  }
330
569
  static off(decodeResult, time) {
331
570
  decodeResult.raw.off_time = time;
332
- const date = new Date(time * 1e3);
333
571
  decodeResult.formatted.items.push({
334
572
  type: "time_of_day",
335
573
  code: "OFF",
336
574
  label: "Takeoff Time",
337
- value: date.toISOString().slice(11, 19)
575
+ value: DateTimeUtils.timestampToString(time, "tod")
338
576
  });
339
577
  }
340
578
  static on(decodeResult, time) {
341
579
  decodeResult.raw.on_time = time;
342
- const date = new Date(time * 1e3);
343
580
  decodeResult.formatted.items.push({
344
581
  type: "time_of_day",
345
582
  code: "ON",
346
583
  label: "Landing Time",
347
- value: date.toISOString().slice(11, 19)
584
+ value: DateTimeUtils.timestampToString(time, "tod")
348
585
  });
349
586
  }
350
587
  static in(decodeResult, time) {
351
588
  decodeResult.raw.in_time = time;
352
- const date = new Date(time * 1e3);
353
589
  decodeResult.formatted.items.push({
354
590
  type: "time_of_day",
355
591
  code: "IN",
356
592
  label: "In Gate Time",
357
- value: date.toISOString().slice(11, 19)
593
+ value: DateTimeUtils.timestampToString(time, "tod")
594
+ });
595
+ }
596
+ static time_of_day(decodeResult, time) {
597
+ decodeResult.raw.time_of_day = time;
598
+ decodeResult.formatted.items.push({
599
+ type: "time_of_day",
600
+ code: "MSG_TOD",
601
+ label: "Message Timestamp",
602
+ value: DateTimeUtils.timestampToString(time, "tod")
603
+ });
604
+ }
605
+ static day(decodeResult, day) {
606
+ decodeResult.raw.day_of_month = day;
607
+ decodeResult.formatted.items.push({
608
+ type: "day_of_month",
609
+ code: "MSG_DAY",
610
+ label: "Day of Month",
611
+ value: `${day}`
612
+ });
613
+ }
614
+ static departureDay(decodeResult, day) {
615
+ decodeResult.raw.departure_day_of_month = day;
616
+ decodeResult.formatted.items.push({
617
+ type: "day_of_month",
618
+ code: "DEP_DAY",
619
+ label: "Departure Day",
620
+ value: `${day}`
621
+ });
622
+ }
623
+ static arrivalDay(decodeResult, day) {
624
+ decodeResult.raw.arrival_day_of_month = day;
625
+ decodeResult.formatted.items.push({
626
+ type: "day_of_month",
627
+ code: "ARR_DAY",
628
+ label: "Arrival Day",
629
+ value: `${day}`
630
+ });
631
+ }
632
+ static text(decodeResult, text) {
633
+ decodeResult.raw.text = text;
634
+ decodeResult.formatted.items.push({
635
+ type: "text",
636
+ code: "TEXT",
637
+ label: "Text Message",
638
+ value: text
358
639
  });
359
640
  }
360
- static unknown(decodeResult, value) {
361
- decodeResult.remaining.text += "," + value;
641
+ static unknown(decodeResult, value, sep = ",") {
642
+ if (!decodeResult.remaining.text)
643
+ decodeResult.remaining.text = value;
644
+ else
645
+ decodeResult.remaining.text += sep + value;
646
+ }
647
+ static unknownArr(decodeResult, value, sep = ",") {
648
+ this.unknown(decodeResult, value.join(sep), sep);
362
649
  }
363
650
  };
364
651
 
365
- // lib/plugins/Label_5Z.ts
366
- var Label_5Z = class extends DecoderPlugin {
367
- name = "label-5z";
652
+ // lib/plugins/Label_5Z_Slash.ts
653
+ var Label_5Z_Slash = class extends DecoderPlugin {
654
+ name = "label-5z-slash";
368
655
  descriptions = {
369
656
  B1: "Request Weight and Balance",
370
657
  B3: "Request Departure Clearance",
@@ -382,6 +669,7 @@ var Label_5Z = class extends DecoderPlugin {
382
669
  D6: "From-To + Date",
383
670
  D7: "From-To + Alternate + Time",
384
671
  EO: "In Range",
672
+ ET: "Expected Time",
385
673
  PW: "Position Weather",
386
674
  RL: "Request Release",
387
675
  R3: "Request HOWGOZIT Message",
@@ -392,53 +680,87 @@ var Label_5Z = class extends DecoderPlugin {
392
680
  };
393
681
  qualifiers() {
394
682
  return {
395
- labels: ["5Z"]
683
+ labels: ["5Z"],
684
+ preambles: ["/"]
396
685
  };
397
686
  }
398
687
  decode(message, options = {}) {
399
688
  const decodeResult = this.defaultResult();
400
689
  decodeResult.decoder.name = this.name;
401
690
  decodeResult.formatted.description = "Airline Designated Downlink";
402
- const uaRegex = /^\/(?<type>\w+) (?<remainder>.+)/;
403
- let results = message.text.match(uaRegex);
404
- if (results && results.length >= 2) {
405
- const type = results.groups.type.split("/")[0];
406
- const { remainder } = results.groups;
407
- const typeDescription = this.descriptions[type] ? this.descriptions[type] : "Unknown";
691
+ const lines = message.text.split("\r\n");
692
+ if (lines[0] === "/TXT") {
693
+ ResultFormatter.text(decodeResult, lines.slice(1).join("\r\n"));
694
+ decodeResult.decoded = true;
695
+ decodeResult.decoder.decodeLevel = "full";
696
+ return decodeResult;
697
+ }
698
+ const data = lines[0].split("/");
699
+ const header = data[1].split(" ");
700
+ const type = header[0];
701
+ const typeDescription = this.descriptions[type];
702
+ if (typeDescription) {
408
703
  decodeResult.raw.airline = "United Airlines";
409
704
  decodeResult.formatted.items.push({
410
705
  type: "airline",
706
+ code: "AIRLINE",
411
707
  label: "Airline",
412
708
  value: "United Airlines"
413
709
  });
414
710
  decodeResult.raw.message_type = type;
415
711
  decodeResult.formatted.items.push({
416
712
  type: "message_type",
713
+ code: "MSG_TYPE",
417
714
  label: "Message Type",
418
715
  value: `${typeDescription} (${type})`
419
716
  });
420
- if (type === "B3") {
421
- const rdcRegex = /^(?<from>\w\w\w)(?<to>\w\w\w) (?<unknown1>\d\d) R(?<runway>.+) G(?<unknown2>.+)$/;
422
- results = remainder.match(rdcRegex);
423
- if (results) {
424
- ResultFormatter.departureAirport(decodeResult, results.groups.from);
425
- ResultFormatter.arrivalAirport(decodeResult, results.groups.to);
426
- ResultFormatter.arrivalRunway(decodeResult, results.groups.runway);
427
- } else {
428
- if (options.debug) {
429
- console.log(`Decoder: Unkown 5Z RDC format: ${remainder}`);
430
- }
717
+ if (type === "B3" && data[1] === "B3 TO DATA REQ ") {
718
+ const info = data[2].split(" ");
719
+ ResultFormatter.departureAirport(decodeResult, info[1]);
720
+ ResultFormatter.arrivalAirport(decodeResult, info[2]);
721
+ decodeResult.raw.day_of_month = Number(info[3]);
722
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
723
+ ResultFormatter.arrivalRunway(decodeResult, info[5].slice(1));
724
+ ResultFormatter.unknownArr(decodeResult, data.slice(3), "/");
725
+ } else if (type === "B3") {
726
+ ResultFormatter.departureAirport(decodeResult, header[1].substring(0, 3), "IATA");
727
+ ResultFormatter.arrivalAirport(decodeResult, header[1].substring(3), "IATA");
728
+ decodeResult.raw.day_of_month = Number(header[2]);
729
+ ResultFormatter.arrivalRunway(decodeResult, header[3].slice(1));
730
+ if (header.length > 4) {
731
+ ResultFormatter.unknownArr(decodeResult, header.slice(4), "/");
431
732
  }
733
+ } else if (type === "C3" && data[1] === "C3 GATE REQ ") {
734
+ const info = data[2].split(" ");
735
+ ResultFormatter.departureAirport(decodeResult, info[1]);
736
+ ResultFormatter.arrivalAirport(decodeResult, info[2]);
737
+ decodeResult.raw.day_of_month = Number(info[3]);
738
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
739
+ ResultFormatter.unknownArr(decodeResult, info.slice(5), " ");
740
+ } else if (type === "C3") {
741
+ ResultFormatter.departureAirport(decodeResult, header[1].substring(0, 3), "IATA");
742
+ ResultFormatter.arrivalAirport(decodeResult, header[1].substring(3), "IATA");
743
+ } else if (type === "ET") {
744
+ const airports = data[2].split(" ");
745
+ ResultFormatter.departureAirport(decodeResult, airports[1]);
746
+ ResultFormatter.arrivalAirport(decodeResult, airports[2]);
747
+ decodeResult.raw.day_of_month = Number(airports[3]);
748
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(airports[4]));
749
+ const estimates = data[3].split(" ");
750
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(estimates[1] + "00"));
751
+ ResultFormatter.unknown(decodeResult, estimates[2]);
432
752
  } else {
433
- decodeResult.remaining.text = remainder;
753
+ if (options.debug) {
754
+ console.log(`Decoder: Unkown 5Z RDC format: ${message.text}`);
755
+ }
434
756
  }
435
757
  decodeResult.decoded = true;
436
- decodeResult.decoder.decodeLevel = "partial";
758
+ decodeResult.decoder.decodeLevel = decodeResult.remaining.text ? "partial" : "full";
437
759
  } else {
438
760
  if (options.debug) {
439
761
  console.log(`Decoder: Unknown 5Z message: ${message.text}`);
440
762
  }
441
- decodeResult.remaining.text = message.text;
763
+ ResultFormatter.unknown(decodeResult, message.text);
442
764
  decodeResult.decoded = false;
443
765
  decodeResult.decoder.decodeLevel = "none";
444
766
  }
@@ -466,7 +788,7 @@ var Label_10_LDR = class extends DecoderPlugin {
466
788
  if (options.debug) {
467
789
  console.log(`Decoder: Unknown 10 message: ${message.text}`);
468
790
  }
469
- decodeResult.remaining.text = message.text;
791
+ ResultFormatter.unknown(decodeResult, message.text);
470
792
  decodeResult.decoded = false;
471
793
  decodeResult.decoder.decodeLevel = "none";
472
794
  return decodeResult;
@@ -487,7 +809,7 @@ var Label_10_LDR = class extends DecoderPlugin {
487
809
  if (altRwy != "") {
488
810
  ResultFormatter.alternateRunway(decodeResult, altRwy);
489
811
  }
490
- decodeResult.remaining.text = [...parts.slice(0, 5), ...parts.slice(15)].join(",");
812
+ ResultFormatter.unknownArr(decodeResult, [...parts.slice(0, 5), ...parts.slice(15)]);
491
813
  decodeResult.decoded = true;
492
814
  decodeResult.decoder.decodeLevel = "partial";
493
815
  return decodeResult;
@@ -514,7 +836,7 @@ var Label_10_POS = class extends DecoderPlugin {
514
836
  if (options.debug) {
515
837
  console.log(`Decoder: Unknown 10 message: ${message.text}`);
516
838
  }
517
- decodeResult.remaining.text = message.text;
839
+ ResultFormatter.unknown(decodeResult, message.text);
518
840
  decodeResult.decoded = false;
519
841
  decodeResult.decoder.decodeLevel = "none";
520
842
  return decodeResult;
@@ -527,160 +849,37 @@ var Label_10_POS = class extends DecoderPlugin {
527
849
  };
528
850
  ResultFormatter.position(decodeResult, position);
529
851
  ResultFormatter.altitude(decodeResult, Number(parts[7]));
530
- decodeResult.remaining.text = [parts[0], ...parts.slice(3, 7), ...parts.slice(8)].join(",");
852
+ ResultFormatter.unknownArr(decodeResult, [parts[0], ...parts.slice(3, 7), ...parts.slice(8)]);
531
853
  decodeResult.decoded = true;
532
854
  decodeResult.decoder.decodeLevel = "partial";
533
855
  return decodeResult;
534
856
  }
535
857
  };
536
858
 
537
- // lib/DateTimeUtils.ts
538
- var DateTimeUtils = class {
539
- // Expects a four digit UTC time string (HHMM)
540
- static UTCToString(UTCString) {
541
- let utcDate = /* @__PURE__ */ new Date();
542
- utcDate.setUTCHours(+UTCString.substr(0, 2), +UTCString.substr(2, 2), 0);
543
- return utcDate.toTimeString();
859
+ // lib/plugins/Label_10_Slash.ts
860
+ var Label_10_Slash = class extends DecoderPlugin {
861
+ // eslint-disable-line camelcase
862
+ name = "label-10-slash";
863
+ qualifiers() {
864
+ return {
865
+ labels: ["10"],
866
+ preambles: ["/"]
867
+ };
544
868
  }
545
- // Expects a six digit date string and a four digit UTC time string
546
- // (DDMMYY) (HHMM)
547
- static UTCDateTimeToString(dateString, timeString) {
548
- let utcDate = /* @__PURE__ */ new Date();
549
- utcDate.setUTCDate(+dateString.substr(0, 2));
550
- utcDate.setUTCMonth(+dateString.substr(2, 2));
551
- if (dateString.length === 6) {
552
- utcDate.setUTCFullYear(2e3 + +dateString.substr(4, 2));
553
- }
554
- if (timeString.length === 6) {
555
- utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), +timeString.substr(4, 2));
556
- } else {
557
- utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), 0);
558
- }
559
- return utcDate.toUTCString();
560
- }
561
- /**
562
- *
563
- * @param time HHMMSS
564
- * @returns seconds since midnight
565
- */
566
- static convertHHMMSSToTod(time) {
567
- const h = Number(time.substring(0, 2));
568
- const m = Number(time.substring(2, 4));
569
- const s = Number(time.substring(4, 6));
570
- const tod = h * 3600 + m * 60 + s;
571
- return tod;
572
- }
573
- /**
574
- *
575
- * @param time HHMMSS
576
- * @param date MMDDYY or MMDDYYYY
577
- * @returns seconds since epoch
578
- */
579
- static convertDateTimeToEpoch(time, date) {
580
- if (date.length === 6) {
581
- date = date.substring(0, 4) + `20${date.substring(4, 6)}`;
582
- }
583
- 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`;
584
- const millis = Date.parse(timestamp);
585
- return millis / 1e3;
586
- }
587
- };
588
-
589
- // lib/utils/route_utils.ts
590
- var RouteUtils = class _RouteUtils {
591
- static routeToString(route) {
592
- let str = "";
593
- if (route.name) {
594
- str += route.name;
595
- }
596
- if (route.runway) {
597
- str += `(${route.runway})`;
598
- }
599
- if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
600
- str += " starting at ";
601
- } else if (str.length !== 0 && route.waypoints) {
602
- str += ": ";
603
- }
604
- if (route.waypoints) {
605
- str += _RouteUtils.waypointsToString(route.waypoints);
606
- }
607
- return str;
608
- }
609
- static waypointToString(waypoint) {
610
- let s = waypoint.name;
611
- if (waypoint.latitude && waypoint.longitude) {
612
- s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
613
- }
614
- if (waypoint.offset) {
615
- s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
616
- }
617
- if (waypoint.time && waypoint.timeFormat) {
618
- s += `@${_RouteUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
619
- }
620
- return s;
621
- }
622
- static getWaypoint(leg) {
623
- const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
624
- if (regex?.length == 4) {
625
- return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
626
- }
627
- const waypoint = leg.split(",");
628
- if (waypoint.length == 2) {
629
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
630
- if (position) {
631
- return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
632
- }
633
- }
634
- if (leg.length == 13 || leg.length == 14) {
635
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
636
- const name = waypoint.length == 2 ? waypoint[0] : "";
637
- if (position) {
638
- return { name, latitude: position.latitude, longitude: position.longitude };
639
- }
640
- }
641
- return { name: leg };
642
- }
643
- // move out if we want public
644
- static timestampToString(time, format) {
645
- const date = new Date(time * 1e3);
646
- if (format == "tod") {
647
- return date.toISOString().slice(11, 19);
648
- }
649
- return date.toISOString().slice(0, -5) + "Z";
650
- }
651
- static waypointsToString(waypoints) {
652
- let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
653
- if (str.startsWith(" > ")) {
654
- str = ">>" + str.slice(2);
655
- }
656
- return str;
657
- }
658
- };
659
-
660
- // lib/plugins/Label_10_Slash.ts
661
- var Label_10_Slash = class extends DecoderPlugin {
662
- // eslint-disable-line camelcase
663
- name = "label-10-slash";
664
- qualifiers() {
665
- return {
666
- labels: ["10"],
667
- preambles: ["/"]
668
- };
669
- }
670
- decode(message, options = {}) {
671
- const decodeResult = this.defaultResult();
672
- decodeResult.decoder.name = this.name;
673
- decodeResult.formatted.description = "Position Report";
674
- decodeResult.message = message;
675
- const parts = message.text.split("/");
676
- if (parts.length < 17) {
677
- if (options.debug) {
678
- console.log(`Decoder: Unknown 10 message: ${message.text}`);
679
- }
680
- decodeResult.remaining.text = message.text;
681
- decodeResult.decoded = false;
682
- decodeResult.decoder.decodeLevel = "none";
683
- return decodeResult;
869
+ decode(message, options = {}) {
870
+ const decodeResult = this.defaultResult();
871
+ decodeResult.decoder.name = this.name;
872
+ decodeResult.formatted.description = "Position Report";
873
+ decodeResult.message = message;
874
+ const parts = message.text.split("/");
875
+ if (parts.length < 17) {
876
+ if (options.debug) {
877
+ console.log(`Decoder: Unknown 10 message: ${message.text}`);
878
+ }
879
+ ResultFormatter.unknown(decodeResult, message.text);
880
+ decodeResult.decoded = false;
881
+ decodeResult.decoder.decodeLevel = "none";
882
+ return decodeResult;
684
883
  }
685
884
  const lat = parts[1];
686
885
  const lon = parts[2];
@@ -692,7 +891,7 @@ var Label_10_Slash = class extends DecoderPlugin {
692
891
  ResultFormatter.heading(decodeResult, Number(parts[5]));
693
892
  ResultFormatter.altitude(decodeResult, 100 * Number(parts[6]));
694
893
  ResultFormatter.arrivalAirport(decodeResult, parts[7]);
695
- ResultFormatter.eta(decodeResult, parts[8] + "00");
894
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[8] + "00"));
696
895
  const waypoints = [{
697
896
  name: parts[11]
698
897
  }, {
@@ -704,17 +903,11 @@ var Label_10_Slash = class extends DecoderPlugin {
704
903
  time: DateTimeUtils.convertHHMMSSToTod(parts[15] + "00"),
705
904
  timeFormat: "tod"
706
905
  }];
707
- decodeResult.raw.route = { waypoints };
708
- decodeResult.formatted.items.push({
709
- type: "aircraft_route",
710
- code: "ROUTE",
711
- label: "Aircraft Route",
712
- value: RouteUtils.routeToString(decodeResult.raw.route)
713
- });
906
+ ResultFormatter.route(decodeResult, { waypoints });
714
907
  if (parts[16]) {
715
908
  ResultFormatter.departureAirport(decodeResult, parts[16]);
716
909
  }
717
- decodeResult.remaining.text = [parts[3], parts[4], ...parts.slice(9, 11), ...parts.slice(17)].join("/");
910
+ ResultFormatter.unknownArr(decodeResult, [parts[3], parts[4], ...parts.slice(9, 11), ...parts.slice(17)], "/");
718
911
  decodeResult.decoded = true;
719
912
  decodeResult.decoder.decodeLevel = "partial";
720
913
  return decodeResult;
@@ -736,35 +929,29 @@ var Label_12_N_Space = class extends DecoderPlugin {
736
929
  decodeResult.formatted.description = "Position Report";
737
930
  decodeResult.message = message;
738
931
  const variant1Regex = /^(?<lat>[NS])\s(?<lat_coord>.*),(?<long>[EW])\s*(?<long_coord>.*),(?<alt>.*),(?<unkwn1>.*),\s*(?<unkwn2>.*),.(?<airframe>.*),(?<unkwn3>.*)$/;
739
- let results;
740
- if (results = message.text.match(variant1Regex)) {
932
+ let results = message.text.match(variant1Regex);
933
+ if (results?.groups) {
741
934
  if (options.debug) {
742
935
  console.log(`Label 12 N : results`);
743
936
  console.log(results);
744
937
  }
745
- decodeResult.raw.position = {
938
+ ResultFormatter.position(decodeResult, {
746
939
  latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
747
940
  longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
748
- };
749
- const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
750
- decodeResult.formatted.items.push({
751
- type: "aircraft_position",
752
- code: "POS",
753
- label: "Aircraft Position",
754
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
755
941
  });
942
+ const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
756
943
  ResultFormatter.altitude(decodeResult, altitude);
757
- decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}, ${results.groups.unkwn3}`;
944
+ ResultFormatter.unknownArr(decodeResult, [results.groups.unkwn1, results.groups.unkwn2, results.groups.unkwn3]);
758
945
  decodeResult.decoded = true;
759
946
  decodeResult.decoder.decodeLevel = "partial";
760
- } else {
761
- if (options.debug) {
762
- console.log(`Decoder: Unknown 12 message: ${message.text}`);
763
- }
764
- decodeResult.remaining.text = message.text;
765
- decodeResult.decoded = false;
766
- decodeResult.decoder.decodeLevel = "none";
947
+ return decodeResult;
767
948
  }
949
+ if (options.debug) {
950
+ console.log(`Decoder: Unknown 12 message: ${message.text}`);
951
+ }
952
+ ResultFormatter.unknown(decodeResult, message.text);
953
+ decodeResult.decoded = false;
954
+ decodeResult.decoder.decodeLevel = "none";
768
955
  return decodeResult;
769
956
  }
770
957
  };
@@ -791,12 +978,11 @@ var Label_13Through18_Slash = class extends DecoderPlugin {
791
978
  if (options?.debug) {
792
979
  console.log(`Decoder: Unknown OOOI message: ${message.text}`);
793
980
  }
794
- decodeResult.remaining.text = message.text;
981
+ ResultFormatter.unknown(decodeResult, message.text);
795
982
  decodeResult.decoded = false;
796
983
  decodeResult.decoder.decodeLevel = "none";
797
984
  return decodeResult;
798
985
  }
799
- decodeResult.remaining.text = "";
800
986
  const data = parts[2].split(" ");
801
987
  ResultFormatter.departureAirport(decodeResult, data[1]);
802
988
  ResultFormatter.arrivalAirport(decodeResult, data[2]);
@@ -812,7 +998,7 @@ var Label_13Through18_Slash = class extends DecoderPlugin {
812
998
  ResultFormatter.in(decodeResult, time);
813
999
  }
814
1000
  if (parts.length === 7) {
815
- decodeResult.remaining.text += parts.slice(4).join("/");
1001
+ ResultFormatter.unknownArr(decodeResult, parts.slice(4), "/");
816
1002
  }
817
1003
  for (let i = 1; i < lines.length; i++) {
818
1004
  if (lines[i].startsWith("/LOC")) {
@@ -826,11 +1012,9 @@ var Label_13Through18_Slash = class extends DecoderPlugin {
826
1012
  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)))
827
1013
  };
828
1014
  }
829
- if (!isNaN(position.latitude) && !isNaN(position.longitude)) {
830
- ResultFormatter.position(decodeResult, position);
831
- }
1015
+ ResultFormatter.position(decodeResult, position);
832
1016
  } else {
833
- decodeResult.remaining.text += "\r\n" + lines[i];
1017
+ ResultFormatter.unknown(decodeResult, lines[i], "\r\n");
834
1018
  }
835
1019
  }
836
1020
  decodeResult.decoded = true;
@@ -875,16 +1059,8 @@ var Label_15 = class extends DecoderPlugin {
875
1059
  decodeResult.formatted.description = "Position Report";
876
1060
  const twoZeeRegex = /^\(2(?<between>.+)\(Z$/;
877
1061
  const results = message.text.match(twoZeeRegex);
878
- if (results) {
879
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.between.substr(0, 13));
880
- if (decodeResult.raw.position) {
881
- decodeResult.formatted.items.push({
882
- type: "position",
883
- code: "POS",
884
- label: "Position",
885
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
886
- });
887
- }
1062
+ if (results?.groups) {
1063
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.between.substr(0, 13)));
888
1064
  }
889
1065
  decodeResult.decoded = true;
890
1066
  decodeResult.decoder.decodeLevel = "partial";
@@ -908,31 +1084,23 @@ var Label_15_FST = class extends DecoderPlugin {
908
1084
  decodeResult.message = message;
909
1085
  const parts = message.text.split(" ");
910
1086
  const header = parts[0];
911
- decodeResult.raw.departure_icao = header.substring(5, 9);
912
- decodeResult.raw.arrival_icao = header.substring(9, 13);
913
1087
  const stringCoords = header.substring(13);
914
1088
  const firstChar = stringCoords.substring(0, 1);
915
1089
  const middleChar = stringCoords.substring(7, 8);
916
1090
  decodeResult.raw.position = {};
917
1091
  if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
918
- decodeResult.raw.position.latitude = Number(stringCoords.substring(1, 7)) / 1e4 * (firstChar === "S" ? -1 : 1);
919
- decodeResult.raw.position.longitude = Number(stringCoords.substring(8, 15)) / 1e4 * (middleChar === "W" ? -1 : 1);
920
- decodeResult.raw.altitude = Number(stringCoords.substring(15)) * 100;
1092
+ const lat = Number(stringCoords.substring(1, 7)) / 1e4 * (firstChar === "S" ? -1 : 1);
1093
+ const lon = Number(stringCoords.substring(8, 15)) / 1e4 * (middleChar === "W" ? -1 : 1);
1094
+ ResultFormatter.position(decodeResult, { latitude: lat, longitude: lon });
1095
+ ResultFormatter.altitude(decodeResult, Number(stringCoords.substring(15)) * 100);
921
1096
  } else {
922
1097
  decodeResult.decoded = false;
923
1098
  decodeResult.decoder.decodeLevel = "none";
924
1099
  return decodeResult;
925
1100
  }
926
- decodeResult.formatted.items.push({
927
- type: "aircraft_position",
928
- code: "POS",
929
- label: "Aircraft Position",
930
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
931
- });
932
- ResultFormatter.altitude(decodeResult, decodeResult.raw.altitude);
933
- ResultFormatter.departureAirport(decodeResult, decodeResult.raw.departure_icao);
934
- ResultFormatter.arrivalAirport(decodeResult, decodeResult.raw.arrival_icao);
935
- decodeResult.remaining.text = parts.slice(1).join(" ");
1101
+ ResultFormatter.departureAirport(decodeResult, header.substring(5, 9));
1102
+ ResultFormatter.arrivalAirport(decodeResult, header.substring(9, 13));
1103
+ ResultFormatter.unknownArr(decodeResult, parts.slice(1), " ");
936
1104
  decodeResult.decoded = true;
937
1105
  decodeResult.decoder.decodeLevel = "partial";
938
1106
  return decodeResult;
@@ -955,52 +1123,45 @@ var Label_16_N_Space = class extends DecoderPlugin {
955
1123
  decodeResult.message = message;
956
1124
  let variant1Regex = /^(?<lat>[NS])\s(?<lat_coord>.*),(?<long>[EW])\s*(?<long_coord>.*),(?<alt>.*),(?<unkwn1>.*),\s*(?<unkwn2>.*)$/;
957
1125
  let variant2Regex = /^(?<lat>[NS])\s(?<lat_coord>.*)\/(?<long>[EW])\s*(?<long_coord>.*)$/;
958
- let results;
959
- if (results = message.text.match(variant1Regex)) {
1126
+ let results = message.text.match(variant1Regex);
1127
+ if (results?.groups) {
960
1128
  if (options.debug) {
961
1129
  console.log(`Label 16 N : results`);
962
1130
  console.log(results);
963
1131
  }
964
- decodeResult.raw.position = {
1132
+ let pos = {
965
1133
  latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
966
1134
  longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
967
1135
  };
968
1136
  const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
969
- decodeResult.formatted.items.push({
970
- type: "aircraft_position",
971
- code: "POS",
972
- label: "Aircraft Position",
973
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
974
- });
1137
+ ResultFormatter.position(decodeResult, pos);
975
1138
  ResultFormatter.altitude(decodeResult, altitude);
976
- decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}`;
1139
+ ResultFormatter.unknownArr(decodeResult, [results.groups.unkwn1, results.groups.unkwn2]);
977
1140
  decodeResult.decoded = true;
978
1141
  decodeResult.decoder.decodeLevel = "partial";
979
- } else if (results = message.text.match(variant2Regex)) {
1142
+ return decodeResult;
1143
+ }
1144
+ results = message.text.match(variant2Regex);
1145
+ if (results?.groups) {
980
1146
  if (options.debug) {
981
1147
  console.log(`Label 16 N : results`);
982
1148
  console.log(results);
983
1149
  }
984
- decodeResult.raw.position = {
1150
+ let pos = {
985
1151
  latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
986
1152
  longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
987
1153
  };
988
- decodeResult.formatted.items.push({
989
- type: "aircraft_position",
990
- code: "POS",
991
- label: "Aircraft Position",
992
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
993
- });
1154
+ ResultFormatter.position(decodeResult, pos);
994
1155
  decodeResult.decoded = true;
995
1156
  decodeResult.decoder.decodeLevel = "full";
996
- } else {
997
- if (options.debug) {
998
- console.log(`Decoder: Unknown 16 message: ${message.text}`);
999
- }
1000
- decodeResult.remaining.text = message.text;
1001
- decodeResult.decoded = false;
1002
- decodeResult.decoder.decodeLevel = "none";
1157
+ return decodeResult;
1158
+ }
1159
+ if (options.debug) {
1160
+ console.log(`Decoder: Unknown 16 message: ${message.text}`);
1003
1161
  }
1162
+ ResultFormatter.unknown(decodeResult, message.text);
1163
+ decodeResult.decoded = false;
1164
+ decodeResult.decoder.decodeLevel = "none";
1004
1165
  return decodeResult;
1005
1166
  }
1006
1167
  };
@@ -1026,28 +1187,12 @@ var Label_1M_Slash = class extends DecoderPlugin {
1026
1187
  console.log(results);
1027
1188
  }
1028
1189
  decodeResult.raw.flight_number = results[0];
1029
- decodeResult.raw.departure_icao = results[3];
1030
- decodeResult.raw.arrival_icao = results[4];
1031
- decodeResult.raw.alternate_icao = results[5];
1032
- decodeResult.raw.arrival_runway = results[8].replace(decodeResult.raw.arrival_icao, "");
1033
- decodeResult.formatted.items.push({
1034
- type: "eta",
1035
- code: "ETA",
1036
- label: "Estimated Time of Arrival",
1037
- value: DateTimeUtils.UTCDateTimeToString(results[2], results[7])
1038
- });
1039
- decodeResult.formatted.items.push({
1040
- type: "destination",
1041
- code: "DST",
1042
- label: "Destination",
1043
- value: decodeResult.raw.arrival_icao
1044
- });
1045
- decodeResult.formatted.items.push({
1046
- type: "origin",
1047
- code: "ORG",
1048
- label: "Origin",
1049
- value: decodeResult.raw.departure_icao
1050
- });
1190
+ ResultFormatter.departureAirport(decodeResult, results[3]);
1191
+ ResultFormatter.arrivalAirport(decodeResult, results[4]);
1192
+ ResultFormatter.alternateAirport(decodeResult, results[5]);
1193
+ ResultFormatter.arrivalRunway(decodeResult, results[8].replace(results[4], ""));
1194
+ const yymmdd = results[2];
1195
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertDateTimeToEpoch(results[7] + "00", yymmdd.substring(2, 4) + yymmdd.substring(4, 6) + yymmdd.substring(0, 2)), "epoch");
1051
1196
  }
1052
1197
  decodeResult.decoded = true;
1053
1198
  decodeResult.decoder.decodeLevel = "partial";
@@ -1055,13 +1200,13 @@ var Label_1M_Slash = class extends DecoderPlugin {
1055
1200
  }
1056
1201
  };
1057
1202
 
1058
- // lib/plugins/Label_20_POS.ts
1059
- var Label_20_POS = class extends DecoderPlugin {
1060
- name = "label-20-pos";
1203
+ // lib/plugins/Label_1L_3-line.ts
1204
+ var Label_1L_3Line = class extends DecoderPlugin {
1205
+ // eslint-disable-line camelcase
1206
+ name = "label-1l-3-line";
1061
1207
  qualifiers() {
1062
1208
  return {
1063
- labels: ["20"],
1064
- preambles: ["POS"]
1209
+ labels: ["1L"]
1065
1210
  };
1066
1211
  }
1067
1212
  decode(message, options = {}) {
@@ -1069,59 +1214,88 @@ var Label_20_POS = class extends DecoderPlugin {
1069
1214
  decodeResult.decoder.name = this.name;
1070
1215
  decodeResult.formatted.description = "Position Report";
1071
1216
  decodeResult.message = message;
1072
- decodeResult.raw.preamble = message.text.substring(0, 3);
1073
- const content = message.text.substring(3);
1074
- const fields = content.split(",");
1075
- if (fields.length == 11) {
1076
- if (options.debug) {
1077
- console.log(`DEBUG: ${this.name}: Variation 1 detected`);
1078
- }
1079
- const rawCoords = fields[0];
1080
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
1081
- if (decodeResult.raw.position) {
1082
- decodeResult.formatted.items.push({
1083
- type: "position",
1084
- code: "POS",
1085
- label: "Position",
1086
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1087
- });
1088
- }
1089
- decodeResult.decoded = true;
1090
- decodeResult.decoder.decodeLevel = "full";
1091
- } else if (fields.length == 5) {
1092
- if (options.debug) {
1093
- console.log(`DEBUG: ${this.name}: Variation 2 detected`);
1094
- }
1095
- const rawCoords = fields[0];
1096
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
1097
- if (decodeResult.raw.position) {
1098
- decodeResult.formatted.items.push({
1099
- type: "position",
1100
- code: "POS",
1101
- label: "Position",
1102
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1103
- });
1104
- }
1105
- decodeResult.decoded = true;
1106
- decodeResult.decoder.decodeLevel = "full";
1107
- } else {
1217
+ const lines = message.text.split("\r\n");
1218
+ if (lines.length !== 3) {
1108
1219
  if (options.debug) {
1109
- console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
1220
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1110
1221
  }
1222
+ decodeResult.remaining.text = message.text;
1111
1223
  decodeResult.decoded = false;
1112
1224
  decodeResult.decoder.decodeLevel = "none";
1225
+ return decodeResult;
1226
+ }
1227
+ const parts = message.text.replaceAll("\r\n", "/").split("/");
1228
+ const data = /* @__PURE__ */ new Map();
1229
+ data.set("", parts[0]);
1230
+ for (let i = 1; i < parts.length; i++) {
1231
+ const part = parts[i].split(" ");
1232
+ data.set(part[0], part.slice(1).join(" "));
1233
+ }
1234
+ const dep = data.get("DEP");
1235
+ if (dep) {
1236
+ ResultFormatter.departureAirport(decodeResult, dep);
1237
+ data.delete("DEP");
1238
+ }
1239
+ const des = data.get("DES");
1240
+ if (des) {
1241
+ ResultFormatter.arrivalAirport(decodeResult, des);
1242
+ data.delete("DES");
1243
+ }
1244
+ const eta = data.get("ETA");
1245
+ if (eta) {
1246
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta + "00"));
1247
+ data.delete("ETA");
1248
+ }
1249
+ const alt = data.get("ALT");
1250
+ if (alt) {
1251
+ ResultFormatter.altitude(decodeResult, Number(alt));
1252
+ data.delete("ALT");
1253
+ }
1254
+ const fn = data.get("FN");
1255
+ if (fn) {
1256
+ ResultFormatter.flightNumber(decodeResult, fn);
1257
+ data.delete("FN");
1113
1258
  }
1259
+ const day = data.get("DAY");
1260
+ const utc = data.get("UTC");
1261
+ if (day && utc) {
1262
+ decodeResult.raw.message_timestamp = Date.parse(day + " GMT+0000") / 1e3 + DateTimeUtils.convertHHMMSSToTod(utc);
1263
+ data.delete("DAY");
1264
+ data.delete("UTC");
1265
+ }
1266
+ const lat = data.get("LAT");
1267
+ const lon = data.get("LON");
1268
+ if (lat && lon) {
1269
+ ResultFormatter.position(decodeResult, {
1270
+ latitude: CoordinateUtils.getDirection(lat[0]) * Number(lat.substring(1)),
1271
+ longitude: CoordinateUtils.getDirection(lon[0]) * Number(lon.substring(1))
1272
+ });
1273
+ data.delete("LAT");
1274
+ data.delete("LON");
1275
+ }
1276
+ let remaining = "";
1277
+ for (const [key, value] of data.entries()) {
1278
+ if (key === "") {
1279
+ remaining += value;
1280
+ } else {
1281
+ remaining += `/${key} ${value}`;
1282
+ }
1283
+ }
1284
+ decodeResult.remaining.text = remaining;
1285
+ decodeResult.decoded = true;
1286
+ decodeResult.decoder.decodeLevel = "partial";
1114
1287
  return decodeResult;
1115
1288
  }
1116
1289
  };
1117
1290
 
1118
- // lib/plugins/Label_21_POS.ts
1119
- var Label_21_POS = class extends DecoderPlugin {
1120
- name = "label-21-pos";
1291
+ // lib/plugins/Label_1L_070.ts
1292
+ var Label_1L_070 = class extends DecoderPlugin {
1293
+ // eslint-disable-line camelcase
1294
+ name = "label-1l-070";
1121
1295
  qualifiers() {
1122
1296
  return {
1123
- labels: ["21"],
1124
- preambles: ["POS"]
1297
+ labels: ["1L"],
1298
+ preambles: ["000000070"]
1125
1299
  };
1126
1300
  }
1127
1301
  decode(message, options = {}) {
@@ -1129,81 +1303,416 @@ var Label_21_POS = class extends DecoderPlugin {
1129
1303
  decodeResult.decoder.name = this.name;
1130
1304
  decodeResult.formatted.description = "Position Report";
1131
1305
  decodeResult.message = message;
1132
- decodeResult.raw.preamble = message.text.substring(0, 3);
1133
- const content = message.text.substring(3);
1134
- const fields = content.split(",");
1135
- if (fields.length == 9) {
1136
- processPosition(decodeResult, fields[0].trim());
1137
- processAlt(decodeResult, fields[3]);
1138
- processTemp(decodeResult, fields[6]);
1139
- processArrvApt(decodeResult, fields[8]);
1140
- decodeResult.remaining.text = [
1141
- fields[1],
1142
- fields[2],
1143
- fields[4],
1144
- fields[5],
1145
- fields[7]
1146
- ].join(",");
1147
- decodeResult.decoded = true;
1148
- decodeResult.decoder.decodeLevel = "partial";
1149
- } else {
1306
+ if (!message.text.startsWith("000000070")) {
1150
1307
  if (options.debug) {
1151
- console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
1308
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1152
1309
  }
1310
+ decodeResult.remaining.text = message.text;
1153
1311
  decodeResult.decoded = false;
1154
1312
  decodeResult.decoder.decodeLevel = "none";
1313
+ return decodeResult;
1155
1314
  }
1156
- return decodeResult;
1157
- }
1158
- };
1159
- function processPosition(decodeResult, value) {
1160
- if (value.length !== 16 && value[0] !== "N" && value[0] !== "S" && value[8] !== "W" && value[8] !== "E") {
1161
- return false;
1162
- }
1163
- const latDir = value[0] === "N" ? 1 : -1;
1315
+ const parts = message.text.substring(9).split(",");
1316
+ if (parts.length !== 7) {
1317
+ if (options.debug) {
1318
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1319
+ }
1320
+ decodeResult.remaining.text = message.text;
1321
+ decodeResult.decoded = false;
1322
+ decodeResult.decoder.decodeLevel = "none";
1323
+ return decodeResult;
1324
+ }
1325
+ ResultFormatter.departureAirport(decodeResult, parts[0]);
1326
+ ResultFormatter.arrivalAirport(decodeResult, parts[1]);
1327
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[2] + "00"));
1328
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[3] + "00"));
1329
+ ResultFormatter.position(decodeResult, {
1330
+ latitude: CoordinateUtils.getDirection(parts[4][0]) * Number(parts[4].substring(1)),
1331
+ longitude: CoordinateUtils.getDirection(parts[5][0]) * Number(parts[5].substring(1))
1332
+ });
1333
+ decodeResult.remaining.text = parts[6];
1334
+ decodeResult.decoded = true;
1335
+ decodeResult.decoder.decodeLevel = "partial";
1336
+ return decodeResult;
1337
+ }
1338
+ };
1339
+
1340
+ // lib/plugins/Label_1L_660.ts
1341
+ var Label_1L_660 = class extends DecoderPlugin {
1342
+ // eslint-disable-line camelcase
1343
+ name = "label-1l-660";
1344
+ qualifiers() {
1345
+ return {
1346
+ labels: ["1L"],
1347
+ preambles: ["000000660"]
1348
+ };
1349
+ }
1350
+ decode(message, options = {}) {
1351
+ const decodeResult = this.defaultResult();
1352
+ decodeResult.decoder.name = this.name;
1353
+ decodeResult.formatted.description = "Position Report";
1354
+ decodeResult.message = message;
1355
+ if (!message.text.startsWith("000000660")) {
1356
+ if (options.debug) {
1357
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1358
+ }
1359
+ decodeResult.remaining.text = message.text;
1360
+ decodeResult.decoded = false;
1361
+ decodeResult.decoder.decodeLevel = "none";
1362
+ return decodeResult;
1363
+ }
1364
+ const parts = message.text.substring(9).split(",");
1365
+ if (parts.length !== 5) {
1366
+ if (options.debug) {
1367
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1368
+ }
1369
+ decodeResult.remaining.text = message.text;
1370
+ decodeResult.decoded = false;
1371
+ decodeResult.decoder.decodeLevel = "none";
1372
+ return decodeResult;
1373
+ }
1374
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(parts[0]);
1375
+ if (position) {
1376
+ ResultFormatter.position(decodeResult, position);
1377
+ }
1378
+ const hhmmss = parts[1].substring(0, 6);
1379
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(hhmmss));
1380
+ const fl = parts[1].substring(6, 9);
1381
+ ResultFormatter.altitude(decodeResult, Number(fl) * 100);
1382
+ const next = parts[1].substring(9);
1383
+ ResultFormatter.route(decodeResult, { waypoints: [{ name: next.trim() }] });
1384
+ decodeResult.remaining.text = parts.slice(2).join(",");
1385
+ decodeResult.decoded = true;
1386
+ decodeResult.decoder.decodeLevel = "partial";
1387
+ return decodeResult;
1388
+ }
1389
+ };
1390
+
1391
+ // lib/plugins/Label_1L_Slash.ts
1392
+ var Label_1L_Slash = class extends DecoderPlugin {
1393
+ // eslint-disable-line camelcase
1394
+ name = "label-1l-1-line";
1395
+ qualifiers() {
1396
+ return {
1397
+ labels: ["1L"],
1398
+ preambles: ["+", "-"]
1399
+ };
1400
+ }
1401
+ decode(message, options = {}) {
1402
+ const decodeResult = this.defaultResult();
1403
+ decodeResult.decoder.name = this.name;
1404
+ decodeResult.formatted.description = "Position Report";
1405
+ decodeResult.message = message;
1406
+ const parts = message.text.split("/");
1407
+ if (parts.length !== 7) {
1408
+ if (options.debug) {
1409
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1410
+ }
1411
+ decodeResult.remaining.text = message.text;
1412
+ decodeResult.decoded = false;
1413
+ decodeResult.decoder.decodeLevel = "none";
1414
+ return decodeResult;
1415
+ }
1416
+ const data = /* @__PURE__ */ new Map();
1417
+ data.set("LAT", parts[0].replaceAll(" ", ""));
1418
+ data.set("LON", parts[1].replaceAll(" ", ""));
1419
+ for (let i = 2; i < parts.length; i++) {
1420
+ const part = parts[i].split(" ");
1421
+ data.set(part[0], part.slice(1).join(" "));
1422
+ }
1423
+ console.log(data);
1424
+ const position = {
1425
+ latitude: Number(data.get("LAT")),
1426
+ longitude: Number(data.get("LON"))
1427
+ };
1428
+ data.delete("LAT");
1429
+ data.delete("LON");
1430
+ ResultFormatter.position(decodeResult, position);
1431
+ const utc = data.get("UTC");
1432
+ if (utc) {
1433
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(utc));
1434
+ data.delete("UTC");
1435
+ }
1436
+ const alt = data.get("ALT");
1437
+ if (alt) {
1438
+ ResultFormatter.altitude(decodeResult, Number(alt));
1439
+ data.delete("ALT");
1440
+ }
1441
+ const fob = data.get("FOB");
1442
+ if (fob) {
1443
+ ResultFormatter.currentFuel(decodeResult, Number(fob));
1444
+ data.delete("FOB");
1445
+ }
1446
+ const eta = data.get("ETA");
1447
+ if (eta) {
1448
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta + "00"));
1449
+ data.delete("ETA");
1450
+ }
1451
+ let remaining = "";
1452
+ for (const [key, value] of data.entries()) {
1453
+ remaining += `/${key} ${value}`;
1454
+ }
1455
+ decodeResult.remaining.text = remaining;
1456
+ decodeResult.decoded = true;
1457
+ decodeResult.decoder.decodeLevel = "partial";
1458
+ return decodeResult;
1459
+ }
1460
+ };
1461
+
1462
+ // lib/plugins/Label_20_POS.ts
1463
+ var Label_20_POS = class extends DecoderPlugin {
1464
+ name = "label-20-pos";
1465
+ qualifiers() {
1466
+ return {
1467
+ labels: ["20"],
1468
+ preambles: ["POS"]
1469
+ };
1470
+ }
1471
+ decode(message, options = {}) {
1472
+ const decodeResult = this.defaultResult();
1473
+ decodeResult.decoder.name = this.name;
1474
+ decodeResult.formatted.description = "Position Report";
1475
+ decodeResult.message = message;
1476
+ decodeResult.raw.preamble = message.text.substring(0, 3);
1477
+ const content = message.text.substring(3);
1478
+ const fields = content.split(",");
1479
+ if (fields.length == 11) {
1480
+ if (options.debug) {
1481
+ console.log(`DEBUG: ${this.name}: Variation 1 detected`);
1482
+ }
1483
+ const rawCoords = fields[0];
1484
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(rawCoords));
1485
+ decodeResult.decoded = true;
1486
+ decodeResult.decoder.decodeLevel = "full";
1487
+ } else if (fields.length == 5) {
1488
+ if (options.debug) {
1489
+ console.log(`DEBUG: ${this.name}: Variation 2 detected`);
1490
+ }
1491
+ const position = CoordinateUtils.decodeStringCoordinates(fields[0]);
1492
+ if (position) {
1493
+ ResultFormatter.position(decodeResult, position);
1494
+ }
1495
+ decodeResult.decoded = true;
1496
+ decodeResult.decoder.decodeLevel = "full";
1497
+ } else {
1498
+ if (options.debug) {
1499
+ console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
1500
+ }
1501
+ decodeResult.decoded = false;
1502
+ decodeResult.decoder.decodeLevel = "none";
1503
+ }
1504
+ return decodeResult;
1505
+ }
1506
+ };
1507
+
1508
+ // lib/plugins/Label_21_POS.ts
1509
+ var Label_21_POS = class extends DecoderPlugin {
1510
+ name = "label-21-pos";
1511
+ qualifiers() {
1512
+ return {
1513
+ labels: ["21"],
1514
+ preambles: ["POS"]
1515
+ };
1516
+ }
1517
+ decode(message, options = {}) {
1518
+ const decodeResult = this.defaultResult();
1519
+ decodeResult.decoder.name = this.name;
1520
+ decodeResult.formatted.description = "Position Report";
1521
+ decodeResult.message = message;
1522
+ decodeResult.raw.preamble = message.text.substring(0, 3);
1523
+ const content = message.text.substring(3);
1524
+ const fields = content.split(",");
1525
+ if (fields.length == 9) {
1526
+ processPosition(decodeResult, fields[0].trim());
1527
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2]));
1528
+ ResultFormatter.altitude(decodeResult, Number(fields[3]));
1529
+ ResultFormatter.temperature(decodeResult, fields[6].replace(/ /g, ""));
1530
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[7]));
1531
+ ResultFormatter.arrivalAirport(decodeResult, fields[8]);
1532
+ ResultFormatter.unknownArr(decodeResult, [fields[1], fields[4], fields[5]]);
1533
+ decodeResult.decoded = true;
1534
+ decodeResult.decoder.decodeLevel = "partial";
1535
+ } else {
1536
+ if (options.debug) {
1537
+ console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
1538
+ }
1539
+ decodeResult.decoded = false;
1540
+ decodeResult.decoder.decodeLevel = "none";
1541
+ }
1542
+ return decodeResult;
1543
+ }
1544
+ };
1545
+ function processPosition(decodeResult, value) {
1546
+ if (value.length !== 16 && value[0] !== "N" && value[0] !== "S" && value[8] !== "W" && value[8] !== "E") {
1547
+ return;
1548
+ }
1549
+ const latDir = value[0] === "N" ? 1 : -1;
1164
1550
  const lonDir = value[8] === "E" ? 1 : -1;
1165
1551
  const position = {
1166
1552
  latitude: latDir * Number(value.substring(1, 7)),
1167
1553
  longitude: lonDir * Number(value.substring(9, 15))
1168
1554
  };
1169
- if (position) {
1170
- decodeResult.raw.position = position;
1171
- decodeResult.formatted.items.push({
1172
- type: "aircraft_position",
1173
- code: "POS",
1174
- label: "Aircraft Position",
1175
- value: CoordinateUtils.coordinateString(position)
1555
+ ResultFormatter.position(decodeResult, position);
1556
+ }
1557
+
1558
+ // lib/plugins/Label_22_OFF.ts
1559
+ var Label_22_OFF = class extends DecoderPlugin {
1560
+ name = "label-22-off";
1561
+ qualifiers() {
1562
+ return {
1563
+ labels: ["22"],
1564
+ preambles: ["OFF"]
1565
+ };
1566
+ }
1567
+ decode(message, options = {}) {
1568
+ const decodeResult = this.defaultResult();
1569
+ decodeResult.decoder.name = this.name;
1570
+ decodeResult.formatted.description = "Takeoff Report";
1571
+ decodeResult.message = message;
1572
+ if (message.text.startsWith("OFF01")) {
1573
+ const fields = message.text.substring(5).split("/");
1574
+ if (fields.length != 2) {
1575
+ decodeResult.decoded = false;
1576
+ decodeResult.decoder.decodeLevel = "none";
1577
+ return decodeResult;
1578
+ }
1579
+ ResultFormatter.flightNumber(decodeResult, fields[0]);
1580
+ ResultFormatter.departureDay(decodeResult, Number(fields[1].substring(0, 2)));
1581
+ ResultFormatter.arrivalDay(decodeResult, Number(fields[1].substring(2, 4)));
1582
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(4, 8) + "00"));
1583
+ ResultFormatter.departureAirport(decodeResult, fields[1].substring(8, 12));
1584
+ ResultFormatter.arrivalAirport(decodeResult, fields[1].substring(12, 16));
1585
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 22)));
1586
+ ResultFormatter.unknown(decodeResult, fields[1].substring(22));
1587
+ decodeResult.decoded = true;
1588
+ decodeResult.decoder.decodeLevel = "partial";
1589
+ } else if (message.text.startsWith("OFF02\r\n")) {
1590
+ const fields = message.text.substring(7).split(",");
1591
+ if (fields.length != 4) {
1592
+ decodeResult.decoded = false;
1593
+ decodeResult.decoder.decodeLevel = "none";
1594
+ return decodeResult;
1595
+ }
1596
+ ResultFormatter.departureAirport(decodeResult, fields[0]);
1597
+ ResultFormatter.arrivalAirport(decodeResult, fields[1]);
1598
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2] + "00"));
1599
+ ResultFormatter.unknown(decodeResult, fields[3]);
1600
+ decodeResult.decoded = true;
1601
+ decodeResult.decoder.decodeLevel = "partial";
1602
+ } else if (message.text.startsWith("OFF02")) {
1603
+ const fields = message.text.substring(5).split("/");
1604
+ if (fields.length != 2) {
1605
+ decodeResult.decoded = false;
1606
+ decodeResult.decoder.decodeLevel = "none";
1607
+ return decodeResult;
1608
+ }
1609
+ ResultFormatter.flightNumber(decodeResult, fields[0]);
1610
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(fields[1].substring(0, 14));
1611
+ if (position) {
1612
+ ResultFormatter.position(decodeResult, position);
1613
+ }
1614
+ ResultFormatter.day(decodeResult, Number(fields[1].substring(14, 16)));
1615
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 20) + "00"));
1616
+ ResultFormatter.departureAirport(decodeResult, fields[1].substring(20, 24));
1617
+ ResultFormatter.arrivalAirport(decodeResult, fields[1].substring(24, 28));
1618
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(28, 32) + "00"));
1619
+ ResultFormatter.unknown(decodeResult, fields[1].substring(32, 36));
1620
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(36, 40) + "00"));
1621
+ decodeResult.decoded = true;
1622
+ decodeResult.decoder.decodeLevel = "partial";
1623
+ } else {
1624
+ if (options.debug) {
1625
+ console.log(`DEBUG: ${this.name}: Unknown variation.`);
1626
+ }
1627
+ decodeResult.decoded = false;
1628
+ decodeResult.decoder.decodeLevel = "none";
1629
+ }
1630
+ return decodeResult;
1631
+ }
1632
+ };
1633
+
1634
+ // lib/plugins/Label_22_POS.ts
1635
+ var Label_22_POS = class extends DecoderPlugin {
1636
+ name = "label-22-pos";
1637
+ qualifiers() {
1638
+ return {
1639
+ labels: ["22"],
1640
+ preambles: ["N", "S"]
1641
+ };
1642
+ }
1643
+ decode(message, options = {}) {
1644
+ const decodeResult = this.defaultResult();
1645
+ decodeResult.decoder.name = this.name;
1646
+ decodeResult.formatted.description = "Position Report";
1647
+ decodeResult.message = message;
1648
+ const fields = message.text.split(",");
1649
+ if (fields.length !== 11) {
1650
+ if (options.debug) {
1651
+ console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${fields.join(",")}`);
1652
+ }
1653
+ decodeResult.decoded = false;
1654
+ decodeResult.decoder.decodeLevel = "none";
1655
+ return decodeResult;
1656
+ }
1657
+ const latStr = fields[0].substring(1, 8);
1658
+ const lonStr = fields[0].substring(9);
1659
+ const lat = Number(latStr) / 1e4;
1660
+ const lon = Number(lonStr) / 1e4;
1661
+ ResultFormatter.position(decodeResult, {
1662
+ latitude: CoordinateUtils.getDirection(fields[0][0]) * lat,
1663
+ longitude: CoordinateUtils.getDirection(fields[0][8]) * lon
1176
1664
  });
1665
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2]));
1666
+ ResultFormatter.altitude(decodeResult, Number(fields[3]));
1667
+ ResultFormatter.unknownArr(decodeResult, [fields[1], ...fields.slice(4)]);
1668
+ decodeResult.decoded = true;
1669
+ decodeResult.decoder.decodeLevel = "partial";
1670
+ return decodeResult;
1177
1671
  }
1178
- return !!position;
1179
- }
1180
- function processAlt(decodeResult, value) {
1181
- decodeResult.raw.altitude = Number(value);
1182
- decodeResult.formatted.items.push({
1183
- type: "altitude",
1184
- code: "ALT",
1185
- label: "Altitude",
1186
- value: `${decodeResult.raw.altitude} feet`
1187
- });
1188
- }
1189
- function processTemp(decodeResult, value) {
1190
- decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
1191
- decodeResult.formatted.items.push({
1192
- type: "outside_air_temperature",
1193
- code: "OATEMP",
1194
- label: "Outside Air Temperature (C)",
1195
- value: `${decodeResult.raw.outside_air_temperature}`
1196
- });
1197
- }
1198
- function processArrvApt(decodeResult, value) {
1199
- decodeResult.raw.arrival_icao = value;
1200
- decodeResult.formatted.items.push({
1201
- type: "destination",
1202
- code: "DST",
1203
- label: "Destination",
1204
- value: decodeResult.raw.arrival_icao
1205
- });
1206
- }
1672
+ };
1673
+
1674
+ // lib/plugins/Label_24_Slash.ts
1675
+ var Label_24_Slash = class extends DecoderPlugin {
1676
+ name = "label-24-slash";
1677
+ qualifiers() {
1678
+ return {
1679
+ labels: ["24"],
1680
+ preambles: ["/"]
1681
+ };
1682
+ }
1683
+ decode(message, options = {}) {
1684
+ const decodeResult = this.defaultResult();
1685
+ decodeResult.decoder.name = this.name;
1686
+ decodeResult.formatted.description = "Position Report";
1687
+ decodeResult.message = message;
1688
+ const fields = message.text.split("/");
1689
+ if (fields.length == 10 && fields[0] == "" && fields[9] == "") {
1690
+ const mmddyy = fields[1].substring(4, 6) + fields[1].substring(2, 4) + fields[1].substring(0, 2);
1691
+ const hhmmss = fields[2] + "00";
1692
+ decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(hhmmss, mmddyy);
1693
+ ResultFormatter.flightNumber(decodeResult, fields[3]);
1694
+ ResultFormatter.altitude(decodeResult, Number(fields[4]));
1695
+ const lat = fields[5];
1696
+ const lon = fields[6];
1697
+ const position = {
1698
+ latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1)),
1699
+ longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1))
1700
+ };
1701
+ ResultFormatter.position(decodeResult, position);
1702
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[8] + "00"));
1703
+ ResultFormatter.unknown(decodeResult, fields[7]);
1704
+ decodeResult.decoded = true;
1705
+ decodeResult.decoder.decodeLevel = "partial";
1706
+ } else {
1707
+ if (options.debug) {
1708
+ console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}. Message: ${message.text}`);
1709
+ }
1710
+ decodeResult.decoded = false;
1711
+ decodeResult.decoder.decodeLevel = "none";
1712
+ }
1713
+ return decodeResult;
1714
+ }
1715
+ };
1207
1716
 
1208
1717
  // lib/plugins/Label_30_Slash_EA.ts
1209
1718
  var Label_30_Slash_EA = class extends DecoderPlugin {
@@ -1226,23 +1735,12 @@ var Label_30_Slash_EA = class extends DecoderPlugin {
1226
1735
  console.log(results);
1227
1736
  }
1228
1737
  }
1229
- decodeResult.formatted.items.push({
1230
- type: "eta",
1231
- code: "ETA",
1232
- label: "Estimated Time of Arrival",
1233
- value: DateTimeUtils.UTCToString(results[0].substr(2, 4))
1234
- });
1235
- if (results[1].substr(0, 2) === "DS") {
1236
- decodeResult.raw.arrival_icao = results[1].substr(2, 4);
1237
- decodeResult.formatted.items.push({
1238
- type: "destination",
1239
- code: "DST",
1240
- label: "Destination",
1241
- value: decodeResult.raw.arrival_icao
1242
- });
1243
- decodeResult.remaining.text = "/".concat(results[2]);
1738
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results[0].substr(2, 4) + "00"));
1739
+ if (results[1].substring(0, 2) === "DS") {
1740
+ ResultFormatter.arrivalAirport(decodeResult, results[1].substring(2, 6));
1741
+ ResultFormatter.unknown(decodeResult, "/".concat(results[2]));
1244
1742
  } else {
1245
- decodeResult.remaining.text = "/".concat(results[1], "/", results[2]);
1743
+ ResultFormatter.unknown(decodeResult, "/".concat(results[1], "/", results[2]));
1246
1744
  }
1247
1745
  decodeResult.decoded = true;
1248
1746
  decodeResult.decoder.decodeLevel = "partial";
@@ -1266,40 +1764,20 @@ var Label_44_ETA = class extends DecoderPlugin {
1266
1764
  decodeResult.message = message;
1267
1765
  const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
1268
1766
  const results = message.text.match(regex);
1269
- if (results) {
1767
+ if (results?.groups) {
1270
1768
  if (options.debug) {
1271
1769
  console.log(`Label 44 ETA Report: groups`);
1272
1770
  console.log(results.groups);
1273
1771
  }
1274
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
1275
- decodeResult.raw.departure_icao = results.groups.departure_icao;
1276
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1772
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords));
1773
+ ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1774
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1277
1775
  decodeResult.raw.current_time = Date.parse(
1278
1776
  (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.current_time.substr(0, 2) + ":" + results.groups.current_time.substr(2, 2) + ":00Z"
1279
1777
  );
1280
1778
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1281
- decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1282
- }
1283
- if (decodeResult.raw.position) {
1284
- decodeResult.formatted.items.push({
1285
- type: "position",
1286
- code: "POS",
1287
- label: "Position",
1288
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1289
- });
1779
+ ResultFormatter.remainingFuel(decodeResult, Number(results.groups.fuel_in_tons));
1290
1780
  }
1291
- decodeResult.formatted.items.push({
1292
- type: "origin",
1293
- code: "ORG",
1294
- label: "Origin",
1295
- value: decodeResult.raw.departure_icao
1296
- });
1297
- decodeResult.formatted.items.push({
1298
- type: "destination",
1299
- code: "DST",
1300
- label: "Destination",
1301
- value: decodeResult.raw.arrival_icao
1302
- });
1303
1781
  }
1304
1782
  decodeResult.decoded = true;
1305
1783
  decodeResult.decoder.decodeLevel = "full";
@@ -1323,40 +1801,20 @@ var Label_44_IN = class extends DecoderPlugin {
1323
1801
  decodeResult.message = message;
1324
1802
  const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
1325
1803
  const results = message.text.match(regex);
1326
- if (results) {
1804
+ if (results?.groups) {
1327
1805
  if (options.debug) {
1328
1806
  console.log(`Label 44 In Air Report: groups`);
1329
1807
  console.log(results.groups);
1330
1808
  }
1331
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
1332
- decodeResult.raw.departure_icao = results.groups.departure_icao;
1333
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1809
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords));
1810
+ ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1811
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1334
1812
  decodeResult.raw.current_time = Date.parse(
1335
1813
  (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.current_time.substr(0, 2) + ":" + results.groups.current_time.substr(2, 2) + ":00Z"
1336
1814
  );
1337
1815
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1338
1816
  decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1339
1817
  }
1340
- if (decodeResult.raw.position) {
1341
- decodeResult.formatted.items.push({
1342
- type: "position",
1343
- code: "POS",
1344
- label: "Position",
1345
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1346
- });
1347
- }
1348
- decodeResult.formatted.items.push({
1349
- type: "origin",
1350
- code: "ORG",
1351
- label: "Origin",
1352
- value: decodeResult.raw.departure_icao
1353
- });
1354
- decodeResult.formatted.items.push({
1355
- type: "destination",
1356
- code: "DST",
1357
- label: "Destination",
1358
- value: decodeResult.raw.arrival_icao
1359
- });
1360
1818
  }
1361
1819
  decodeResult.decoded = true;
1362
1820
  decodeResult.decoder.decodeLevel = "full";
@@ -1380,13 +1838,14 @@ var Label_44_OFF = class extends DecoderPlugin {
1380
1838
  decodeResult.message = message;
1381
1839
  const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<eta_time>.*),(?<fuel_in_tons>.*)$/;
1382
1840
  const results = message.text.match(regex);
1383
- if (results) {
1841
+ if (results?.groups) {
1384
1842
  if (options.debug) {
1385
1843
  console.log(`Label 44 Off Runway Report: groups`);
1386
1844
  console.log(results.groups);
1387
1845
  }
1388
- decodeResult.raw.departure_icao = results.groups.departure_icao;
1389
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1846
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords));
1847
+ ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1848
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1390
1849
  decodeResult.raw.current_time = Date.parse(
1391
1850
  (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.current_time.substr(0, 2) + ":" + results.groups.current_time.substr(2, 2) + ":00Z"
1392
1851
  );
@@ -1396,27 +1855,6 @@ var Label_44_OFF = class extends DecoderPlugin {
1396
1855
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1397
1856
  decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1398
1857
  }
1399
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
1400
- if (decodeResult.raw.position) {
1401
- decodeResult.formatted.items.push({
1402
- type: "position",
1403
- code: "POS",
1404
- label: "Position",
1405
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1406
- });
1407
- }
1408
- decodeResult.formatted.items.push({
1409
- type: "origin",
1410
- code: "ORG",
1411
- label: "Origin",
1412
- value: decodeResult.raw.departure_icao
1413
- });
1414
- decodeResult.formatted.items.push({
1415
- type: "destination",
1416
- code: "DST",
1417
- label: "Destination",
1418
- value: decodeResult.raw.arrival_icao
1419
- });
1420
1858
  }
1421
1859
  decodeResult.decoded = true;
1422
1860
  decodeResult.decoder.decodeLevel = "full";
@@ -1440,40 +1878,20 @@ var Label_44_ON = class extends DecoderPlugin {
1440
1878
  decodeResult.message = message;
1441
1879
  const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
1442
1880
  const results = message.text.match(regex);
1443
- if (results) {
1881
+ if (results?.groups) {
1444
1882
  if (options.debug) {
1445
1883
  console.log(`Label 44 On Runway Report: groups`);
1446
1884
  console.log(results.groups);
1447
1885
  }
1448
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
1449
- decodeResult.raw.departure_icao = results.groups.departure_icao;
1450
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1886
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords));
1887
+ ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1888
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1451
1889
  decodeResult.raw.current_time = Date.parse(
1452
1890
  (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.current_time.substr(0, 2) + ":" + results.groups.current_time.substr(2, 2) + ":00Z"
1453
1891
  );
1454
1892
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1455
- decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1893
+ ResultFormatter.remainingFuel(decodeResult, Number(results.groups.fuel_in_tons));
1456
1894
  }
1457
- if (decodeResult.raw.position) {
1458
- decodeResult.formatted.items.push({
1459
- type: "position",
1460
- code: "POS",
1461
- label: "Position",
1462
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1463
- });
1464
- }
1465
- decodeResult.formatted.items.push({
1466
- type: "origin",
1467
- code: "ORG",
1468
- label: "Origin",
1469
- value: decodeResult.raw.departure_icao
1470
- });
1471
- decodeResult.formatted.items.push({
1472
- type: "destination",
1473
- code: "DST",
1474
- label: "Destination",
1475
- value: decodeResult.raw.arrival_icao
1476
- });
1477
1895
  }
1478
1896
  decodeResult.decoded = true;
1479
1897
  decodeResult.decoder.decodeLevel = "full";
@@ -1497,12 +1915,12 @@ var Label_44_POS = class extends DecoderPlugin {
1497
1915
  decodeResult.message = message;
1498
1916
  const regex = /^.*,(?<unsplit_coords>.*),(?<flight_level_or_ground>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<eta_time>.*),(?<fuel_in_tons>.*)$/;
1499
1917
  const results = message.text.match(regex);
1500
- if (results) {
1918
+ if (results?.groups) {
1501
1919
  if (options.debug) {
1502
1920
  console.log(`Label 44 Position Report: groups`);
1503
1921
  console.log(results.groups);
1504
1922
  }
1505
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(results.groups.unsplit_coords);
1923
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(results.groups.unsplit_coords));
1506
1924
  const flight_level = results.groups.flight_level_or_ground == "GRD" || results.groups.flight_level_or_ground == "***" ? 0 : Number(results.groups.flight_level_or_ground);
1507
1925
  decodeResult.raw.current_time = Date.parse(
1508
1926
  (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.current_time.substr(0, 2) + ":" + results.groups.current_time.substr(2, 2) + ":00Z"
@@ -1513,20 +1931,221 @@ var Label_44_POS = class extends DecoderPlugin {
1513
1931
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1514
1932
  decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1515
1933
  }
1516
- if (decodeResult.raw.position) {
1517
- decodeResult.formatted.items.push({
1518
- type: "aircraft_position",
1519
- code: "POS",
1520
- label: "Aircraft Position",
1521
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1522
- });
1523
- }
1524
1934
  ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1525
1935
  ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1526
1936
  ResultFormatter.altitude(decodeResult, flight_level * 100);
1527
1937
  }
1528
1938
  decodeResult.decoded = true;
1529
- decodeResult.decoder.decodeLevel = "full";
1939
+ decodeResult.decoder.decodeLevel = "full";
1940
+ return decodeResult;
1941
+ }
1942
+ };
1943
+
1944
+ // lib/plugins/Label_4A.ts
1945
+ var Label_4A = class extends DecoderPlugin {
1946
+ name = "label-4a";
1947
+ qualifiers() {
1948
+ return {
1949
+ labels: ["4A"]
1950
+ };
1951
+ }
1952
+ decode(message, options = {}) {
1953
+ const decodeResult = this.defaultResult();
1954
+ decodeResult.decoder.name = this.name;
1955
+ decodeResult.message = message;
1956
+ decodeResult.formatted.description = "Latest New Format";
1957
+ let text = message.text;
1958
+ if (text.match(/^M\d{2}A\w{6}/)) {
1959
+ ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
1960
+ text = text.substring(10);
1961
+ }
1962
+ decodeResult.decoded = true;
1963
+ const fields = text.split(",");
1964
+ if (fields.length === 11) {
1965
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[0]));
1966
+ ResultFormatter.tail(decodeResult, fields[2].replace(".", ""));
1967
+ if (fields[3])
1968
+ ResultFormatter.callsign(decodeResult, fields[3]);
1969
+ ResultFormatter.departureAirport(decodeResult, fields[4]);
1970
+ ResultFormatter.arrivalAirport(decodeResult, fields[5]);
1971
+ ResultFormatter.altitude(decodeResult, Number(text.substring(48, 51)) * 100);
1972
+ ResultFormatter.unknownArr(decodeResult, fields.slice(8));
1973
+ } else if (fields.length === 6) {
1974
+ if (fields[0].match(/^[NS]/)) {
1975
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(fields[0].substring(0, 13)));
1976
+ let wp1 = {
1977
+ name: fields[0].substring(13).trim(),
1978
+ time: DateTimeUtils.convertHHMMSSToTod(fields[1].substring(0, 6)),
1979
+ timeFormat: "tod"
1980
+ };
1981
+ ResultFormatter.altitude(decodeResult, Number(fields[1].substring(6, 9)) * 100);
1982
+ let wp2 = {
1983
+ name: fields[1].substring(9).trim(),
1984
+ time: DateTimeUtils.convertHHMMSSToTod(fields[2]),
1985
+ timeFormat: "tod"
1986
+ };
1987
+ ResultFormatter.route(decodeResult, { waypoints: [wp1, wp2] });
1988
+ ResultFormatter.temperature(decodeResult, fields[3]);
1989
+ ResultFormatter.unknownArr(decodeResult, fields.slice(4));
1990
+ } else {
1991
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[0]));
1992
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1]));
1993
+ ResultFormatter.unknown(decodeResult, fields[2]);
1994
+ ResultFormatter.altitude(decodeResult, Number(fields[3]));
1995
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates((fields[4] + fields[5]).replace(/[ \.]/g, "")));
1996
+ }
1997
+ } else {
1998
+ decodeResult.decoded = false;
1999
+ ResultFormatter.unknown(decodeResult, text);
2000
+ }
2001
+ if (decodeResult.decoded) {
2002
+ if (!decodeResult.remaining.text)
2003
+ decodeResult.decoder.decodeLevel = "full";
2004
+ else
2005
+ decodeResult.decoder.decodeLevel = "partial";
2006
+ } else {
2007
+ decodeResult.decoder.decodeLevel = "none";
2008
+ }
2009
+ return decodeResult;
2010
+ }
2011
+ };
2012
+
2013
+ // lib/plugins/Label_4A_01.ts
2014
+ var Label_4A_01 = class extends DecoderPlugin {
2015
+ name = "label-4a-01";
2016
+ qualifiers() {
2017
+ return {
2018
+ labels: ["4A"],
2019
+ preambles: ["01"]
2020
+ };
2021
+ }
2022
+ decode(message, options = {}) {
2023
+ const decodeResult = this.defaultResult();
2024
+ decodeResult.decoder.name = this.name;
2025
+ decodeResult.message = message;
2026
+ decodeResult.formatted.description = "Latest New Format";
2027
+ decodeResult.decoded = true;
2028
+ 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)/);
2029
+ if (rgx) {
2030
+ ResultFormatter.state_change(decodeResult, rgx[1], rgx[2]);
2031
+ ResultFormatter.callsign(decodeResult, rgx[3]);
2032
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(rgx[4] + "00"));
2033
+ ResultFormatter.departureAirport(decodeResult, rgx[5]);
2034
+ ResultFormatter.arrivalAirport(decodeResult, rgx[6]);
2035
+ ResultFormatter.altitude(decodeResult, Number(rgx[7].replace(/ /g, "")));
2036
+ ResultFormatter.unknown(decodeResult, rgx[8]);
2037
+ ResultFormatter.temperature(decodeResult, rgx[9].replace(/ /g, ""));
2038
+ } else {
2039
+ decodeResult.decoded = false;
2040
+ ResultFormatter.unknown(decodeResult, message.text);
2041
+ }
2042
+ if (decodeResult.decoded) {
2043
+ if (!decodeResult.remaining.text)
2044
+ decodeResult.decoder.decodeLevel = "full";
2045
+ else
2046
+ decodeResult.decoder.decodeLevel = "partial";
2047
+ } else {
2048
+ decodeResult.decoder.decodeLevel = "none";
2049
+ }
2050
+ return decodeResult;
2051
+ }
2052
+ };
2053
+
2054
+ // lib/plugins/Label_4A_DIS.ts
2055
+ var Label_4A_DIS = class extends DecoderPlugin {
2056
+ name = "label-4a-dis";
2057
+ qualifiers() {
2058
+ return {
2059
+ labels: ["4A"],
2060
+ preambles: ["DIS"]
2061
+ };
2062
+ }
2063
+ decode(message, options = {}) {
2064
+ const decodeResult = this.defaultResult();
2065
+ decodeResult.decoder.name = this.name;
2066
+ decodeResult.message = message;
2067
+ decodeResult.formatted.description = "Latest New Format";
2068
+ decodeResult.decoded = true;
2069
+ const fields = message.text.split(",");
2070
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(2) + "00"));
2071
+ ResultFormatter.callsign(decodeResult, fields[2]);
2072
+ ResultFormatter.freetext(decodeResult, fields.slice(3).join(""));
2073
+ if (decodeResult.decoded) {
2074
+ if (!decodeResult.remaining.text)
2075
+ decodeResult.decoder.decodeLevel = "full";
2076
+ else
2077
+ decodeResult.decoder.decodeLevel = "partial";
2078
+ } else {
2079
+ decodeResult.decoder.decodeLevel = "none";
2080
+ }
2081
+ return decodeResult;
2082
+ }
2083
+ };
2084
+
2085
+ // lib/plugins/Label_4A_DOOR.ts
2086
+ var Label_4A_DOOR = class extends DecoderPlugin {
2087
+ name = "label-4a-door";
2088
+ qualifiers() {
2089
+ return {
2090
+ labels: ["4A"],
2091
+ preambles: ["DOOR"]
2092
+ };
2093
+ }
2094
+ decode(message, options = {}) {
2095
+ const decodeResult = this.defaultResult();
2096
+ decodeResult.decoder.name = this.name;
2097
+ decodeResult.message = message;
2098
+ decodeResult.formatted.description = "Latest New Format";
2099
+ decodeResult.decoded = true;
2100
+ const fields = message.text.split(" ");
2101
+ if (fields.length === 3) {
2102
+ ResultFormatter.door_event(decodeResult, fields[0].split("/")[1], fields[1]);
2103
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2] + "00"));
2104
+ } else {
2105
+ decodeResult.decoded = false;
2106
+ ResultFormatter.unknown(decodeResult, message.text);
2107
+ }
2108
+ if (decodeResult.decoded) {
2109
+ if (!decodeResult.remaining.text)
2110
+ decodeResult.decoder.decodeLevel = "full";
2111
+ else
2112
+ decodeResult.decoder.decodeLevel = "partial";
2113
+ } else {
2114
+ decodeResult.decoder.decodeLevel = "none";
2115
+ }
2116
+ return decodeResult;
2117
+ }
2118
+ };
2119
+
2120
+ // lib/plugins/Label_4A_Slash_01.ts
2121
+ var Label_4A_Slash_01 = class extends DecoderPlugin {
2122
+ name = "label-4a-slash-01";
2123
+ qualifiers() {
2124
+ return {
2125
+ labels: ["4A"],
2126
+ preambles: ["/01"]
2127
+ };
2128
+ }
2129
+ decode(message, options = {}) {
2130
+ const decodeResult = this.defaultResult();
2131
+ decodeResult.decoder.name = this.name;
2132
+ decodeResult.message = message;
2133
+ decodeResult.formatted.description = "Latest New Format";
2134
+ decodeResult.decoded = true;
2135
+ if (message.text.length === 5 && message.text.substring(0, 4) === "/01-") {
2136
+ ResultFormatter.unknown(decodeResult, message.text.substring(4));
2137
+ } else {
2138
+ decodeResult.decoded = false;
2139
+ ResultFormatter.unknown(decodeResult, message.text);
2140
+ }
2141
+ if (decodeResult.decoded) {
2142
+ if (!decodeResult.remaining.text)
2143
+ decodeResult.decoder.decodeLevel = "full";
2144
+ else
2145
+ decodeResult.decoder.decodeLevel = "partial";
2146
+ } else {
2147
+ decodeResult.decoder.decodeLevel = "none";
2148
+ }
1530
2149
  return decodeResult;
1531
2150
  }
1532
2151
  };
@@ -1556,13 +2175,13 @@ var Label_4N = class extends DecoderPlugin {
1556
2175
  ResultFormatter.departureAirport(decodeResult, text.substring(8, 11));
1557
2176
  ResultFormatter.arrivalAirport(decodeResult, text.substring(13, 16));
1558
2177
  ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(30, 45).replace(/^(.)0/, "$1")));
1559
- ResultFormatter.altitude(decodeResult, text.substring(48, 51) * 100);
1560
- decodeResult.remaining.text = [text.substring(2, 4), text.substring(19, 29)].join(" ");
2178
+ ResultFormatter.altitude(decodeResult, Number(text.substring(48, 51)) * 100);
2179
+ ResultFormatter.unknownArr(decodeResult, [text.substring(2, 4), text.substring(19, 29)], " ");
1561
2180
  } else if (fields.length === 33) {
1562
2181
  decodeResult.raw.date = fields[3];
1563
2182
  if (fields[1] === "B") {
1564
2183
  ResultFormatter.position(decodeResult, { latitude: Number(fields[4]), longitude: Number(fields[5]) });
1565
- ResultFormatter.altitude(decodeResult, fields[6]);
2184
+ ResultFormatter.altitude(decodeResult, Number(fields[6]));
1566
2185
  }
1567
2186
  ResultFormatter.departureAirport(decodeResult, fields[8]);
1568
2187
  ResultFormatter.arrivalAirport(decodeResult, fields[9]);
@@ -1572,13 +2191,13 @@ var Label_4N = class extends DecoderPlugin {
1572
2191
  ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
1573
2192
  }
1574
2193
  ResultFormatter.checksum(decodeResult, fields[32]);
1575
- decodeResult.remaining.text = [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != "").join(",");
2194
+ ResultFormatter.unknownArr(decodeResult, [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != ""));
1576
2195
  } else {
1577
2196
  decodeResult.decoded = false;
1578
- decodeResult.remaining.text = text;
2197
+ ResultFormatter.unknown(decodeResult, text);
1579
2198
  }
1580
2199
  if (decodeResult.decoded) {
1581
- if (decodeResult.remaining.text === "")
2200
+ if (!decodeResult.remaining.text)
1582
2201
  decodeResult.decoder.decodeLevel = "full";
1583
2202
  else
1584
2203
  decodeResult.decoder.decodeLevel = "partial";
@@ -1671,23 +2290,14 @@ var Label_80 = class extends DecoderPlugin {
1671
2290
  break;
1672
2291
  }
1673
2292
  case "FOB": {
1674
- decodeResult.raw.fuel_on_board = match.groups.value;
1675
- decodeResult.formatted.items.push({
1676
- type: "fuel_on_board",
1677
- code: "FOB",
1678
- label: this.descriptions[match.groups.field],
1679
- value: decodeResult.raw.fuel_on_board
1680
- });
2293
+ const fob = Number(match.groups.value);
2294
+ if (!isNaN(fob)) {
2295
+ ResultFormatter.currentFuel(decodeResult, fob);
2296
+ }
1681
2297
  break;
1682
2298
  }
1683
2299
  case "HDG": {
1684
- decodeResult.raw.heading = Number(match.groups.value);
1685
- decodeResult.formatted.items.push({
1686
- type: "heading",
1687
- code: "HDG",
1688
- label: this.descriptions[match.groups.field],
1689
- value: decodeResult.raw.heading
1690
- });
2300
+ ResultFormatter.heading(decodeResult, Number(match.groups.value));
1691
2301
  break;
1692
2302
  }
1693
2303
  case "MCH": {
@@ -1777,17 +2387,20 @@ var Label_83 = class extends DecoderPlugin {
1777
2387
  if (fields[2].length > 5) {
1778
2388
  decodeResult.raw.day_of_month = fields[2].substring(5);
1779
2389
  }
1780
- decodeResult.remaining.text = fields[2].substring(0, 4);
2390
+ ResultFormatter.unknown(decodeResult, fields[2].substring(0, 4));
1781
2391
  const subfields = fields[3].split("/");
1782
2392
  ResultFormatter.departureAirport(decodeResult, subfields[0]);
1783
2393
  ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
1784
2394
  ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
1785
- ResultFormatter.eta(decodeResult, fields[6] + "00");
2395
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[6] + "00"));
1786
2396
  } else if (text.substring(0, 5) === "001PR") {
1787
2397
  decodeResult.raw.day_of_month = text.substring(5, 7);
1788
- ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(13, 28).replace(/\./g, "")));
2398
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(13, 28).replace(/\./g, ""));
2399
+ if (position) {
2400
+ ResultFormatter.position(decodeResult, position);
2401
+ }
1789
2402
  ResultFormatter.altitude(decodeResult, Number(text.substring(28, 33)));
1790
- decodeResult.remaining.text = text.substring(33);
2403
+ ResultFormatter.unknown(decodeResult, text.substring(33));
1791
2404
  } else {
1792
2405
  const fields = text.replace(/\s/g, "").split(",");
1793
2406
  if (fields.length === 9) {
@@ -1802,17 +2415,17 @@ var Label_83 = class extends DecoderPlugin {
1802
2415
  longitude: Number(fields[4].replace(/\s/g, ""))
1803
2416
  }
1804
2417
  );
1805
- ResultFormatter.altitude(decodeResult, fields[5]);
1806
- ResultFormatter.groundspeed(decodeResult, fields[6]);
1807
- ResultFormatter.heading(decodeResult, fields[7]);
1808
- decodeResult.remaining.text = fields[8];
2418
+ ResultFormatter.altitude(decodeResult, Number(fields[5]));
2419
+ ResultFormatter.groundspeed(decodeResult, Number(fields[6]));
2420
+ ResultFormatter.heading(decodeResult, Number(fields[7]));
2421
+ ResultFormatter.unknown(decodeResult, fields[8]);
1809
2422
  } else {
1810
2423
  decodeResult.decoded = false;
1811
- decodeResult.remaining.text = message.text;
2424
+ ResultFormatter.unknown(decodeResult, message.text);
1812
2425
  }
1813
2426
  }
1814
2427
  if (decodeResult.decoded) {
1815
- if (decodeResult.remaining.text === "")
2428
+ if (!decodeResult.remaining.text)
1816
2429
  decodeResult.decoder.decodeLevel = "full";
1817
2430
  else
1818
2431
  decodeResult.decoder.decodeLevel = "partial";
@@ -1838,24 +2451,13 @@ var Label_8E = class extends DecoderPlugin {
1838
2451
  decodeResult.message = message;
1839
2452
  const regex = /^(?<arrival_icao>\w{4}),(?<arrival_eta>\d{4})$/;
1840
2453
  const results = message.text.match(regex);
1841
- if (results) {
2454
+ if (results?.groups) {
1842
2455
  if (options.debug) {
1843
2456
  console.log(`Label 8E ETA: groups`);
1844
2457
  console.log(results.groups);
1845
2458
  }
1846
- decodeResult.formatted.items.push({
1847
- type: "eta",
1848
- code: "ETA",
1849
- label: "Estimated Time of Arrival",
1850
- value: DateTimeUtils.UTCToString(results.groups.arrival_eta)
1851
- });
1852
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1853
- decodeResult.formatted.items.push({
1854
- type: "destination",
1855
- code: "DST",
1856
- label: "Destination",
1857
- value: decodeResult.raw.arrival_icao
1858
- });
2459
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta + "00"));
2460
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1859
2461
  }
1860
2462
  decodeResult.decoded = true;
1861
2463
  decodeResult.decoder.decodeLevel = "full";
@@ -1900,7 +2502,8 @@ var Label_ColonComma = class extends DecoderPlugin {
1900
2502
  decodeResult.formatted.items.push({
1901
2503
  type: "frequency",
1902
2504
  label: "Frequency",
1903
- value: `${decodeResult.raw.frequency} MHz`
2505
+ value: `${decodeResult.raw.frequency} MHz`,
2506
+ code: "FREQ"
1904
2507
  });
1905
2508
  decodeResult.decoded = true;
1906
2509
  decodeResult.decoder.decodeLevel = "full";
@@ -1908,62 +2511,6 @@ var Label_ColonComma = class extends DecoderPlugin {
1908
2511
  }
1909
2512
  };
1910
2513
 
1911
- // lib/plugins/Label_H1_FLR.ts
1912
- var Label_H1_FLR = class extends DecoderPlugin {
1913
- name = "label-h1-flr";
1914
- qualifiers() {
1915
- return {
1916
- labels: ["H1"],
1917
- preambles: ["FLR", "#CFBFLR"]
1918
- };
1919
- }
1920
- decode(message, options = {}) {
1921
- let decodeResult = this.defaultResult();
1922
- decodeResult.decoder.name = this.name;
1923
- decodeResult.formatted.description = "Fault Log Report";
1924
- decodeResult.message = message;
1925
- const parts = message.text.split("/FR");
1926
- if (parts.length > 1) {
1927
- decodeResult.remaining.text = "";
1928
- const fields = parts[0].split("/");
1929
- for (let i = 1; i < fields.length; i++) {
1930
- const field = fields[i];
1931
- if (field.startsWith("PN")) {
1932
- processUnknown(decodeResult, "/" + field);
1933
- } else {
1934
- processUnknown(decodeResult, "/" + field);
1935
- }
1936
- }
1937
- const data = parts[1].substring(0, 20);
1938
- const msg = parts[1].substring(20);
1939
- const datetime = data.substring(0, 12);
1940
- const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
1941
- processUnknown(decodeResult, data.substring(12));
1942
- decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
1943
- decodeResult.raw.fault_message = msg;
1944
- decodeResult.formatted.items.push({
1945
- type: "fault",
1946
- code: "FR",
1947
- label: "Fault Report",
1948
- value: decodeResult.raw.fault_message
1949
- });
1950
- decodeResult.decoded = true;
1951
- decodeResult.decoder.decodeLevel = "partial";
1952
- } else {
1953
- if (options.debug) {
1954
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
1955
- }
1956
- decodeResult.remaining.text = message.text;
1957
- decodeResult.decoded = false;
1958
- decodeResult.decoder.decodeLevel = "none";
1959
- }
1960
- return decodeResult;
1961
- }
1962
- };
1963
- function processUnknown(decodeResult, value) {
1964
- decodeResult.remaining.text += value;
1965
- }
1966
-
1967
2514
  // lib/utils/flight_plan_utils.ts
1968
2515
  var FlightPlanUtils = class _FlightPlanUtils {
1969
2516
  /**
@@ -2005,6 +2552,8 @@ var FlightPlanUtils = class _FlightPlanUtils {
2005
2552
  case "R":
2006
2553
  addRunway(decodeResult, value);
2007
2554
  break;
2555
+ // case 'WS': // something about routes, has altitude, so current parsing won't work
2556
+ // break;
2008
2557
  default:
2009
2558
  if (allKnownFields) {
2010
2559
  decodeResult.remaining.text = "";
@@ -2067,13 +2616,7 @@ function addRunway(decodeResult, value) {
2067
2616
  }
2068
2617
  function addRoute(decodeResult, value) {
2069
2618
  const route = value.split(".");
2070
- decodeResult.raw.route = { waypoints: route.map((leg) => RouteUtils.getWaypoint(leg)) };
2071
- decodeResult.formatted.items.push({
2072
- type: "aircraft_route",
2073
- code: "ROUTE",
2074
- label: "Aircraft Route",
2075
- value: RouteUtils.routeToString(decodeResult.raw.route)
2076
- });
2619
+ ResultFormatter.route(decodeResult, { waypoints: route.map((leg) => RouteUtils.getWaypoint(leg)) });
2077
2620
  }
2078
2621
  function addProcedure(decodeResult, value, type) {
2079
2622
  if (decodeResult.raw.procedures === void 0) {
@@ -2126,11 +2669,10 @@ function addCompanyRoute(decodeResult, value) {
2126
2669
  // lib/utils/h1_helper.ts
2127
2670
  var H1Helper = class {
2128
2671
  static decodeH1Message(decodeResult, message) {
2129
- let allKnownFields = true;
2130
2672
  const checksum = message.slice(-4);
2131
2673
  const data = message.slice(0, message.length - 4);
2132
2674
  const fields = data.split("/");
2133
- allKnownFields = allKnownFields && parseMessageType(decodeResult, fields[0]);
2675
+ parseMessageType(decodeResult, fields[0]);
2134
2676
  for (let i = 1; i < fields.length; ++i) {
2135
2677
  if (fields[i].startsWith("FN")) {
2136
2678
  decodeResult.raw.flight_number = fields[i].substring(2);
@@ -2149,59 +2691,49 @@ var H1Helper = class {
2149
2691
  decodeResult.raw.message_timestamp = time;
2150
2692
  } else if (fields[i].startsWith("PS")) {
2151
2693
  const pos = processPS(decodeResult, fields[i].substring(2).split(","));
2152
- allKnownFields == allKnownFields && pos;
2153
2694
  } else if (fields[i].startsWith("DT")) {
2154
2695
  const data2 = fields[i].substring(2).split(",");
2155
- const dt = processDT(decodeResult, data2);
2156
- allKnownFields = allKnownFields && dt;
2696
+ processDT(decodeResult, data2);
2157
2697
  } else if (fields[i].startsWith("ID")) {
2158
2698
  processIdentification(decodeResult, fields[i].substring(2).split(","));
2159
2699
  } else if (fields[i].startsWith("LR")) {
2160
2700
  const data2 = fields[i].substring(2).split(",");
2161
- const lr = processLR(decodeResult, data2);
2162
- allKnownFields = allKnownFields && lr;
2701
+ processLR(decodeResult, data2);
2163
2702
  } else if (fields[i].startsWith("RI") || fields[i].startsWith("RF") || fields[i].startsWith("RP")) {
2164
- const fp = FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
2165
- allKnownFields = allKnownFields && fp;
2703
+ FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
2166
2704
  } else if (fields[i].startsWith("PR")) {
2167
- allKnownFields = false;
2168
- decodeResult.remaining.text += "/" + fields[i];
2169
- } else if (fields[i].startsWith("PS")) {
2170
- allKnownFields = false;
2171
- decodeResult.remaining.text += fields[i];
2705
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
2172
2706
  } else if (fields[i].startsWith("AF")) {
2173
- const af = processAirField(decodeResult, fields[i].substring(2).split(","));
2174
- allKnownFields = allKnownFields && af;
2707
+ processAirField(decodeResult, fields[i].substring(2).split(","));
2175
2708
  } else if (fields[i].startsWith("TD")) {
2176
- const td = processTimeOfDeparture(decodeResult, fields[i].substring(2).split(","));
2177
- allKnownFields = allKnownFields && td;
2709
+ processTimeOfDeparture(decodeResult, fields[i].substring(2).split(","));
2178
2710
  } else if (fields[i].startsWith("FX")) {
2179
- decodeResult.raw.free_text = fields[i].substring(2);
2180
- decodeResult.formatted.items.push({
2181
- type: "text",
2182
- code: "TEXT",
2183
- label: "Free Text",
2184
- value: decodeResult.raw.free_text
2185
- });
2711
+ ResultFormatter.freetext(decodeResult, fields[i].substring(2));
2712
+ } else if (fields[i].startsWith("ET")) {
2713
+ if (fields[i].length === 7) {
2714
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(3) + "00"));
2715
+ } else if (fields[i].length === 8) {
2716
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(4) + "00"));
2717
+ } else {
2718
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
2719
+ }
2186
2720
  } else {
2187
- decodeResult.remaining.text += "/" + fields[i];
2188
- allKnownFields = false;
2721
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
2189
2722
  }
2190
2723
  }
2191
2724
  if (decodeResult.formatted.items.length > 0) {
2192
2725
  ResultFormatter.checksum(decodeResult, checksum);
2193
2726
  }
2194
- return allKnownFields;
2727
+ return true;
2195
2728
  }
2196
2729
  };
2197
2730
  function processAirField(decodeResult, data) {
2198
2731
  if (data.length === 2) {
2199
2732
  ResultFormatter.departureAirport(decodeResult, data[0]);
2200
2733
  ResultFormatter.arrivalAirport(decodeResult, data[1]);
2201
- return true;
2734
+ } else {
2735
+ ResultFormatter.unknown(decodeResult, data.join(","), "AF/");
2202
2736
  }
2203
- decodeResult.remaining.text += "AF/" + data.join(",");
2204
- return false;
2205
2737
  }
2206
2738
  function processTimeOfDeparture(decodeResult, data) {
2207
2739
  if (data.length === 2) {
@@ -2219,10 +2751,9 @@ function processTimeOfDeparture(decodeResult, data) {
2219
2751
  label: "Estimated Departure Time",
2220
2752
  value: `${data[1].substring(0, 2)}:${data[1].substring(2)}`
2221
2753
  });
2222
- return true;
2754
+ } else {
2755
+ ResultFormatter.unknown(decodeResult, data.join(","), "/TD");
2223
2756
  }
2224
- decodeResult.remaining.text += "/TD" + data.join(",");
2225
- return false;
2226
2757
  }
2227
2758
  function processIdentification(decodeResult, data) {
2228
2759
  ResultFormatter.tail(decodeResult, data[0]);
@@ -2234,11 +2765,10 @@ function processIdentification(decodeResult, data) {
2234
2765
  }
2235
2766
  }
2236
2767
  function processDT(decodeResult, data) {
2237
- let allKnownFields = true;
2238
2768
  if (!decodeResult.raw.arrival_icao) {
2239
2769
  ResultFormatter.arrivalAirport(decodeResult, data[0]);
2240
2770
  } else if (decodeResult.raw.arrival_icao != data[0]) {
2241
- decodeResult.remaining.text += "/" + data;
2771
+ ResultFormatter.unknownArr(decodeResult, data);
2242
2772
  }
2243
2773
  if (data.length > 1) {
2244
2774
  ResultFormatter.arrivalRunway(decodeResult, data[1]);
@@ -2247,19 +2777,16 @@ function processDT(decodeResult, data) {
2247
2777
  ResultFormatter.currentFuel(decodeResult, Number(data[2]));
2248
2778
  }
2249
2779
  if (data.length > 3) {
2250
- ResultFormatter.eta(decodeResult, data[3]);
2780
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[3]));
2251
2781
  }
2252
2782
  if (data.length > 4) {
2253
2783
  ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
2254
2784
  }
2255
2785
  if (data.length > 5) {
2256
- allKnownFields = false;
2257
- decodeResult.remaining.text += "," + data.slice(5).join(",");
2786
+ ResultFormatter.unknownArr(decodeResult, data);
2258
2787
  }
2259
- return allKnownFields;
2260
2788
  }
2261
2789
  function processLR(decodeResult, data) {
2262
- let allKnownFields = true;
2263
2790
  if (data.length === 19) {
2264
2791
  ResultFormatter.unknown(decodeResult, data[1]);
2265
2792
  ResultFormatter.flightNumber(decodeResult, data[2]);
@@ -2267,34 +2794,47 @@ function processLR(decodeResult, data) {
2267
2794
  ResultFormatter.arrivalAirport(decodeResult, data[4]);
2268
2795
  ResultFormatter.arrivalRunway(decodeResult, data[5]);
2269
2796
  ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
2270
- allKnownFields = false;
2271
2797
  } else {
2272
- allKnownFields = false;
2798
+ ResultFormatter.unknown(decodeResult, data.join(","));
2273
2799
  }
2274
- return allKnownFields;
2275
2800
  }
2276
2801
  function parseMessageType(decodeResult, messageType) {
2277
- let decoded = true;
2278
2802
  const parts = messageType.split("#");
2279
2803
  if (parts.length == 1) {
2280
- if (parts[0].startsWith("POS") && parts[0].length !== 3 && !parts[0].startsWith("POS/")) {
2281
- decoded = processPosition2(decodeResult, parts[0].substring(3).split(","));
2804
+ const type = parts[0].substring(0, 3);
2805
+ if (type === "POS" && parts[0].length !== 3) {
2806
+ processPosition2(decodeResult, parts[0].substring(3).split(","));
2282
2807
  }
2283
- return decoded;
2808
+ return processMessageType(decodeResult, type);
2284
2809
  } else if (parts.length == 2) {
2285
2810
  if (parts[0].length > 0) {
2286
- decodeResult.remaining.text += parts[0].substring(0, 3);
2811
+ ResultFormatter.unknown(decodeResult, parts[0].substring(0, 3));
2287
2812
  decodeResult.raw.flight_number = parts[0].substring(3);
2288
- decodeResult.remaining.text += "#" + parts[1].substring(0, 3);
2813
+ ResultFormatter.unknown(decodeResult, parts[1].length == 5 ? parts[1].substring(0, 2) : parts[1].substring(0, 3), "#");
2289
2814
  }
2290
- if (parts[1].substring(3, 6) === "POS" && parts[1].length !== 6 && parts[1].substring(3, 7) !== "POS/") {
2291
- decoded = processPosition2(decodeResult, parts[1].substring(6).split(","));
2815
+ const type = parts[1].length == 5 ? parts[1].substring(2, 5) : parts[1].substring(3, 6);
2816
+ if (parts[1].substring(3, 6) === "POS" && parts[1].length > 6) {
2817
+ processPosition2(decodeResult, parts[1].substring(6).split(","));
2292
2818
  }
2293
- decodeResult.raw.message_type = messageType;
2294
- return decoded;
2819
+ processMessageType(decodeResult, type);
2820
+ } else {
2821
+ ResultFormatter.unknown(decodeResult, messageType);
2822
+ }
2823
+ }
2824
+ function processMessageType(decodeResult, type) {
2825
+ if (type === "FPN") {
2826
+ decodeResult.formatted.description = "Flight Plan";
2827
+ } else if (type === "FTX") {
2828
+ decodeResult.formatted.description = "Free Text";
2829
+ } else if (type === "INI") {
2830
+ decodeResult.formatted.description = "Flight Plan Initial Report";
2831
+ } else if (type === "POS") {
2832
+ decodeResult.formatted.description = "Position Report";
2833
+ } else if (type === "PRG") {
2834
+ decodeResult.formatted.description = "Progress Report";
2835
+ } else {
2836
+ decodeResult.formatted.description = "Unknown H1 Message";
2295
2837
  }
2296
- decodeResult.remaining.text += messageType;
2297
- return false;
2298
2838
  }
2299
2839
  function processDC(decodeResult, data) {
2300
2840
  decodeResult.raw.message_date = data[0];
@@ -2303,13 +2843,9 @@ function processDC(decodeResult, data) {
2303
2843
  const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
2304
2844
  const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
2305
2845
  decodeResult.raw.message_timestamp = time;
2306
- } else {
2307
- return false;
2308
2846
  }
2309
- return true;
2310
2847
  }
2311
2848
  function processPS(decodeResult, data) {
2312
- let allKnownFields = true;
2313
2849
  const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2314
2850
  if (position) {
2315
2851
  decodeResult.raw.position = position;
@@ -2319,8 +2855,6 @@ function processPS(decodeResult, data) {
2319
2855
  label: "Aircraft Position",
2320
2856
  value: CoordinateUtils.coordinateString(position)
2321
2857
  });
2322
- } else {
2323
- allKnownFields = false;
2324
2858
  }
2325
2859
  if (data.length === 9) {
2326
2860
  processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
@@ -2339,11 +2873,8 @@ function processPS(decodeResult, data) {
2339
2873
  ResultFormatter.unknown(decodeResult, data[9]);
2340
2874
  ResultFormatter.unknown(decodeResult, data.slice(11).join(","));
2341
2875
  }
2342
- allKnownFields = false;
2343
- return allKnownFields;
2344
2876
  }
2345
2877
  function processPosition2(decodeResult, data) {
2346
- let allKnownFields = true;
2347
2878
  const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2348
2879
  if (position) {
2349
2880
  decodeResult.raw.position = position;
@@ -2353,8 +2884,6 @@ function processPosition2(decodeResult, data) {
2353
2884
  label: "Aircraft Position",
2354
2885
  value: CoordinateUtils.coordinateString(position)
2355
2886
  });
2356
- } else {
2357
- allKnownFields = false;
2358
2887
  }
2359
2888
  if (data.length >= 10) {
2360
2889
  ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
@@ -2369,8 +2898,6 @@ function processPosition2(decodeResult, data) {
2369
2898
  ResultFormatter.unknown(decodeResult, data[12]);
2370
2899
  ResultFormatter.unknown(decodeResult, data[13]);
2371
2900
  }
2372
- allKnownFields = false;
2373
- return allKnownFields;
2374
2901
  }
2375
2902
  function processRoute(decodeResult, last, time, next, eta, then, date) {
2376
2903
  const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
@@ -2393,30 +2920,27 @@ function processRoute(decodeResult, last, time, next, eta, then, date) {
2393
2920
  });
2394
2921
  }
2395
2922
 
2396
- // lib/plugins/Label_H1_FPN.ts
2397
- var Label_H1_FPN = class extends DecoderPlugin {
2398
- name = "label-h1-fpn";
2923
+ // lib/plugins/Label_H1.ts
2924
+ var Label_H1 = class extends DecoderPlugin {
2925
+ name = "label-h1";
2399
2926
  qualifiers() {
2400
2927
  return {
2401
- labels: ["H1"],
2402
- preambles: ["FPN", "#M1BFPN"]
2928
+ labels: ["H1"]
2403
2929
  };
2404
2930
  }
2405
2931
  decode(message, options = {}) {
2406
2932
  let decodeResult = this.defaultResult();
2407
2933
  decodeResult.decoder.name = this.name;
2408
- decodeResult.formatted.description = "Flight Plan";
2409
2934
  decodeResult.message = message;
2410
- decodeResult.remaining.text = "";
2411
2935
  const msg = message.text.replace(/\n|\r/g, "");
2412
- const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, msg);
2413
- decodeResult.decoded = true;
2414
- decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
2936
+ const decoded = H1Helper.decodeH1Message(decodeResult, msg);
2937
+ decodeResult.decoded = decoded;
2938
+ decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
2415
2939
  if (decodeResult.formatted.items.length === 0) {
2416
2940
  if (options.debug) {
2417
2941
  console.log(`Decoder: Unknown H1 message: ${message.text}`);
2418
2942
  }
2419
- decodeResult.remaining.text = message.text;
2943
+ ResultFormatter.unknown(decodeResult, message.text);
2420
2944
  decodeResult.decoded = false;
2421
2945
  decodeResult.decoder.decodeLevel = "none";
2422
2946
  }
@@ -2424,60 +2948,47 @@ var Label_H1_FPN = class extends DecoderPlugin {
2424
2948
  }
2425
2949
  };
2426
2950
 
2427
- // lib/plugins/Label_H1_FTX.ts
2428
- var Label_H1_FTX = class extends DecoderPlugin {
2429
- name = "label-h1-ftx";
2951
+ // lib/plugins/Label_H1_FLR.ts
2952
+ var Label_H1_FLR = class extends DecoderPlugin {
2953
+ name = "label-h1-flr";
2430
2954
  qualifiers() {
2431
2955
  return {
2432
2956
  labels: ["H1"],
2433
- preambles: ["FTX", "- #MDFTX"]
2957
+ preambles: ["FLR", "#CFBFLR"]
2434
2958
  };
2435
2959
  }
2436
2960
  decode(message, options = {}) {
2437
2961
  let decodeResult = this.defaultResult();
2438
2962
  decodeResult.decoder.name = this.name;
2439
- decodeResult.formatted.description = "Free Text";
2963
+ decodeResult.formatted.description = "Fault Log Report";
2440
2964
  decodeResult.message = message;
2441
- decodeResult.remaining.text = "";
2442
- const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
2443
- decodeResult.decoded = true;
2444
- decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
2445
- if (decodeResult.formatted.items.length === 0) {
2446
- if (options.debug) {
2447
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
2965
+ const parts = message.text.split("/FR");
2966
+ if (parts.length > 1) {
2967
+ const fields = parts[0].split("/");
2968
+ for (let i = 1; i < fields.length; i++) {
2969
+ const field = fields[i];
2970
+ ResultFormatter.unknown(decodeResult, field, "/");
2448
2971
  }
2449
- decodeResult.remaining.text = message.text;
2450
- decodeResult.decoded = false;
2451
- decodeResult.decoder.decodeLevel = "none";
2452
- }
2453
- return decodeResult;
2454
- }
2455
- };
2456
-
2457
- // lib/plugins/Label_H1_INI.ts
2458
- var Label_H1_INI = class extends DecoderPlugin {
2459
- // eslint-disable-line camelcase
2460
- name = "label-h1-ini";
2461
- qualifiers() {
2462
- return {
2463
- labels: ["H1"],
2464
- preambles: ["INI", "- #MDINI"]
2465
- };
2466
- }
2467
- decode(message, options = {}) {
2468
- const decodeResult = this.defaultResult();
2469
- decodeResult.decoder.name = this.name;
2470
- decodeResult.formatted.description = "Flight Plan Initial Report";
2471
- decodeResult.message = message;
2472
- decodeResult.remaining.text = "";
2473
- const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
2474
- decodeResult.decoded = true;
2475
- decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
2476
- if (decodeResult.formatted.items.length === 0) {
2972
+ const data = parts[1].substring(0, 20);
2973
+ const msg = parts[1].substring(20);
2974
+ const datetime = data.substring(0, 12);
2975
+ const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
2976
+ ResultFormatter.unknown(decodeResult, data.substring(12), "/");
2977
+ decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
2978
+ decodeResult.raw.fault_message = msg;
2979
+ decodeResult.formatted.items.push({
2980
+ type: "fault",
2981
+ code: "FR",
2982
+ label: "Fault Report",
2983
+ value: decodeResult.raw.fault_message
2984
+ });
2985
+ decodeResult.decoded = true;
2986
+ decodeResult.decoder.decodeLevel = "partial";
2987
+ } else {
2477
2988
  if (options.debug) {
2478
2989
  console.log(`Decoder: Unknown H1 message: ${message.text}`);
2479
2990
  }
2480
- decodeResult.remaining.text = message.text;
2991
+ ResultFormatter.unknown(decodeResult, message.text);
2481
2992
  decodeResult.decoded = false;
2482
2993
  decodeResult.decoder.decodeLevel = "none";
2483
2994
  }
@@ -2500,7 +3011,6 @@ var Label_H1_OHMA = class extends DecoderPlugin {
2500
3011
  decodeResult.decoder.name = this.name;
2501
3012
  decodeResult.formatted.description = "OHMA Message";
2502
3013
  decodeResult.message = message;
2503
- decodeResult.remaining.text = "";
2504
3014
  const data = message.text.split("OHMA")[1];
2505
3015
  try {
2506
3016
  const compressedBuffer = Buffer.from(data, "base64");
@@ -2535,7 +3045,7 @@ var Label_H1_OHMA = class extends DecoderPlugin {
2535
3045
  if (options.debug) {
2536
3046
  console.log(`Decoder: Unknown H1 OHMA message: ${message.text}`, e);
2537
3047
  }
2538
- decodeResult.remaining.text += message.text;
3048
+ ResultFormatter.unknown(decodeResult, message.text);
2539
3049
  decodeResult.decoded = false;
2540
3050
  decodeResult.decoder.decodeLevel = "none";
2541
3051
  }
@@ -2543,14 +3053,13 @@ var Label_H1_OHMA = class extends DecoderPlugin {
2543
3053
  }
2544
3054
  };
2545
3055
 
2546
- // lib/plugins/Label_H1_POS.ts
2547
- var Label_H1_POS = class extends DecoderPlugin {
2548
- name = "label-h1-pos";
3056
+ // lib/plugins/Label_H1_StarPOS.ts
3057
+ var Label_H1_StarPOS = class extends DecoderPlugin {
3058
+ name = "label-h1-star-pos";
2549
3059
  qualifiers() {
2550
3060
  return {
2551
- labels: ["H1", "4J"],
2552
- preambles: ["POS", "#M1BPOS", "/.POS"]
2553
- //TODO - support data before #
3061
+ labels: ["H1"],
3062
+ preambles: ["*POS"]
2554
3063
  };
2555
3064
  }
2556
3065
  decode(message, options = {}) {
@@ -2558,18 +3067,28 @@ var Label_H1_POS = class extends DecoderPlugin {
2558
3067
  decodeResult.decoder.name = this.name;
2559
3068
  decodeResult.formatted.description = "Position Report";
2560
3069
  decodeResult.message = message;
2561
- decodeResult.remaining.text = "";
2562
- const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
2563
- decodeResult.decoded = true;
2564
- decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
2565
- if (decodeResult.formatted.items.length === 0) {
3070
+ const msg = message.text;
3071
+ if (msg.length !== 43 || !msg.startsWith("*POS")) {
2566
3072
  if (options.debug) {
2567
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
3073
+ console.log(`Decoder: Unknown H1 message: ${msg}`);
2568
3074
  }
2569
- decodeResult.remaining.text = message.text;
3075
+ ResultFormatter.unknown(decodeResult, msg);
2570
3076
  decodeResult.decoded = false;
2571
3077
  decodeResult.decoder.decodeLevel = "none";
3078
+ return decodeResult;
2572
3079
  }
3080
+ decodeResult.raw.month = Number(msg.substring(4, 6));
3081
+ decodeResult.raw.day_of_month = Number(msg.substring(6, 8));
3082
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(msg.substring(8, 12) + "00"));
3083
+ ResultFormatter.position(decodeResult, {
3084
+ // Deg Min, no sec
3085
+ latitude: CoordinateUtils.getDirection(msg.substring(12, 13)) * (Number(msg.substring(13, 15)) + Number(msg.substring(15, 17)) / 60),
3086
+ longitude: CoordinateUtils.getDirection(msg.substring(17, 18)) * (Number(msg.substring(18, 21)) + Number(msg.substring(21, 23)) / 60)
3087
+ });
3088
+ ResultFormatter.altitude(decodeResult, Number(msg.substring(23, 28)));
3089
+ ResultFormatter.unknown(decodeResult, msg.substring(28));
3090
+ decodeResult.decoded = true;
3091
+ decodeResult.decoder.decodeLevel = "partial";
2573
3092
  return decodeResult;
2574
3093
  }
2575
3094
  };
@@ -2590,21 +3109,13 @@ var Label_H1_WRN = class extends DecoderPlugin {
2590
3109
  decodeResult.message = message;
2591
3110
  const parts = message.text.split("/WN");
2592
3111
  if (parts.length > 1) {
2593
- decodeResult.remaining.text = "";
2594
3112
  const fields = parts[0].split("/");
2595
- for (let i = 1; i < fields.length; i++) {
2596
- const field = fields[i];
2597
- if (field.startsWith("PN")) {
2598
- processUnknown2(decodeResult, "/" + field);
2599
- } else {
2600
- processUnknown2(decodeResult, "/" + field);
2601
- }
2602
- }
3113
+ ResultFormatter.unknownArr(decodeResult, fields.slice(1), "/");
2603
3114
  const data = parts[1].substring(0, 20);
2604
3115
  const msg = parts[1].substring(20);
2605
3116
  const datetime = data.substring(0, 12);
2606
3117
  const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
2607
- processUnknown2(decodeResult, data.substring(12));
3118
+ ResultFormatter.unknown(decodeResult, data.substring(12), "/");
2608
3119
  decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
2609
3120
  decodeResult.raw.warning_message = msg;
2610
3121
  decodeResult.formatted.items.push({
@@ -2619,16 +3130,13 @@ var Label_H1_WRN = class extends DecoderPlugin {
2619
3130
  if (options.debug) {
2620
3131
  console.log(`Decoder: Unknown H1 message: ${message.text}`);
2621
3132
  }
2622
- decodeResult.remaining.text = message.text;
3133
+ ResultFormatter.unknown(decodeResult, message.text);
2623
3134
  decodeResult.decoded = false;
2624
3135
  decodeResult.decoder.decodeLevel = "none";
2625
3136
  }
2626
3137
  return decodeResult;
2627
3138
  }
2628
3139
  };
2629
- function processUnknown2(decodeResult, value) {
2630
- decodeResult.remaining.text += value;
2631
- }
2632
3140
 
2633
3141
  // lib/plugins/Label_HX.ts
2634
3142
  var Label_HX = class extends DecoderPlugin {
@@ -2653,27 +3161,20 @@ var Label_HX = class extends DecoderPlugin {
2653
3161
  let londir = parts[4].substring(0, 1);
2654
3162
  let londeg = Number(parts[4].substring(1, 4));
2655
3163
  let lonmin = Number(parts[4].substring(4, 8));
2656
- decodeResult.raw.position = {
3164
+ let pos = {
2657
3165
  latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
2658
3166
  longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
2659
3167
  };
2660
- decodeResult.remaining.text = parts.slice(5).join(" ");
3168
+ ResultFormatter.unknownArr(decodeResult, parts.slice(5), " ");
3169
+ ResultFormatter.position(decodeResult, pos);
2661
3170
  } else if (parts[2] === "43") {
2662
3171
  ResultFormatter.departureAirport(decodeResult, parts[3]);
2663
- decodeResult.remaining.text = parts.slice(4).join(" ");
3172
+ ResultFormatter.unknownArr(decodeResult, parts.slice(4), " ");
2664
3173
  } else {
2665
3174
  decodeResult.decoded = false;
2666
3175
  }
2667
- if (decodeResult.raw.position) {
2668
- decodeResult.formatted.items.push({
2669
- type: "aircraft_position",
2670
- code: "POS",
2671
- label: "Aircraft Position",
2672
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
2673
- });
2674
- }
2675
3176
  if (decodeResult.decoded) {
2676
- if (decodeResult.remaining.text === "")
3177
+ if (!decodeResult.remaining.text)
2677
3178
  decodeResult.decoder.decodeLevel = "full";
2678
3179
  else
2679
3180
  decodeResult.decoder.decodeLevel = "partial";
@@ -2701,7 +3202,7 @@ var Label_SQ = class extends DecoderPlugin {
2701
3202
  if (decodeResult.raw.version === "2") {
2702
3203
  const regex = /0(\d)X(?<org>\w)(?<iata>\w\w\w)(?<icao>\w\w\w\w)(?<station>\d)(?<lat>\d+)(?<latd>[NS])(?<lng>\d+)(?<lngd>[EW])V(?<vfreq>\d+)\/.*/;
2703
3204
  const result = message.text.match(regex);
2704
- if (result && result.length >= 8) {
3205
+ if (result?.groups && result.length >= 8) {
2705
3206
  decodeResult.raw.groundStation = {
2706
3207
  number: result.groups.station,
2707
3208
  iataCode: result.groups.iata,
@@ -2711,7 +3212,7 @@ var Label_SQ = class extends DecoderPlugin {
2711
3212
  longitude: Number(result.groups.lng) / 100 * (result.groups.lngd === "W" ? -1 : 1)
2712
3213
  }
2713
3214
  };
2714
- decodeResult.raw.vdlFrequency = result.groups.vfreq / 1e3;
3215
+ decodeResult.raw.vdlFrequency = Number(result.groups.vfreq) / 1e3;
2715
3216
  }
2716
3217
  }
2717
3218
  decodeResult.formatted.description = "Ground Station Squitter";
@@ -2802,33 +3303,13 @@ var Label_QR = class extends DecoderPlugin {
2802
3303
  decode(message, options = {}) {
2803
3304
  const decodeResult = this.defaultResult();
2804
3305
  decodeResult.decoder.name = this.name;
2805
- decodeResult.raw.origin = message.text.substring(0, 4);
2806
- decodeResult.raw.destination = message.text.substring(4, 8);
2807
- decodeResult.raw.wheels_on = message.text.substring(8, 12);
2808
- decodeResult.remaining.text = message.text.substring(12);
2809
3306
  decodeResult.formatted.description = "ON Report";
2810
- decodeResult.formatted.items = [
2811
- {
2812
- type: "origin",
2813
- code: "ORG",
2814
- label: "Origin",
2815
- value: decodeResult.raw.origin
2816
- },
2817
- {
2818
- type: "destination",
2819
- code: "DST",
2820
- label: "Destination",
2821
- value: decodeResult.raw.destination
2822
- },
2823
- {
2824
- type: "wheels_on",
2825
- code: "WON",
2826
- label: "Wheels ON",
2827
- value: decodeResult.raw.wheels_on
2828
- }
2829
- ];
3307
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3308
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3309
+ ResultFormatter.on(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3310
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
2830
3311
  decodeResult.decoded = true;
2831
- if (decodeResult.remaining.text === "")
3312
+ if (!decodeResult.remaining.text)
2832
3313
  decodeResult.decoder.decodeLevel = "full";
2833
3314
  else
2834
3315
  decodeResult.decoder.decodeLevel = "partial";
@@ -2847,33 +3328,13 @@ var Label_QP = class extends DecoderPlugin {
2847
3328
  decode(message, options = {}) {
2848
3329
  const decodeResult = this.defaultResult();
2849
3330
  decodeResult.decoder.name = this.name;
2850
- decodeResult.raw.origin = message.text.substring(0, 4);
2851
- decodeResult.raw.destination = message.text.substring(4, 8);
2852
- decodeResult.raw.gate_out = message.text.substring(8, 12);
2853
- decodeResult.remaining.text = message.text.substring(12);
2854
3331
  decodeResult.formatted.description = "OUT Report";
2855
- decodeResult.formatted.items = [
2856
- {
2857
- type: "origin",
2858
- code: "ORG",
2859
- label: "Origin",
2860
- value: decodeResult.raw.origin
2861
- },
2862
- {
2863
- type: "destination",
2864
- code: "DST",
2865
- label: "Destination",
2866
- value: decodeResult.raw.destination
2867
- },
2868
- {
2869
- type: "gate_out",
2870
- code: "GOUT",
2871
- label: "Gate OUT",
2872
- value: decodeResult.raw.gate_out
2873
- }
2874
- ];
3332
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3333
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3334
+ ResultFormatter.out(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3335
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
2875
3336
  decodeResult.decoded = true;
2876
- if (decodeResult.remaining.text === "")
3337
+ if (!decodeResult.remaining.text)
2877
3338
  decodeResult.decoder.decodeLevel = "full";
2878
3339
  else
2879
3340
  decodeResult.decoder.decodeLevel = "partial";
@@ -2892,33 +3353,13 @@ var Label_QS = class extends DecoderPlugin {
2892
3353
  decode(message, options = {}) {
2893
3354
  const decodeResult = this.defaultResult();
2894
3355
  decodeResult.decoder.name = this.name;
2895
- decodeResult.raw.origin = message.text.substring(0, 4);
2896
- decodeResult.raw.destination = message.text.substring(4, 8);
2897
- decodeResult.raw.gate_in = message.text.substring(8, 12);
2898
- decodeResult.remaining.text = message.text.substring(12);
2899
3356
  decodeResult.formatted.description = "IN Report";
2900
- decodeResult.formatted.items = [
2901
- {
2902
- type: "origin",
2903
- code: "ORG",
2904
- label: "Origin",
2905
- value: decodeResult.raw.origin
2906
- },
2907
- {
2908
- type: "destination",
2909
- code: "DST",
2910
- label: "Destination",
2911
- value: decodeResult.raw.destination
2912
- },
2913
- {
2914
- type: "gate_in",
2915
- code: "GIN",
2916
- label: "Gate IN",
2917
- value: decodeResult.raw.gate_in
2918
- }
2919
- ];
3357
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3358
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3359
+ ResultFormatter.in(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3360
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
2920
3361
  decodeResult.decoded = true;
2921
- if (decodeResult.remaining.text === "")
3362
+ if (!decodeResult.remaining.text)
2922
3363
  decodeResult.decoder.decodeLevel = "full";
2923
3364
  else
2924
3365
  decodeResult.decoder.decodeLevel = "partial";
@@ -2941,46 +3382,33 @@ var Label_QQ = class extends DecoderPlugin {
2941
3382
  decodeResult.formatted.description = "OFF Report";
2942
3383
  ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
2943
3384
  ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
2944
- decodeResult.raw.wheels_off = message.text.substring(8, 12);
2945
3385
  if (message.text.substring(12, 19) === "\r\n001FE") {
2946
3386
  decodeResult.raw.day_of_month = message.text.substring(19, 21);
2947
- decodeResult.raw.wheels_off = message.text.substring(21, 27);
3387
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(21, 27)));
2948
3388
  let latdir = message.text.substring(27, 28);
2949
3389
  let latdeg = Number(message.text.substring(28, 30));
2950
3390
  let latmin = Number(message.text.substring(30, 34));
2951
3391
  let londir = message.text.substring(34, 35);
2952
3392
  let londeg = Number(message.text.substring(35, 38));
2953
3393
  let lonmin = Number(message.text.substring(38, 42));
2954
- decodeResult.raw.position = {
3394
+ let pos = {
2955
3395
  latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
2956
3396
  longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
2957
3397
  };
2958
- decodeResult.remaining.text = message.text.substring(42, 45);
3398
+ ResultFormatter.unknown(decodeResult, message.text.substring(42, 45));
3399
+ ResultFormatter.position(decodeResult, pos);
2959
3400
  if (decodeResult.remaining.text !== "---") {
2960
- ResultFormatter.groundspeed(decodeResult, message.text.substring(45, 48));
3401
+ ResultFormatter.groundspeed(decodeResult, Number(message.text.substring(45, 48)));
2961
3402
  } else {
2962
3403
  ResultFormatter.unknown(decodeResult, message.text.substring(45, 48));
2963
3404
  }
2964
3405
  ResultFormatter.unknown(decodeResult, message.text.substring(48));
2965
3406
  } else {
2966
- decodeResult.remaining.text = message.text.substring(12);
2967
- }
2968
- decodeResult.formatted.items.push({
2969
- type: "wheels_off",
2970
- code: "WOFF",
2971
- label: "Wheels OFF",
2972
- value: decodeResult.raw.wheels_off
2973
- });
2974
- if (decodeResult.raw.position) {
2975
- decodeResult.formatted.items.push({
2976
- type: "aircraft_position",
2977
- code: "POS",
2978
- label: "Aircraft Position",
2979
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
2980
- });
3407
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3408
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
2981
3409
  }
2982
3410
  decodeResult.decoded = true;
2983
- if (decodeResult.remaining.text === "")
3411
+ if (!decodeResult.remaining.text)
2984
3412
  decodeResult.decoder.decodeLevel = "full";
2985
3413
  else
2986
3414
  decodeResult.decoder.decodeLevel = "partial";
@@ -3800,7 +4228,7 @@ var MessageDecoder = class {
3800
4228
  this.plugins = [];
3801
4229
  this.debug = false;
3802
4230
  this.registerPlugin(new Label_ColonComma(this));
3803
- this.registerPlugin(new Label_5Z(this));
4231
+ this.registerPlugin(new Label_5Z_Slash(this));
3804
4232
  this.registerPlugin(new Label_10_LDR(this));
3805
4233
  this.registerPlugin(new Label_10_POS(this));
3806
4234
  this.registerPlugin(new Label_10_Slash(this));
@@ -3809,23 +4237,33 @@ var MessageDecoder = class {
3809
4237
  this.registerPlugin(new Label_15(this));
3810
4238
  this.registerPlugin(new Label_15_FST(this));
3811
4239
  this.registerPlugin(new Label_16_N_Space(this));
4240
+ this.registerPlugin(new Label_1L_3Line(this));
4241
+ this.registerPlugin(new Label_1L_070(this));
4242
+ this.registerPlugin(new Label_1L_660(this));
4243
+ this.registerPlugin(new Label_1L_Slash(this));
3812
4244
  this.registerPlugin(new Label_20_POS(this));
3813
4245
  this.registerPlugin(new Label_21_POS(this));
4246
+ this.registerPlugin(new Label_22_OFF(this));
4247
+ this.registerPlugin(new Label_22_POS(this));
4248
+ this.registerPlugin(new Label_24_Slash(this));
3814
4249
  this.registerPlugin(new Label_30_Slash_EA(this));
3815
4250
  this.registerPlugin(new Label_44_ETA(this));
3816
4251
  this.registerPlugin(new Label_44_IN(this));
3817
4252
  this.registerPlugin(new Label_44_OFF(this));
3818
4253
  this.registerPlugin(new Label_44_ON(this));
3819
4254
  this.registerPlugin(new Label_44_POS(this));
4255
+ this.registerPlugin(new Label_4A(this));
4256
+ this.registerPlugin(new Label_4A_01(this));
4257
+ this.registerPlugin(new Label_4A_DIS(this));
4258
+ this.registerPlugin(new Label_4A_DOOR(this));
4259
+ this.registerPlugin(new Label_4A_Slash_01(this));
3820
4260
  this.registerPlugin(new Label_4N(this));
3821
4261
  this.registerPlugin(new Label_B6_Forwardslash(this));
3822
- this.registerPlugin(new Label_H1_FPN(this));
3823
4262
  this.registerPlugin(new Label_H1_FLR(this));
3824
- this.registerPlugin(new Label_H1_FTX(this));
3825
- this.registerPlugin(new Label_H1_INI(this));
3826
4263
  this.registerPlugin(new Label_H1_OHMA(this));
3827
- this.registerPlugin(new Label_H1_POS(this));
3828
4264
  this.registerPlugin(new Label_H1_WRN(this));
4265
+ this.registerPlugin(new Label_H1(this));
4266
+ this.registerPlugin(new Label_H1_StarPOS(this));
3829
4267
  this.registerPlugin(new Label_HX(this));
3830
4268
  this.registerPlugin(new Label_80(this));
3831
4269
  this.registerPlugin(new Label_83(this));
@@ -3873,29 +4311,30 @@ var MessageDecoder = class {
3873
4311
  console.log("Usable plugins");
3874
4312
  console.log(usablePlugins);
3875
4313
  }
3876
- let result;
3877
- if (usablePlugins.length > 0) {
3878
- const plugin = usablePlugins[0];
4314
+ let result = {
4315
+ decoded: false,
4316
+ error: "No known decoder plugin for this message",
4317
+ decoder: {
4318
+ name: "none",
4319
+ type: "none",
4320
+ decodeLevel: "none"
4321
+ },
4322
+ message,
4323
+ remaining: {
4324
+ text: message.text
4325
+ },
4326
+ raw: {},
4327
+ formatted: {
4328
+ description: "Not Decoded",
4329
+ items: []
4330
+ }
4331
+ };
4332
+ for (let i = 0; i < usablePlugins.length; i++) {
4333
+ const plugin = usablePlugins[i];
3879
4334
  result = plugin.decode(message);
3880
- } else {
3881
- result = {
3882
- decoded: false,
3883
- error: "No known decoder plugin for this message",
3884
- decoder: {
3885
- name: "none",
3886
- type: "none",
3887
- decodeLevel: "none"
3888
- },
3889
- message,
3890
- remaining: {
3891
- text: message.text
3892
- },
3893
- raw: {},
3894
- formatted: {
3895
- description: "Not Decoded",
3896
- items: []
3897
- }
3898
- };
4335
+ if (result.decoded) {
4336
+ break;
4337
+ }
3899
4338
  }
3900
4339
  if (options.debug) {
3901
4340
  console.log("Result");