@airframes/acars-decoder 1.6.13 → 1.6.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -38,10 +38,13 @@ var DateTimeUtils = class {
38
38
  }
39
39
  /**
40
40
  *
41
- * @param time HHMMSS
41
+ * @param time HHMMSS or HHMM
42
42
  * @returns seconds since midnight
43
43
  */
44
44
  static convertHHMMSSToTod(time) {
45
+ if (time.length === 4) {
46
+ time += "00";
47
+ }
45
48
  const h = Number(time.substring(0, 2));
46
49
  const m = Number(time.substring(2, 4));
47
50
  const s = Number(time.substring(4, 6));
@@ -566,27 +569,36 @@ var ResultFormatter = class {
566
569
  });
567
570
  }
568
571
  static day(decodeResult, day) {
569
- decodeResult.raw.day_of_month = day;
572
+ decodeResult.raw.day = day;
570
573
  decodeResult.formatted.items.push({
571
- type: "day_of_month",
574
+ type: "day",
572
575
  code: "MSG_DAY",
573
576
  label: "Day of Month",
574
577
  value: `${day}`
575
578
  });
576
579
  }
580
+ static month(decodeResult, month) {
581
+ decodeResult.raw.month = month;
582
+ decodeResult.formatted.items.push({
583
+ type: "month",
584
+ code: "MSG_MON",
585
+ label: "Month of Year",
586
+ value: `${month}`
587
+ });
588
+ }
577
589
  static departureDay(decodeResult, day) {
578
- decodeResult.raw.departure_day_of_month = day;
590
+ decodeResult.raw.departure_day = day;
579
591
  decodeResult.formatted.items.push({
580
- type: "day_of_month",
592
+ type: "day",
581
593
  code: "DEP_DAY",
582
594
  label: "Departure Day",
583
595
  value: `${day}`
584
596
  });
585
597
  }
586
598
  static arrivalDay(decodeResult, day) {
587
- decodeResult.raw.arrival_day_of_month = day;
599
+ decodeResult.raw.arrival_day = day;
588
600
  decodeResult.formatted.items.push({
589
- type: "day_of_month",
601
+ type: "day",
590
602
  code: "ARR_DAY",
591
603
  label: "Arrival Day",
592
604
  value: `${day}`
@@ -681,14 +693,14 @@ var Label_5Z_Slash = class extends DecoderPlugin {
681
693
  const info = data[2].split(" ");
682
694
  ResultFormatter.departureAirport(decodeResult, info[1]);
683
695
  ResultFormatter.arrivalAirport(decodeResult, info[2]);
684
- decodeResult.raw.day_of_month = Number(info[3]);
696
+ decodeResult.raw.day = Number(info[3]);
685
697
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
686
698
  ResultFormatter.arrivalRunway(decodeResult, info[5].slice(1));
687
699
  ResultFormatter.unknownArr(decodeResult, data.slice(3), "/");
688
700
  } else if (type === "B3") {
689
701
  ResultFormatter.departureAirport(decodeResult, header[1].substring(0, 3), "IATA");
690
702
  ResultFormatter.arrivalAirport(decodeResult, header[1].substring(3), "IATA");
691
- decodeResult.raw.day_of_month = Number(header[2]);
703
+ decodeResult.raw.day = Number(header[2]);
692
704
  ResultFormatter.arrivalRunway(decodeResult, header[3].slice(1));
693
705
  if (header.length > 4) {
694
706
  ResultFormatter.unknownArr(decodeResult, header.slice(4), "/");
@@ -697,7 +709,7 @@ var Label_5Z_Slash = class extends DecoderPlugin {
697
709
  const info = data[2].split(" ");
698
710
  ResultFormatter.departureAirport(decodeResult, info[1]);
699
711
  ResultFormatter.arrivalAirport(decodeResult, info[2]);
700
- decodeResult.raw.day_of_month = Number(info[3]);
712
+ decodeResult.raw.day = Number(info[3]);
701
713
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
702
714
  ResultFormatter.unknownArr(decodeResult, info.slice(5), " ");
703
715
  } else if (type === "C3") {
@@ -707,10 +719,10 @@ var Label_5Z_Slash = class extends DecoderPlugin {
707
719
  const airports = data[2].split(" ");
708
720
  ResultFormatter.departureAirport(decodeResult, airports[1]);
709
721
  ResultFormatter.arrivalAirport(decodeResult, airports[2]);
710
- decodeResult.raw.day_of_month = Number(airports[3]);
722
+ decodeResult.raw.day = Number(airports[3]);
711
723
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(airports[4]));
712
724
  const estimates = data[3].split(" ");
713
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(estimates[1] + "00"));
725
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(estimates[1]));
714
726
  ResultFormatter.unknown(decodeResult, estimates[2]);
715
727
  } else {
716
728
  if (options.debug) {
@@ -854,16 +866,16 @@ var Label_10_Slash = class extends DecoderPlugin {
854
866
  ResultFormatter.heading(decodeResult, Number(parts[5]));
855
867
  ResultFormatter.altitude(decodeResult, 100 * Number(parts[6]));
856
868
  ResultFormatter.arrivalAirport(decodeResult, parts[7]);
857
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[8] + "00"));
869
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[8]));
858
870
  const waypoints = [{
859
871
  name: parts[11]
860
872
  }, {
861
873
  name: parts[12],
862
- time: DateTimeUtils.convertHHMMSSToTod(parts[13] + "00"),
874
+ time: DateTimeUtils.convertHHMMSSToTod(parts[13]),
863
875
  timeFormat: "tod"
864
876
  }, {
865
877
  name: parts[14],
866
- time: DateTimeUtils.convertHHMMSSToTod(parts[15] + "00"),
878
+ time: DateTimeUtils.convertHHMMSSToTod(parts[15]),
867
879
  timeFormat: "tod"
868
880
  }];
869
881
  ResultFormatter.route(decodeResult, { waypoints });
@@ -883,7 +895,7 @@ var Label_12_N_Space = class extends DecoderPlugin {
883
895
  qualifiers() {
884
896
  return {
885
897
  labels: ["12"],
886
- preambles: ["N "]
898
+ preambles: ["N ", "S "]
887
899
  };
888
900
  }
889
901
  decode(message, options = {}) {
@@ -949,7 +961,7 @@ var Label_13Through18_Slash = class extends DecoderPlugin {
949
961
  const data = parts[2].split(" ");
950
962
  ResultFormatter.departureAirport(decodeResult, data[1]);
951
963
  ResultFormatter.arrivalAirport(decodeResult, data[2]);
952
- decodeResult.raw.day_of_month = Number(data[3]);
964
+ decodeResult.raw.day = Number(data[3]);
953
965
  const time = DateTimeUtils.convertHHMMSSToTod(data[4]);
954
966
  if (labelNumber === 13) {
955
967
  ResultFormatter.out(decodeResult, time);
@@ -1009,7 +1021,7 @@ function getMsgType(labelNumber) {
1009
1021
 
1010
1022
  // lib/plugins/Label_15.ts
1011
1023
  var Label_15 = class extends DecoderPlugin {
1012
- name = "label-5z";
1024
+ name = "label-15";
1013
1025
  qualifiers() {
1014
1026
  return {
1015
1027
  labels: ["15"],
@@ -1020,10 +1032,28 @@ var Label_15 = class extends DecoderPlugin {
1020
1032
  const decodeResult = this.defaultResult();
1021
1033
  decodeResult.decoder.name = this.name;
1022
1034
  decodeResult.formatted.description = "Position Report";
1023
- const twoZeeRegex = /^\(2(?<between>.+)\(Z$/;
1024
- const results = message.text.match(twoZeeRegex);
1025
- if (results?.groups) {
1026
- ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.between.substr(0, 13)));
1035
+ decodeResult.message = message;
1036
+ if (message.text.startsWith("(2") && message.text.endsWith("(Z")) {
1037
+ const between = message.text.substring(2, message.text.length - 2);
1038
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(between.substring(0, 13)));
1039
+ if (between.length === 25) {
1040
+ ResultFormatter.unknown(decodeResult, between.substring(13, 19));
1041
+ const alt = between.substring(19, 22);
1042
+ if (alt != "---") {
1043
+ ResultFormatter.altitude(decodeResult, 100 * Number(alt));
1044
+ }
1045
+ ResultFormatter.temperature(decodeResult, between.substring(22).replace(" ", "0"));
1046
+ } else {
1047
+ ResultFormatter.unknown(decodeResult, between.substring(13));
1048
+ }
1049
+ } else {
1050
+ if (options.debug) {
1051
+ console.log(`Decoder: Unknown 15 message: ${message.text}`);
1052
+ }
1053
+ ResultFormatter.unknown(decodeResult, message.text);
1054
+ decodeResult.decoded = false;
1055
+ decodeResult.decoder.decodeLevel = "none";
1056
+ return decodeResult;
1027
1057
  }
1028
1058
  decodeResult.decoded = true;
1029
1059
  decodeResult.decoder.decodeLevel = "partial";
@@ -1076,7 +1106,7 @@ var Label_16_N_Space = class extends DecoderPlugin {
1076
1106
  qualifiers() {
1077
1107
  return {
1078
1108
  labels: ["16"],
1079
- preambles: ["N "]
1109
+ preambles: ["N ", "S "]
1080
1110
  };
1081
1111
  }
1082
1112
  decode(message, options = {}) {
@@ -1206,7 +1236,7 @@ var Label_1L_3Line = class extends DecoderPlugin {
1206
1236
  }
1207
1237
  const eta = data.get("ETA");
1208
1238
  if (eta) {
1209
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta + "00"));
1239
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta));
1210
1240
  data.delete("ETA");
1211
1241
  }
1212
1242
  const alt = data.get("ALT");
@@ -1287,8 +1317,8 @@ var Label_1L_070 = class extends DecoderPlugin {
1287
1317
  }
1288
1318
  ResultFormatter.departureAirport(decodeResult, parts[0]);
1289
1319
  ResultFormatter.arrivalAirport(decodeResult, parts[1]);
1290
- ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[2] + "00"));
1291
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[3] + "00"));
1320
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[2]));
1321
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[3]));
1292
1322
  ResultFormatter.position(decodeResult, {
1293
1323
  latitude: CoordinateUtils.getDirection(parts[4][0]) * Number(parts[4].substring(1)),
1294
1324
  longitude: CoordinateUtils.getDirection(parts[5][0]) * Number(parts[5].substring(1))
@@ -1408,7 +1438,7 @@ var Label_1L_Slash = class extends DecoderPlugin {
1408
1438
  }
1409
1439
  const eta = data.get("ETA");
1410
1440
  if (eta) {
1411
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta + "00"));
1441
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta));
1412
1442
  data.delete("ETA");
1413
1443
  }
1414
1444
  let remaining = "";
@@ -1542,7 +1572,7 @@ var Label_22_OFF = class extends DecoderPlugin {
1542
1572
  ResultFormatter.flightNumber(decodeResult, fields[0]);
1543
1573
  ResultFormatter.departureDay(decodeResult, Number(fields[1].substring(0, 2)));
1544
1574
  ResultFormatter.arrivalDay(decodeResult, Number(fields[1].substring(2, 4)));
1545
- ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(4, 8) + "00"));
1575
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(4, 8)));
1546
1576
  ResultFormatter.departureAirport(decodeResult, fields[1].substring(8, 12));
1547
1577
  ResultFormatter.arrivalAirport(decodeResult, fields[1].substring(12, 16));
1548
1578
  ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 22)));
@@ -1558,7 +1588,7 @@ var Label_22_OFF = class extends DecoderPlugin {
1558
1588
  }
1559
1589
  ResultFormatter.departureAirport(decodeResult, fields[0]);
1560
1590
  ResultFormatter.arrivalAirport(decodeResult, fields[1]);
1561
- ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2] + "00"));
1591
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2]));
1562
1592
  ResultFormatter.unknown(decodeResult, fields[3]);
1563
1593
  decodeResult.decoded = true;
1564
1594
  decodeResult.decoder.decodeLevel = "partial";
@@ -1575,12 +1605,12 @@ var Label_22_OFF = class extends DecoderPlugin {
1575
1605
  ResultFormatter.position(decodeResult, position);
1576
1606
  }
1577
1607
  ResultFormatter.day(decodeResult, Number(fields[1].substring(14, 16)));
1578
- ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 20) + "00"));
1608
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 20)));
1579
1609
  ResultFormatter.departureAirport(decodeResult, fields[1].substring(20, 24));
1580
1610
  ResultFormatter.arrivalAirport(decodeResult, fields[1].substring(24, 28));
1581
- ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(28, 32) + "00"));
1611
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(28, 32)));
1582
1612
  ResultFormatter.unknown(decodeResult, fields[1].substring(32, 36));
1583
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(36, 40) + "00"));
1613
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(36, 40)));
1584
1614
  decodeResult.decoded = true;
1585
1615
  decodeResult.decoder.decodeLevel = "partial";
1586
1616
  } else {
@@ -1662,7 +1692,7 @@ var Label_24_Slash = class extends DecoderPlugin {
1662
1692
  longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1))
1663
1693
  };
1664
1694
  ResultFormatter.position(decodeResult, position);
1665
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[8] + "00"));
1695
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[8]));
1666
1696
  ResultFormatter.unknown(decodeResult, fields[7]);
1667
1697
  decodeResult.decoded = true;
1668
1698
  decodeResult.decoder.decodeLevel = "partial";
@@ -1698,7 +1728,7 @@ var Label_30_Slash_EA = class extends DecoderPlugin {
1698
1728
  console.log(results);
1699
1729
  }
1700
1730
  }
1701
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results[0].substr(2, 4) + "00"));
1731
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results[0].substr(2, 4)));
1702
1732
  if (results[1].substring(0, 2) === "DS") {
1703
1733
  ResultFormatter.arrivalAirport(decodeResult, results[1].substring(2, 6));
1704
1734
  ResultFormatter.unknown(decodeResult, "/".concat(results[2]));
@@ -1725,22 +1755,35 @@ var Label_44_ETA = class extends DecoderPlugin {
1725
1755
  decodeResult.decoder.name = this.name;
1726
1756
  decodeResult.formatted.description = "ETA Report";
1727
1757
  decodeResult.message = message;
1728
- const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
1729
- const results = message.text.match(regex);
1730
- if (results?.groups) {
1758
+ const data = message.text.split(",");
1759
+ if (data.length >= 9) {
1731
1760
  if (options.debug) {
1732
1761
  console.log(`Label 44 ETA Report: groups`);
1733
- console.log(results.groups);
1762
+ console.log(data);
1734
1763
  }
1735
- ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords));
1736
- ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1737
- ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1738
- decodeResult.raw.current_time = Date.parse(
1739
- (/* @__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"
1740
- );
1741
- if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1742
- ResultFormatter.remainingFuel(decodeResult, Number(results.groups.fuel_in_tons));
1764
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[1]));
1765
+ ResultFormatter.altitude(decodeResult, 100 * Number(data[2]));
1766
+ ResultFormatter.departureAirport(decodeResult, data[3]);
1767
+ ResultFormatter.arrivalAirport(decodeResult, data[4]);
1768
+ ResultFormatter.month(decodeResult, Number(data[5].substring(0, 2)));
1769
+ ResultFormatter.day(decodeResult, Number(data[5].substring(2, 4)));
1770
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[6]));
1771
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[7]));
1772
+ const fuel = Number(data[8]);
1773
+ if (!isNaN(fuel)) {
1774
+ ResultFormatter.remainingFuel(decodeResult, Number(fuel));
1775
+ }
1776
+ if (data.length > 9) {
1777
+ ResultFormatter.unknownArr(decodeResult, data.slice(9));
1778
+ }
1779
+ } else {
1780
+ if (options.debug) {
1781
+ console.log(`Decoder: Unknown 44 message: ${message.text}`);
1743
1782
  }
1783
+ ResultFormatter.unknown(decodeResult, message.text);
1784
+ decodeResult.decoded = false;
1785
+ decodeResult.decoder.decodeLevel = "none";
1786
+ return decodeResult;
1744
1787
  }
1745
1788
  decodeResult.decoded = true;
1746
1789
  decodeResult.decoder.decodeLevel = "full";
@@ -1762,22 +1805,33 @@ var Label_44_IN = class extends DecoderPlugin {
1762
1805
  decodeResult.decoder.name = this.name;
1763
1806
  decodeResult.formatted.description = "In Air Report";
1764
1807
  decodeResult.message = message;
1765
- const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
1766
- const results = message.text.match(regex);
1767
- if (results?.groups) {
1808
+ const data = message.text.split(",");
1809
+ if (data.length >= 7) {
1768
1810
  if (options.debug) {
1769
1811
  console.log(`Label 44 In Air Report: groups`);
1770
- console.log(results.groups);
1812
+ console.log(data);
1771
1813
  }
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);
1775
- decodeResult.raw.current_time = Date.parse(
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"
1777
- );
1778
- if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1779
- decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1814
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[1]));
1815
+ ResultFormatter.departureAirport(decodeResult, data[2]);
1816
+ ResultFormatter.arrivalAirport(decodeResult, data[3]);
1817
+ ResultFormatter.month(decodeResult, Number(data[4].substring(0, 2)));
1818
+ ResultFormatter.day(decodeResult, Number(data[4].substring(2, 4)));
1819
+ ResultFormatter.in(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[5]));
1820
+ const fuel = Number(data[6]);
1821
+ if (!isNaN(fuel)) {
1822
+ ResultFormatter.remainingFuel(decodeResult, Number(fuel));
1823
+ }
1824
+ if (data.length > 7) {
1825
+ ResultFormatter.unknownArr(decodeResult, data.slice(7));
1826
+ }
1827
+ } else {
1828
+ if (options.debug) {
1829
+ console.log(`Decoder: Unknown 44 message: ${message.text}`);
1780
1830
  }
1831
+ ResultFormatter.unknown(decodeResult, message.text);
1832
+ decodeResult.decoded = false;
1833
+ decodeResult.decoder.decodeLevel = "none";
1834
+ return decodeResult;
1781
1835
  }
1782
1836
  decodeResult.decoded = true;
1783
1837
  decodeResult.decoder.decodeLevel = "full";
@@ -1799,25 +1853,34 @@ var Label_44_OFF = class extends DecoderPlugin {
1799
1853
  decodeResult.decoder.name = this.name;
1800
1854
  decodeResult.formatted.description = "Off Runway Report";
1801
1855
  decodeResult.message = message;
1802
- const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<eta_time>.*),(?<fuel_in_tons>.*)$/;
1803
- const results = message.text.match(regex);
1804
- if (results?.groups) {
1856
+ const data = message.text.split(",");
1857
+ if (data.length >= 8) {
1805
1858
  if (options.debug) {
1806
1859
  console.log(`Label 44 Off Runway Report: groups`);
1807
- console.log(results.groups);
1860
+ console.log(data);
1808
1861
  }
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);
1812
- decodeResult.raw.current_time = Date.parse(
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"
1814
- );
1815
- decodeResult.raw.eta_time = Date.parse(
1816
- (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.eta_time.substr(0, 2) + ":" + results.groups.eta_time.substr(2, 2) + ":00Z"
1817
- );
1818
- if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1819
- decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1862
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[1]));
1863
+ ResultFormatter.departureAirport(decodeResult, data[2]);
1864
+ ResultFormatter.arrivalAirport(decodeResult, data[3]);
1865
+ ResultFormatter.month(decodeResult, Number(data[4].substring(0, 2)));
1866
+ ResultFormatter.day(decodeResult, Number(data[4].substring(2, 4)));
1867
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[5]));
1868
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[6]));
1869
+ const fuel = Number(data[7]);
1870
+ if (!isNaN(fuel)) {
1871
+ ResultFormatter.remainingFuel(decodeResult, Number(fuel));
1872
+ }
1873
+ if (data.length > 8) {
1874
+ ResultFormatter.unknownArr(decodeResult, data.slice(8));
1875
+ }
1876
+ } else {
1877
+ if (options.debug) {
1878
+ console.log(`Decoder: Unknown 44 message: ${message.text}`);
1820
1879
  }
1880
+ ResultFormatter.unknown(decodeResult, message.text);
1881
+ decodeResult.decoded = false;
1882
+ decodeResult.decoder.decodeLevel = "none";
1883
+ return decodeResult;
1821
1884
  }
1822
1885
  decodeResult.decoded = true;
1823
1886
  decodeResult.decoder.decodeLevel = "full";
@@ -1839,22 +1902,33 @@ var Label_44_ON = class extends DecoderPlugin {
1839
1902
  decodeResult.decoder.name = this.name;
1840
1903
  decodeResult.formatted.description = "On Runway Report";
1841
1904
  decodeResult.message = message;
1842
- const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
1843
- const results = message.text.match(regex);
1844
- if (results?.groups) {
1905
+ const data = message.text.split(",");
1906
+ if (data.length >= 7) {
1845
1907
  if (options.debug) {
1846
1908
  console.log(`Label 44 On Runway Report: groups`);
1847
- console.log(results.groups);
1909
+ console.log(data);
1848
1910
  }
1849
- ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords));
1850
- ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1851
- ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1852
- decodeResult.raw.current_time = Date.parse(
1853
- (/* @__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"
1854
- );
1855
- if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1856
- ResultFormatter.remainingFuel(decodeResult, Number(results.groups.fuel_in_tons));
1911
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[1]));
1912
+ ResultFormatter.departureAirport(decodeResult, data[2]);
1913
+ ResultFormatter.arrivalAirport(decodeResult, data[3]);
1914
+ ResultFormatter.month(decodeResult, Number(data[4].substring(0, 2)));
1915
+ ResultFormatter.day(decodeResult, Number(data[4].substring(2, 4)));
1916
+ ResultFormatter.on(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[5]));
1917
+ const fuel = Number(data[6]);
1918
+ if (!isNaN(fuel)) {
1919
+ ResultFormatter.remainingFuel(decodeResult, Number(fuel));
1920
+ }
1921
+ if (data.length > 7) {
1922
+ ResultFormatter.unknownArr(decodeResult, data.slice(7));
1923
+ }
1924
+ } else {
1925
+ if (options.debug) {
1926
+ console.log(`Decoder: Unknown 44 message: ${message.text}`);
1857
1927
  }
1928
+ ResultFormatter.unknown(decodeResult, message.text);
1929
+ decodeResult.decoded = false;
1930
+ decodeResult.decoder.decodeLevel = "none";
1931
+ return decodeResult;
1858
1932
  }
1859
1933
  decodeResult.decoded = true;
1860
1934
  decodeResult.decoder.decodeLevel = "full";
@@ -2113,456 +2187,95 @@ var Label_4A_Slash_01 = class extends DecoderPlugin {
2113
2187
  }
2114
2188
  };
2115
2189
 
2116
- // lib/plugins/Label_4N.ts
2117
- var Label_4N = class extends DecoderPlugin {
2118
- name = "label-4n";
2119
- qualifiers() {
2120
- return {
2121
- labels: ["4N"]
2122
- };
2123
- }
2124
- decode(message, options = {}) {
2125
- const decodeResult = this.defaultResult();
2126
- decodeResult.decoder.name = this.name;
2127
- decodeResult.message = message;
2128
- decodeResult.formatted.description = "Airline Defined";
2129
- let text = message.text;
2130
- if (text.match(/^M\d{2}A\w{6}/)) {
2131
- ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
2132
- text = text.substring(10);
2133
- }
2134
- decodeResult.decoded = true;
2135
- const fields = text.split(",");
2136
- if (text.length === 51) {
2137
- decodeResult.raw.day_of_month = text.substring(0, 2);
2138
- ResultFormatter.departureAirport(decodeResult, text.substring(8, 11));
2139
- ResultFormatter.arrivalAirport(decodeResult, text.substring(13, 16));
2140
- ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(30, 45).replace(/^(.)0/, "$1")));
2141
- ResultFormatter.altitude(decodeResult, Number(text.substring(48, 51)) * 100);
2142
- ResultFormatter.unknownArr(decodeResult, [text.substring(2, 4), text.substring(19, 29)], " ");
2143
- } else if (fields.length === 33) {
2144
- decodeResult.raw.date = fields[3];
2145
- if (fields[1] === "B") {
2146
- ResultFormatter.position(decodeResult, { latitude: Number(fields[4]), longitude: Number(fields[5]) });
2147
- ResultFormatter.altitude(decodeResult, Number(fields[6]));
2148
- }
2149
- ResultFormatter.departureAirport(decodeResult, fields[8]);
2150
- ResultFormatter.arrivalAirport(decodeResult, fields[9]);
2151
- ResultFormatter.alternateAirport(decodeResult, fields[10]);
2152
- ResultFormatter.arrivalRunway(decodeResult, fields[11].split("/")[0]);
2153
- if (fields[12].length > 1) {
2154
- ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
2190
+ // lib/utils/flight_plan_utils.ts
2191
+ var FlightPlanUtils = class _FlightPlanUtils {
2192
+ /**
2193
+ * Processes flight plan data
2194
+ *
2195
+ * Expected format is [header, key1, val1, ... keyN, valN]
2196
+ *
2197
+ * @param decodeResult - results
2198
+ * @param data - original message split by ':'
2199
+ * @returns whether all fields were processed or not
2200
+ */
2201
+ static processFlightPlan(decodeResult, data) {
2202
+ let allKnownFields = _FlightPlanUtils.parseHeader(decodeResult, data[0]);
2203
+ for (let i = 1; i < data.length; i += 2) {
2204
+ const key = data[i];
2205
+ const value = data[i + 1];
2206
+ switch (key) {
2207
+ case "A":
2208
+ addProcedure(decodeResult, value, "arrival");
2209
+ break;
2210
+ case "AA":
2211
+ addArrivalAirport(decodeResult, value);
2212
+ break;
2213
+ case "AP":
2214
+ addProcedure(decodeResult, value, "approach");
2215
+ break;
2216
+ case "CR":
2217
+ addCompanyRoute(decodeResult, value);
2218
+ break;
2219
+ case "D":
2220
+ addProcedure(decodeResult, value, "departure");
2221
+ break;
2222
+ case "DA":
2223
+ addDepartureAirport(decodeResult, value);
2224
+ break;
2225
+ case "F":
2226
+ addRoute(decodeResult, value);
2227
+ break;
2228
+ case "R":
2229
+ addRunway(decodeResult, value);
2230
+ break;
2231
+ // case 'WS': // something about routes, has altitude, so current parsing won't work
2232
+ // break;
2233
+ default:
2234
+ if (allKnownFields) {
2235
+ decodeResult.remaining.text = "";
2236
+ allKnownFields = false;
2237
+ }
2238
+ decodeResult.remaining.text += `:${key}:${value}`;
2239
+ decodeResult.decoder.decodeLevel = "partial";
2155
2240
  }
2156
- ResultFormatter.checksum(decodeResult, fields[32]);
2157
- ResultFormatter.unknownArr(decodeResult, [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != ""));
2158
- } else {
2159
- decodeResult.decoded = false;
2160
- ResultFormatter.unknown(decodeResult, text);
2161
2241
  }
2162
- if (decodeResult.decoded) {
2163
- if (!decodeResult.remaining.text)
2164
- decodeResult.decoder.decodeLevel = "full";
2165
- else
2166
- decodeResult.decoder.decodeLevel = "partial";
2242
+ return allKnownFields;
2243
+ }
2244
+ static parseHeader(decodeResult, header) {
2245
+ let allKnownFields = true;
2246
+ if (header.startsWith("RF")) {
2247
+ decodeResult.formatted.items.push({
2248
+ type: "status",
2249
+ code: "ROUTE_STATUS",
2250
+ label: "Route Status",
2251
+ value: "Route Filed"
2252
+ });
2253
+ decodeResult.raw.route_status = "RF";
2254
+ if (header.length > 2) {
2255
+ addRoute(decodeResult, header.substring(2));
2256
+ }
2257
+ } else if (header.startsWith("RP")) {
2258
+ decodeResult.raw.route_status = "RP";
2259
+ decodeResult.formatted.items.push({
2260
+ type: "status",
2261
+ code: "ROUTE_STATUS",
2262
+ label: "Route Status",
2263
+ value: "Route Planned"
2264
+ });
2265
+ decodeResult.raw.route_status = header;
2266
+ } else if (header.startsWith("RI")) {
2267
+ decodeResult.raw.route_status = "RI";
2268
+ decodeResult.formatted.items.push({
2269
+ type: "status",
2270
+ code: "ROUTE_STATUS",
2271
+ label: "Route Status",
2272
+ value: "Route Inactive"
2273
+ });
2167
2274
  } else {
2168
- decodeResult.decoder.decodeLevel = "none";
2275
+ decodeResult.remaining.text += header;
2276
+ allKnownFields = false;
2169
2277
  }
2170
- return decodeResult;
2171
- }
2172
- };
2173
-
2174
- // lib/plugins/Label_80.ts
2175
- var Label_80 = class extends DecoderPlugin {
2176
- name = "label-80";
2177
- descriptions = {
2178
- ALT: "Altitude",
2179
- DWND: "Wind Direction",
2180
- ETA: "Estimated Time of Arrival",
2181
- FOB: "Fuel on Board",
2182
- FL: "Flight Level",
2183
- HDG: "Heading",
2184
- MCH: "Aircraft Speed",
2185
- NWYP: "Next Waypoint",
2186
- POS: "Aircraft Position",
2187
- SAT: "Static Air Temperature",
2188
- SWND: "Wind Speed",
2189
- TAS: "True Airspeed",
2190
- WYP: "Waypoint"
2191
- };
2192
- qualifiers() {
2193
- return {
2194
- labels: ["80"],
2195
- preambles: ["3N01 POSRPT"]
2196
- };
2197
- }
2198
- decode(message, options = {}) {
2199
- const decodeResult = this.defaultResult();
2200
- decodeResult.decoder.name = this.name;
2201
- decodeResult.formatted.description = "Airline Defined Position Report";
2202
- const parts = message.text.split("\n");
2203
- let posRptRegex = /^3N01 POSRPT \d\d\d\d\/\d\d (?<orig>\w+)\/(?<dest>\w+) \.(?<tail>[\w-]+)(\/(?<agate>.+) (?<sta>\w+:\w+))*/;
2204
- let results = parts[0].match(posRptRegex);
2205
- if (!results?.groups) {
2206
- decodeResult.decoded = false;
2207
- decodeResult.decoder.decodeLevel = "none";
2208
- return decodeResult;
2209
- }
2210
- if (results && results.length > 0) {
2211
- ResultFormatter.departureAirport(decodeResult, results.groups.orig);
2212
- ResultFormatter.arrivalAirport(decodeResult, results.groups.dest);
2213
- ResultFormatter.tail(decodeResult, results.groups.tail);
2214
- if (results.groups.agate) {
2215
- decodeResult.raw.arrival_gate = results.groups.agate;
2216
- decodeResult.formatted.items.push({
2217
- type: "arrival_gate",
2218
- code: "ARG",
2219
- label: "Arrival Gate",
2220
- value: `${results.groups.agate}`
2221
- });
2222
- decodeResult.raw.scheduled_time_of_arrival = results.groups.sta;
2223
- decodeResult.formatted.items.push({
2224
- type: "scheduled_time_of_arrival",
2225
- code: "STA",
2226
- label: "Scheduled Time of Arrival",
2227
- value: `${results.groups.sta}`
2228
- });
2229
- }
2230
- posRptRegex = /\/(?<field>\w+)\s(?<value>[\w\+\-:\.]+)\s*/gi;
2231
- const remainingParts = parts.slice(1);
2232
- for (const part of remainingParts) {
2233
- const matches = part.matchAll(posRptRegex);
2234
- for (const match of matches) {
2235
- switch (match.groups?.field) {
2236
- case "ALT": {
2237
- ResultFormatter.altitude(decodeResult, Number(match.groups.value));
2238
- break;
2239
- }
2240
- case "DWND": {
2241
- decodeResult.raw.wind_direction = Number(match.groups.value);
2242
- decodeResult.formatted.items.push({
2243
- type: "wind_direction",
2244
- code: "DWND",
2245
- label: this.descriptions[match.groups.field],
2246
- value: decodeResult.raw.wind_direction
2247
- });
2248
- break;
2249
- }
2250
- case "FL": {
2251
- const flight_level = Number(match.groups.value);
2252
- ResultFormatter.altitude(decodeResult, flight_level * 100);
2253
- break;
2254
- }
2255
- case "FOB": {
2256
- const fob = Number(match.groups.value);
2257
- if (!isNaN(fob)) {
2258
- ResultFormatter.currentFuel(decodeResult, fob);
2259
- }
2260
- break;
2261
- }
2262
- case "HDG": {
2263
- ResultFormatter.heading(decodeResult, Number(match.groups.value));
2264
- break;
2265
- }
2266
- case "MCH": {
2267
- decodeResult.raw.mach = Number(match.groups.value) / 1e3;
2268
- decodeResult.formatted.items.push({
2269
- type: "mach",
2270
- code: "MCH",
2271
- label: this.descriptions[match.groups.field],
2272
- value: `${decodeResult.raw.mach} Mach`
2273
- });
2274
- break;
2275
- }
2276
- case "NWYP": {
2277
- decodeResult.raw.next_waypoint = match.groups.value;
2278
- decodeResult.formatted.items.push({
2279
- type: "next_waypoint",
2280
- code: "NWYP",
2281
- label: this.descriptions[match.groups.field],
2282
- value: decodeResult.raw.next_waypoint
2283
- });
2284
- break;
2285
- }
2286
- case "POS": {
2287
- const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
2288
- const posResult = match.groups.value.match(posRegex);
2289
- const lat = Number(posResult?.groups?.lat) * (posResult?.groups?.lngd === "S" ? -1 : 1);
2290
- const lon = Number(posResult?.groups?.lng) * (posResult?.groups?.lngd === "W" ? -1 : 1);
2291
- const position = {
2292
- latitude: Number.isInteger(lat) ? lat / 1e3 : lat / 100,
2293
- longitude: Number.isInteger(lon) ? lon / 1e3 : lon / 100
2294
- };
2295
- ResultFormatter.position(decodeResult, position);
2296
- break;
2297
- }
2298
- case "SWND": {
2299
- decodeResult.raw.wind_speed = Number(match.groups.value);
2300
- decodeResult.formatted.items.push({
2301
- type: "wind_speed",
2302
- code: "SWND",
2303
- label: this.descriptions[match.groups.field],
2304
- value: decodeResult.raw.wind_speed
2305
- });
2306
- break;
2307
- }
2308
- default: {
2309
- if (match.groups?.field != void 0) {
2310
- const description = this.descriptions[match.groups.field] ? this.descriptions[match.groups.field] : "Unknown";
2311
- decodeResult.formatted.items.push({
2312
- type: match.groups.field,
2313
- code: match.groups.field,
2314
- label: description || `Unknown (${match.groups.field})`,
2315
- value: `${match.groups.value}`
2316
- });
2317
- }
2318
- }
2319
- }
2320
- }
2321
- }
2322
- decodeResult.decoded = true;
2323
- decodeResult.decoder.decodeLevel = "partial";
2324
- }
2325
- return decodeResult;
2326
- }
2327
- };
2328
-
2329
- // lib/plugins/Label_83.ts
2330
- var Label_83 = class extends DecoderPlugin {
2331
- name = "label-83";
2332
- qualifiers() {
2333
- return {
2334
- labels: ["83"]
2335
- };
2336
- }
2337
- decode(message, options = {}) {
2338
- const decodeResult = this.defaultResult();
2339
- decodeResult.decoder.name = this.name;
2340
- decodeResult.message = message;
2341
- decodeResult.formatted.description = "Airline Defined";
2342
- let text = message.text;
2343
- if (text.match(/^M\d{2}A\w{6}/)) {
2344
- ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
2345
- text = text.substring(10);
2346
- }
2347
- decodeResult.decoded = true;
2348
- if (text.substring(0, 10) === "4DH3 ETAT2") {
2349
- const fields = text.split(/\s+/);
2350
- if (fields[2].length > 5) {
2351
- decodeResult.raw.day_of_month = fields[2].substring(5);
2352
- }
2353
- ResultFormatter.unknown(decodeResult, fields[2].substring(0, 4));
2354
- const subfields = fields[3].split("/");
2355
- ResultFormatter.departureAirport(decodeResult, subfields[0]);
2356
- ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
2357
- ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
2358
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[6] + "00"));
2359
- } else if (text.substring(0, 5) === "001PR") {
2360
- decodeResult.raw.day_of_month = text.substring(5, 7);
2361
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(13, 28).replace(/\./g, ""));
2362
- if (position) {
2363
- ResultFormatter.position(decodeResult, position);
2364
- }
2365
- ResultFormatter.altitude(decodeResult, Number(text.substring(28, 33)));
2366
- ResultFormatter.unknown(decodeResult, text.substring(33));
2367
- } else {
2368
- const fields = text.replace(/\s/g, "").split(",");
2369
- if (fields.length === 9) {
2370
- ResultFormatter.departureAirport(decodeResult, fields[0]);
2371
- ResultFormatter.arrivalAirport(decodeResult, fields[1]);
2372
- decodeResult.raw.day_of_month = fields[2].substring(0, 2);
2373
- decodeResult.raw.time = fields[2].substring(2);
2374
- ResultFormatter.position(
2375
- decodeResult,
2376
- {
2377
- latitude: Number(fields[3].replace(/\s/g, "")),
2378
- longitude: Number(fields[4].replace(/\s/g, ""))
2379
- }
2380
- );
2381
- ResultFormatter.altitude(decodeResult, Number(fields[5]));
2382
- ResultFormatter.groundspeed(decodeResult, Number(fields[6]));
2383
- ResultFormatter.heading(decodeResult, Number(fields[7]));
2384
- ResultFormatter.unknown(decodeResult, fields[8]);
2385
- } else {
2386
- decodeResult.decoded = false;
2387
- ResultFormatter.unknown(decodeResult, message.text);
2388
- }
2389
- }
2390
- if (decodeResult.decoded) {
2391
- if (!decodeResult.remaining.text)
2392
- decodeResult.decoder.decodeLevel = "full";
2393
- else
2394
- decodeResult.decoder.decodeLevel = "partial";
2395
- } else {
2396
- decodeResult.decoder.decodeLevel = "none";
2397
- }
2398
- return decodeResult;
2399
- }
2400
- };
2401
-
2402
- // lib/plugins/Label_8E.ts
2403
- var Label_8E = class extends DecoderPlugin {
2404
- name = "label-8e";
2405
- qualifiers() {
2406
- return {
2407
- labels: ["8E"]
2408
- };
2409
- }
2410
- decode(message, options = {}) {
2411
- const decodeResult = this.defaultResult();
2412
- decodeResult.decoder.name = this.name;
2413
- decodeResult.formatted.description = "ETA Report";
2414
- decodeResult.message = message;
2415
- const regex = /^(?<arrival_icao>\w{4}),(?<arrival_eta>\d{4})$/;
2416
- const results = message.text.match(regex);
2417
- if (results?.groups) {
2418
- if (options.debug) {
2419
- console.log(`Label 8E ETA: groups`);
2420
- console.log(results.groups);
2421
- }
2422
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta + "00"));
2423
- ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
2424
- }
2425
- decodeResult.decoded = true;
2426
- decodeResult.decoder.decodeLevel = "full";
2427
- return decodeResult;
2428
- }
2429
- };
2430
-
2431
- // lib/plugins/Label_B6.ts
2432
- var Label_B6_Forwardslash = class extends DecoderPlugin {
2433
- name = "label-b6-forwardslash";
2434
- qualifiers() {
2435
- return {
2436
- labels: ["B6"],
2437
- preambles: ["/"]
2438
- };
2439
- }
2440
- decode(message, options = {}) {
2441
- const decodeResult = this.defaultResult();
2442
- decodeResult.decoder.name = this.name;
2443
- decodeResult.formatted.description = "CPDLC Message";
2444
- decodeResult.message = message;
2445
- if (options.debug) {
2446
- console.log("CPDLC: " + message);
2447
- }
2448
- return decodeResult;
2449
- }
2450
- };
2451
-
2452
- // lib/plugins/Label_ColonComma.ts
2453
- var Label_ColonComma = class extends DecoderPlugin {
2454
- name = "label-colon-comma";
2455
- qualifiers() {
2456
- return {
2457
- labels: [":;"]
2458
- };
2459
- }
2460
- decode(message, options = {}) {
2461
- const decodeResult = this.defaultResult();
2462
- decodeResult.decoder.name = this.name;
2463
- decodeResult.raw.frequency = Number(message.text) / 1e3;
2464
- decodeResult.formatted.description = "Aircraft Transceiver Frequency Change";
2465
- decodeResult.formatted.items.push({
2466
- type: "frequency",
2467
- label: "Frequency",
2468
- value: `${decodeResult.raw.frequency} MHz`,
2469
- code: "FREQ"
2470
- });
2471
- decodeResult.decoded = true;
2472
- decodeResult.decoder.decodeLevel = "full";
2473
- return decodeResult;
2474
- }
2475
- };
2476
-
2477
- // lib/utils/flight_plan_utils.ts
2478
- var FlightPlanUtils = class _FlightPlanUtils {
2479
- /**
2480
- * Processes flight plan data
2481
- *
2482
- * Expected format is [header, key1, val1, ... keyN, valN]
2483
- *
2484
- * @param decodeResult - results
2485
- * @param data - original message split by ':'
2486
- * @returns whether all fields were processed or not
2487
- */
2488
- static processFlightPlan(decodeResult, data) {
2489
- let allKnownFields = _FlightPlanUtils.parseHeader(decodeResult, data[0]);
2490
- for (let i = 1; i < data.length; i += 2) {
2491
- const key = data[i];
2492
- const value = data[i + 1];
2493
- switch (key) {
2494
- case "A":
2495
- addProcedure(decodeResult, value, "arrival");
2496
- break;
2497
- case "AA":
2498
- addArrivalAirport(decodeResult, value);
2499
- break;
2500
- case "AP":
2501
- addProcedure(decodeResult, value, "approach");
2502
- break;
2503
- case "CR":
2504
- addCompanyRoute(decodeResult, value);
2505
- break;
2506
- case "D":
2507
- addProcedure(decodeResult, value, "departure");
2508
- break;
2509
- case "DA":
2510
- addDepartureAirport(decodeResult, value);
2511
- break;
2512
- case "F":
2513
- addRoute(decodeResult, value);
2514
- break;
2515
- case "R":
2516
- addRunway(decodeResult, value);
2517
- break;
2518
- // case 'WS': // something about routes, has altitude, so current parsing won't work
2519
- // break;
2520
- default:
2521
- if (allKnownFields) {
2522
- decodeResult.remaining.text = "";
2523
- allKnownFields = false;
2524
- }
2525
- decodeResult.remaining.text += `:${key}:${value}`;
2526
- decodeResult.decoder.decodeLevel = "partial";
2527
- }
2528
- }
2529
- return allKnownFields;
2530
- }
2531
- static parseHeader(decodeResult, header) {
2532
- let allKnownFields = true;
2533
- if (header.startsWith("RF")) {
2534
- decodeResult.formatted.items.push({
2535
- type: "status",
2536
- code: "ROUTE_STATUS",
2537
- label: "Route Status",
2538
- value: "Route Filed"
2539
- });
2540
- decodeResult.raw.route_status = "RF";
2541
- if (header.length > 2) {
2542
- addRoute(decodeResult, header.substring(2));
2543
- }
2544
- } else if (header.startsWith("RP")) {
2545
- decodeResult.raw.route_status = "RP";
2546
- decodeResult.formatted.items.push({
2547
- type: "status",
2548
- code: "ROUTE_STATUS",
2549
- label: "Route Status",
2550
- value: "Route Planned"
2551
- });
2552
- decodeResult.raw.route_status = header;
2553
- } else if (header.startsWith("RI")) {
2554
- decodeResult.raw.route_status = "RI";
2555
- decodeResult.formatted.items.push({
2556
- type: "status",
2557
- code: "ROUTE_STATUS",
2558
- label: "Route Status",
2559
- value: "Route Inactive"
2560
- });
2561
- } else {
2562
- decodeResult.remaining.text += header;
2563
- allKnownFields = false;
2564
- }
2565
- return allKnownFields;
2278
+ return allKnownFields;
2566
2279
  }
2567
2280
  };
2568
2281
  function addArrivalAirport(decodeResult, value) {
@@ -2674,9 +2387,11 @@ var H1Helper = class {
2674
2387
  ResultFormatter.freetext(decodeResult, fields[i].substring(2));
2675
2388
  } else if (fields[i].startsWith("ET")) {
2676
2389
  if (fields[i].length === 7) {
2677
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(3) + "00"));
2390
+ ResultFormatter.day(decodeResult, Number(fields[i].substring(2, 3)));
2391
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(3)));
2678
2392
  } else if (fields[i].length === 8) {
2679
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(4) + "00"));
2393
+ ResultFormatter.day(decodeResult, Number(fields[i].substring(2, 4)));
2394
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(4)));
2680
2395
  } else {
2681
2396
  ResultFormatter.unknown(decodeResult, fields[i], "/");
2682
2397
  }
@@ -2727,161 +2442,554 @@ function processIdentification(decodeResult, data) {
2727
2442
  decodeResult.raw.mission_number = data[2];
2728
2443
  }
2729
2444
  }
2730
- function processDT(decodeResult, data) {
2731
- if (!decodeResult.raw.arrival_icao) {
2732
- ResultFormatter.arrivalAirport(decodeResult, data[0]);
2733
- } else if (decodeResult.raw.arrival_icao != data[0]) {
2734
- ResultFormatter.unknownArr(decodeResult, data);
2445
+ function processDT(decodeResult, data) {
2446
+ if (!decodeResult.raw.arrival_icao) {
2447
+ ResultFormatter.arrivalAirport(decodeResult, data[0]);
2448
+ } else if (decodeResult.raw.arrival_icao != data[0]) {
2449
+ ResultFormatter.unknownArr(decodeResult, data);
2450
+ }
2451
+ if (data.length > 1) {
2452
+ ResultFormatter.arrivalRunway(decodeResult, data[1]);
2453
+ }
2454
+ if (data.length > 2) {
2455
+ ResultFormatter.currentFuel(decodeResult, Number(data[2]));
2456
+ }
2457
+ if (data.length > 3) {
2458
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[3]));
2459
+ }
2460
+ if (data.length > 4) {
2461
+ ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
2462
+ }
2463
+ if (data.length > 5) {
2464
+ ResultFormatter.unknownArr(decodeResult, data);
2465
+ }
2466
+ }
2467
+ function processLR(decodeResult, data) {
2468
+ if (data.length === 19) {
2469
+ ResultFormatter.unknown(decodeResult, data[1]);
2470
+ ResultFormatter.flightNumber(decodeResult, data[2]);
2471
+ ResultFormatter.departureAirport(decodeResult, data[3]);
2472
+ ResultFormatter.arrivalAirport(decodeResult, data[4]);
2473
+ ResultFormatter.arrivalRunway(decodeResult, data[5]);
2474
+ ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
2475
+ } else {
2476
+ ResultFormatter.unknown(decodeResult, data.join(","));
2477
+ }
2478
+ }
2479
+ function parseMessageType(decodeResult, messageType) {
2480
+ const parts = messageType.split("#");
2481
+ if (parts.length == 1) {
2482
+ const type = parts[0].substring(0, 3);
2483
+ if (type === "POS" && parts[0].length !== 3) {
2484
+ processPosition2(decodeResult, parts[0].substring(3).split(","));
2485
+ }
2486
+ return processMessageType(decodeResult, type);
2487
+ } else if (parts.length == 2) {
2488
+ if (parts[0].length > 0) {
2489
+ ResultFormatter.unknown(decodeResult, parts[0].substring(0, 3));
2490
+ decodeResult.raw.flight_number = parts[0].substring(3);
2491
+ ResultFormatter.unknown(decodeResult, parts[1].length == 5 ? parts[1].substring(0, 2) : parts[1].substring(0, 3), "#");
2492
+ }
2493
+ const type = parts[1].length == 5 ? parts[1].substring(2, 5) : parts[1].substring(3, 6);
2494
+ if (parts[1].substring(3, 6) === "POS" && parts[1].length > 6) {
2495
+ processPosition2(decodeResult, parts[1].substring(6).split(","));
2496
+ }
2497
+ processMessageType(decodeResult, type);
2498
+ } else {
2499
+ ResultFormatter.unknown(decodeResult, messageType);
2500
+ }
2501
+ }
2502
+ function processMessageType(decodeResult, type) {
2503
+ if (type === "FPN") {
2504
+ decodeResult.formatted.description = "Flight Plan";
2505
+ } else if (type === "FTX") {
2506
+ decodeResult.formatted.description = "Free Text";
2507
+ } else if (type === "INI") {
2508
+ decodeResult.formatted.description = "Flight Plan Initial Report";
2509
+ } else if (type === "POS") {
2510
+ decodeResult.formatted.description = "Position Report";
2511
+ } else if (type === "PRG") {
2512
+ decodeResult.formatted.description = "Progress Report";
2513
+ } else {
2514
+ decodeResult.formatted.description = "Unknown H1 Message";
2515
+ }
2516
+ }
2517
+ function processDC(decodeResult, data) {
2518
+ decodeResult.raw.message_date = data[0];
2519
+ if (data.length === 1) {
2520
+ } else if (data.length === 2) {
2521
+ const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
2522
+ const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
2523
+ decodeResult.raw.message_timestamp = time;
2524
+ }
2525
+ }
2526
+ function processPS(decodeResult, data) {
2527
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2528
+ if (position) {
2529
+ decodeResult.raw.position = position;
2530
+ decodeResult.formatted.items.push({
2531
+ type: "aircraft_position",
2532
+ code: "POS",
2533
+ label: "Aircraft Position",
2534
+ value: CoordinateUtils.coordinateString(position)
2535
+ });
2536
+ }
2537
+ if (data.length === 9) {
2538
+ processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
2539
+ ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
2540
+ ResultFormatter.temperature(decodeResult, data[6]);
2541
+ ResultFormatter.unknown(decodeResult, data[7]);
2542
+ ResultFormatter.unknown(decodeResult, data[8]);
2543
+ }
2544
+ if (data.length === 14) {
2545
+ ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2546
+ processRoute(decodeResult, data[4], data[2], data[6], data[5], void 0);
2547
+ ResultFormatter.temperature(decodeResult, data[7]);
2548
+ ResultFormatter.groundspeed(decodeResult, Number(data[10]));
2549
+ ResultFormatter.unknown(decodeResult, data[1]);
2550
+ ResultFormatter.unknown(decodeResult, data[8]);
2551
+ ResultFormatter.unknown(decodeResult, data[9]);
2552
+ ResultFormatter.unknown(decodeResult, data.slice(11).join(","));
2553
+ }
2554
+ }
2555
+ function processPosition2(decodeResult, data) {
2556
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2557
+ if (position) {
2558
+ decodeResult.raw.position = position;
2559
+ decodeResult.formatted.items.push({
2560
+ type: "aircraft_position",
2561
+ code: "POS",
2562
+ label: "Aircraft Position",
2563
+ value: CoordinateUtils.coordinateString(position)
2564
+ });
2565
+ }
2566
+ if (data.length >= 10) {
2567
+ ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2568
+ processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
2569
+ ResultFormatter.temperature(decodeResult, data[7]);
2570
+ ResultFormatter.unknown(decodeResult, data[8]);
2571
+ ResultFormatter.unknown(decodeResult, data[9]);
2572
+ }
2573
+ if (data.length >= 14) {
2574
+ ResultFormatter.groundspeed(decodeResult, Number(data[10]));
2575
+ ResultFormatter.unknown(decodeResult, data[11]);
2576
+ ResultFormatter.unknown(decodeResult, data[12]);
2577
+ ResultFormatter.unknown(decodeResult, data[13]);
2578
+ }
2579
+ }
2580
+ function processRoute(decodeResult, last, time, next, eta, then, date) {
2581
+ const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
2582
+ const nextTime = date ? DateTimeUtils.convertDateTimeToEpoch(eta, date) : DateTimeUtils.convertHHMMSSToTod(eta);
2583
+ const timeFormat = date ? "epoch" : "tod";
2584
+ const lastWaypoint = RouteUtils.getWaypoint(last);
2585
+ lastWaypoint.time = lastTime;
2586
+ lastWaypoint.timeFormat = timeFormat;
2587
+ const nextWaypoint = RouteUtils.getWaypoint(next);
2588
+ nextWaypoint.time = nextTime;
2589
+ nextWaypoint.timeFormat = timeFormat;
2590
+ const thenWaypoint = RouteUtils.getWaypoint(then || "?");
2591
+ const waypoints = [lastWaypoint, nextWaypoint, thenWaypoint];
2592
+ decodeResult.raw.route = { waypoints };
2593
+ decodeResult.formatted.items.push({
2594
+ type: "aircraft_route",
2595
+ code: "ROUTE",
2596
+ label: "Aircraft Route",
2597
+ value: RouteUtils.routeToString(decodeResult.raw.route)
2598
+ });
2599
+ }
2600
+
2601
+ // lib/plugins/Label_4J_POS.ts
2602
+ var Label_4J_POS = class extends DecoderPlugin {
2603
+ name = "label-4j-pos";
2604
+ qualifiers() {
2605
+ return {
2606
+ labels: ["4J"],
2607
+ preambles: ["POS/"]
2608
+ };
2735
2609
  }
2736
- if (data.length > 1) {
2737
- ResultFormatter.arrivalRunway(decodeResult, data[1]);
2610
+ // copied from Label_H1.ts since i don't really want to have to have
2611
+ // something named like that decode more than 1 type
2612
+ // if we figure out a good name, i'll combine them
2613
+ decode(message, options = {}) {
2614
+ let decodeResult = this.defaultResult();
2615
+ decodeResult.decoder.name = this.name;
2616
+ decodeResult.message = message;
2617
+ const msg = message.text.replace(/\n|\r/g, "");
2618
+ const decoded = H1Helper.decodeH1Message(decodeResult, msg);
2619
+ decodeResult.decoded = decoded;
2620
+ decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
2621
+ if (decodeResult.formatted.items.length === 0) {
2622
+ if (options.debug) {
2623
+ console.log(`Decoder: Unknown H1 message: ${message.text}`);
2624
+ }
2625
+ ResultFormatter.unknown(decodeResult, message.text);
2626
+ decodeResult.decoded = false;
2627
+ decodeResult.decoder.decodeLevel = "none";
2628
+ }
2629
+ return decodeResult;
2738
2630
  }
2739
- if (data.length > 2) {
2740
- ResultFormatter.currentFuel(decodeResult, Number(data[2]));
2631
+ };
2632
+
2633
+ // lib/plugins/Label_4N.ts
2634
+ var Label_4N = class extends DecoderPlugin {
2635
+ name = "label-4n";
2636
+ qualifiers() {
2637
+ return {
2638
+ labels: ["4N"]
2639
+ };
2741
2640
  }
2742
- if (data.length > 3) {
2743
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[3]));
2641
+ decode(message, options = {}) {
2642
+ const decodeResult = this.defaultResult();
2643
+ decodeResult.decoder.name = this.name;
2644
+ decodeResult.message = message;
2645
+ decodeResult.formatted.description = "Airline Defined";
2646
+ let text = message.text;
2647
+ if (text.match(/^M\d{2}A\w{6}/)) {
2648
+ ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
2649
+ text = text.substring(10);
2650
+ }
2651
+ decodeResult.decoded = true;
2652
+ const fields = text.split(",");
2653
+ if (text.length === 51) {
2654
+ decodeResult.raw.day = text.substring(0, 2);
2655
+ ResultFormatter.departureAirport(decodeResult, text.substring(8, 11));
2656
+ ResultFormatter.arrivalAirport(decodeResult, text.substring(13, 16));
2657
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(30, 45).replace(/^(.)0/, "$1")));
2658
+ ResultFormatter.altitude(decodeResult, Number(text.substring(48, 51)) * 100);
2659
+ ResultFormatter.unknownArr(decodeResult, [text.substring(2, 4), text.substring(19, 29)], " ");
2660
+ } else if (fields.length === 33) {
2661
+ decodeResult.raw.date = fields[3];
2662
+ if (fields[1] === "B") {
2663
+ ResultFormatter.position(decodeResult, { latitude: Number(fields[4]), longitude: Number(fields[5]) });
2664
+ ResultFormatter.altitude(decodeResult, Number(fields[6]));
2665
+ }
2666
+ ResultFormatter.departureAirport(decodeResult, fields[8]);
2667
+ ResultFormatter.arrivalAirport(decodeResult, fields[9]);
2668
+ ResultFormatter.alternateAirport(decodeResult, fields[10]);
2669
+ ResultFormatter.arrivalRunway(decodeResult, fields[11].split("/")[0]);
2670
+ if (fields[12].length > 1) {
2671
+ ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
2672
+ }
2673
+ ResultFormatter.checksum(decodeResult, fields[32]);
2674
+ ResultFormatter.unknownArr(decodeResult, [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != ""));
2675
+ } else {
2676
+ decodeResult.decoded = false;
2677
+ ResultFormatter.unknown(decodeResult, text);
2678
+ }
2679
+ if (decodeResult.decoded) {
2680
+ if (!decodeResult.remaining.text)
2681
+ decodeResult.decoder.decodeLevel = "full";
2682
+ else
2683
+ decodeResult.decoder.decodeLevel = "partial";
2684
+ } else {
2685
+ decodeResult.decoder.decodeLevel = "none";
2686
+ }
2687
+ return decodeResult;
2744
2688
  }
2745
- if (data.length > 4) {
2746
- ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
2689
+ };
2690
+
2691
+ // lib/plugins/Label_80.ts
2692
+ var Label_80 = class extends DecoderPlugin {
2693
+ name = "label-80";
2694
+ descriptions = {
2695
+ ALT: "Altitude",
2696
+ DWND: "Wind Direction",
2697
+ ETA: "Estimated Time of Arrival",
2698
+ FOB: "Fuel on Board",
2699
+ FL: "Flight Level",
2700
+ HDG: "Heading",
2701
+ MCH: "Aircraft Speed",
2702
+ NWYP: "Next Waypoint",
2703
+ POS: "Aircraft Position",
2704
+ SAT: "Static Air Temperature",
2705
+ SWND: "Wind Speed",
2706
+ TAS: "True Airspeed",
2707
+ WYP: "Waypoint"
2708
+ };
2709
+ qualifiers() {
2710
+ return {
2711
+ labels: ["80"],
2712
+ preambles: ["3N01 POSRPT"]
2713
+ };
2747
2714
  }
2748
- if (data.length > 5) {
2749
- ResultFormatter.unknownArr(decodeResult, data);
2715
+ decode(message, options = {}) {
2716
+ const decodeResult = this.defaultResult();
2717
+ decodeResult.decoder.name = this.name;
2718
+ decodeResult.formatted.description = "Airline Defined Position Report";
2719
+ const parts = message.text.split("\n");
2720
+ let posRptRegex = /^3N01 POSRPT \d\d\d\d\/\d\d (?<orig>\w+)\/(?<dest>\w+) \.(?<tail>[\w-]+)(\/(?<agate>.+) (?<sta>\w+:\w+))*/;
2721
+ let results = parts[0].match(posRptRegex);
2722
+ if (!results?.groups) {
2723
+ decodeResult.decoded = false;
2724
+ decodeResult.decoder.decodeLevel = "none";
2725
+ return decodeResult;
2726
+ }
2727
+ if (results && results.length > 0) {
2728
+ ResultFormatter.departureAirport(decodeResult, results.groups.orig);
2729
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.dest);
2730
+ ResultFormatter.tail(decodeResult, results.groups.tail);
2731
+ if (results.groups.agate) {
2732
+ decodeResult.raw.arrival_gate = results.groups.agate;
2733
+ decodeResult.formatted.items.push({
2734
+ type: "arrival_gate",
2735
+ code: "ARG",
2736
+ label: "Arrival Gate",
2737
+ value: `${results.groups.agate}`
2738
+ });
2739
+ decodeResult.raw.scheduled_time_of_arrival = results.groups.sta;
2740
+ decodeResult.formatted.items.push({
2741
+ type: "scheduled_time_of_arrival",
2742
+ code: "STA",
2743
+ label: "Scheduled Time of Arrival",
2744
+ value: `${results.groups.sta}`
2745
+ });
2746
+ }
2747
+ posRptRegex = /\/(?<field>\w+)\s(?<value>[\w\+\-:\.]+)\s*/gi;
2748
+ const remainingParts = parts.slice(1);
2749
+ for (const part of remainingParts) {
2750
+ const matches = part.matchAll(posRptRegex);
2751
+ for (const match of matches) {
2752
+ switch (match.groups?.field) {
2753
+ case "ALT": {
2754
+ ResultFormatter.altitude(decodeResult, Number(match.groups.value));
2755
+ break;
2756
+ }
2757
+ case "DWND": {
2758
+ decodeResult.raw.wind_direction = Number(match.groups.value);
2759
+ decodeResult.formatted.items.push({
2760
+ type: "wind_direction",
2761
+ code: "DWND",
2762
+ label: this.descriptions[match.groups.field],
2763
+ value: decodeResult.raw.wind_direction
2764
+ });
2765
+ break;
2766
+ }
2767
+ case "FL": {
2768
+ const flight_level = Number(match.groups.value);
2769
+ ResultFormatter.altitude(decodeResult, flight_level * 100);
2770
+ break;
2771
+ }
2772
+ case "FOB": {
2773
+ const fob = Number(match.groups.value);
2774
+ if (!isNaN(fob)) {
2775
+ ResultFormatter.currentFuel(decodeResult, fob);
2776
+ }
2777
+ break;
2778
+ }
2779
+ case "HDG": {
2780
+ ResultFormatter.heading(decodeResult, Number(match.groups.value));
2781
+ break;
2782
+ }
2783
+ case "MCH": {
2784
+ decodeResult.raw.mach = Number(match.groups.value) / 1e3;
2785
+ decodeResult.formatted.items.push({
2786
+ type: "mach",
2787
+ code: "MCH",
2788
+ label: this.descriptions[match.groups.field],
2789
+ value: `${decodeResult.raw.mach} Mach`
2790
+ });
2791
+ break;
2792
+ }
2793
+ case "NWYP": {
2794
+ decodeResult.raw.next_waypoint = match.groups.value;
2795
+ decodeResult.formatted.items.push({
2796
+ type: "next_waypoint",
2797
+ code: "NWYP",
2798
+ label: this.descriptions[match.groups.field],
2799
+ value: decodeResult.raw.next_waypoint
2800
+ });
2801
+ break;
2802
+ }
2803
+ case "POS": {
2804
+ const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
2805
+ const posResult = match.groups.value.match(posRegex);
2806
+ const lat = Number(posResult?.groups?.lat) * (posResult?.groups?.lngd === "S" ? -1 : 1);
2807
+ const lon = Number(posResult?.groups?.lng) * (posResult?.groups?.lngd === "W" ? -1 : 1);
2808
+ const position = {
2809
+ latitude: Number.isInteger(lat) ? lat / 1e3 : lat / 100,
2810
+ longitude: Number.isInteger(lon) ? lon / 1e3 : lon / 100
2811
+ };
2812
+ ResultFormatter.position(decodeResult, position);
2813
+ break;
2814
+ }
2815
+ case "SWND": {
2816
+ decodeResult.raw.wind_speed = Number(match.groups.value);
2817
+ decodeResult.formatted.items.push({
2818
+ type: "wind_speed",
2819
+ code: "SWND",
2820
+ label: this.descriptions[match.groups.field],
2821
+ value: decodeResult.raw.wind_speed
2822
+ });
2823
+ break;
2824
+ }
2825
+ default: {
2826
+ if (match.groups?.field != void 0) {
2827
+ const description = this.descriptions[match.groups.field] ? this.descriptions[match.groups.field] : "Unknown";
2828
+ decodeResult.formatted.items.push({
2829
+ type: match.groups.field,
2830
+ code: match.groups.field,
2831
+ label: description || `Unknown (${match.groups.field})`,
2832
+ value: `${match.groups.value}`
2833
+ });
2834
+ }
2835
+ }
2836
+ }
2837
+ }
2838
+ }
2839
+ decodeResult.decoded = true;
2840
+ decodeResult.decoder.decodeLevel = "partial";
2841
+ }
2842
+ return decodeResult;
2750
2843
  }
2751
- }
2752
- function processLR(decodeResult, data) {
2753
- if (data.length === 19) {
2754
- ResultFormatter.unknown(decodeResult, data[1]);
2755
- ResultFormatter.flightNumber(decodeResult, data[2]);
2756
- ResultFormatter.departureAirport(decodeResult, data[3]);
2757
- ResultFormatter.arrivalAirport(decodeResult, data[4]);
2758
- ResultFormatter.arrivalRunway(decodeResult, data[5]);
2759
- ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
2760
- } else {
2761
- ResultFormatter.unknown(decodeResult, data.join(","));
2844
+ };
2845
+
2846
+ // lib/plugins/Label_83.ts
2847
+ var Label_83 = class extends DecoderPlugin {
2848
+ name = "label-83";
2849
+ qualifiers() {
2850
+ return {
2851
+ labels: ["83"]
2852
+ };
2762
2853
  }
2763
- }
2764
- function parseMessageType(decodeResult, messageType) {
2765
- const parts = messageType.split("#");
2766
- if (parts.length == 1) {
2767
- const type = parts[0].substring(0, 3);
2768
- if (type === "POS" && parts[0].length !== 3) {
2769
- processPosition2(decodeResult, parts[0].substring(3).split(","));
2854
+ decode(message, options = {}) {
2855
+ const decodeResult = this.defaultResult();
2856
+ decodeResult.decoder.name = this.name;
2857
+ decodeResult.message = message;
2858
+ decodeResult.formatted.description = "Airline Defined";
2859
+ let text = message.text;
2860
+ if (text.match(/^M\d{2}A\w{6}/)) {
2861
+ ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
2862
+ text = text.substring(10);
2770
2863
  }
2771
- return processMessageType(decodeResult, type);
2772
- } else if (parts.length == 2) {
2773
- if (parts[0].length > 0) {
2774
- ResultFormatter.unknown(decodeResult, parts[0].substring(0, 3));
2775
- decodeResult.raw.flight_number = parts[0].substring(3);
2776
- ResultFormatter.unknown(decodeResult, parts[1].length == 5 ? parts[1].substring(0, 2) : parts[1].substring(0, 3), "#");
2864
+ decodeResult.decoded = true;
2865
+ if (text.substring(0, 10) === "4DH3 ETAT2") {
2866
+ const fields = text.split(/\s+/);
2867
+ if (fields[2].length > 5) {
2868
+ decodeResult.raw.day = fields[2].substring(5);
2869
+ }
2870
+ ResultFormatter.unknown(decodeResult, fields[2].substring(0, 4));
2871
+ const subfields = fields[3].split("/");
2872
+ ResultFormatter.departureAirport(decodeResult, subfields[0]);
2873
+ ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
2874
+ ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
2875
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[6] + "00"));
2876
+ } else if (text.substring(0, 5) === "001PR") {
2877
+ decodeResult.raw.day = text.substring(5, 7);
2878
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(13, 28).replace(/\./g, ""));
2879
+ if (position) {
2880
+ ResultFormatter.position(decodeResult, position);
2881
+ }
2882
+ ResultFormatter.altitude(decodeResult, Number(text.substring(28, 33)));
2883
+ ResultFormatter.unknown(decodeResult, text.substring(33));
2884
+ } else {
2885
+ const fields = text.replace(/\s/g, "").split(",");
2886
+ if (fields.length === 9) {
2887
+ ResultFormatter.departureAirport(decodeResult, fields[0]);
2888
+ ResultFormatter.arrivalAirport(decodeResult, fields[1]);
2889
+ decodeResult.raw.day = fields[2].substring(0, 2);
2890
+ decodeResult.raw.time = fields[2].substring(2);
2891
+ ResultFormatter.position(
2892
+ decodeResult,
2893
+ {
2894
+ latitude: Number(fields[3].replace(/\s/g, "")),
2895
+ longitude: Number(fields[4].replace(/\s/g, ""))
2896
+ }
2897
+ );
2898
+ ResultFormatter.altitude(decodeResult, Number(fields[5]));
2899
+ ResultFormatter.groundspeed(decodeResult, Number(fields[6]));
2900
+ ResultFormatter.heading(decodeResult, Number(fields[7]));
2901
+ ResultFormatter.unknown(decodeResult, fields[8]);
2902
+ } else {
2903
+ decodeResult.decoded = false;
2904
+ ResultFormatter.unknown(decodeResult, message.text);
2905
+ }
2777
2906
  }
2778
- const type = parts[1].length == 5 ? parts[1].substring(2, 5) : parts[1].substring(3, 6);
2779
- if (parts[1].substring(3, 6) === "POS" && parts[1].length > 6) {
2780
- processPosition2(decodeResult, parts[1].substring(6).split(","));
2907
+ if (decodeResult.decoded) {
2908
+ if (!decodeResult.remaining.text)
2909
+ decodeResult.decoder.decodeLevel = "full";
2910
+ else
2911
+ decodeResult.decoder.decodeLevel = "partial";
2912
+ } else {
2913
+ decodeResult.decoder.decodeLevel = "none";
2781
2914
  }
2782
- processMessageType(decodeResult, type);
2783
- } else {
2784
- ResultFormatter.unknown(decodeResult, messageType);
2915
+ return decodeResult;
2785
2916
  }
2786
- }
2787
- function processMessageType(decodeResult, type) {
2788
- if (type === "FPN") {
2789
- decodeResult.formatted.description = "Flight Plan";
2790
- } else if (type === "FTX") {
2791
- decodeResult.formatted.description = "Free Text";
2792
- } else if (type === "INI") {
2793
- decodeResult.formatted.description = "Flight Plan Initial Report";
2794
- } else if (type === "POS") {
2795
- decodeResult.formatted.description = "Position Report";
2796
- } else if (type === "PRG") {
2797
- decodeResult.formatted.description = "Progress Report";
2798
- } else {
2799
- decodeResult.formatted.description = "Unknown H1 Message";
2917
+ };
2918
+
2919
+ // lib/plugins/Label_8E.ts
2920
+ var Label_8E = class extends DecoderPlugin {
2921
+ name = "label-8e";
2922
+ qualifiers() {
2923
+ return {
2924
+ labels: ["8E"]
2925
+ };
2800
2926
  }
2801
- }
2802
- function processDC(decodeResult, data) {
2803
- decodeResult.raw.message_date = data[0];
2804
- if (data.length === 1) {
2805
- } else if (data.length === 2) {
2806
- const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
2807
- const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
2808
- decodeResult.raw.message_timestamp = time;
2927
+ decode(message, options = {}) {
2928
+ const decodeResult = this.defaultResult();
2929
+ decodeResult.decoder.name = this.name;
2930
+ decodeResult.formatted.description = "ETA Report";
2931
+ decodeResult.message = message;
2932
+ const regex = /^(?<arrival_icao>\w{4}),(?<arrival_eta>\d{4})$/;
2933
+ const results = message.text.match(regex);
2934
+ if (results?.groups) {
2935
+ if (options.debug) {
2936
+ console.log(`Label 8E ETA: groups`);
2937
+ console.log(results.groups);
2938
+ }
2939
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta));
2940
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
2941
+ }
2942
+ decodeResult.decoded = true;
2943
+ decodeResult.decoder.decodeLevel = "full";
2944
+ return decodeResult;
2809
2945
  }
2810
- }
2811
- function processPS(decodeResult, data) {
2812
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2813
- if (position) {
2814
- decodeResult.raw.position = position;
2815
- decodeResult.formatted.items.push({
2816
- type: "aircraft_position",
2817
- code: "POS",
2818
- label: "Aircraft Position",
2819
- value: CoordinateUtils.coordinateString(position)
2820
- });
2946
+ };
2947
+
2948
+ // lib/plugins/Label_B6.ts
2949
+ var Label_B6_Forwardslash = class extends DecoderPlugin {
2950
+ name = "label-b6-forwardslash";
2951
+ qualifiers() {
2952
+ return {
2953
+ labels: ["B6"],
2954
+ preambles: ["/"]
2955
+ };
2821
2956
  }
2822
- if (data.length === 9) {
2823
- processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
2824
- ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
2825
- ResultFormatter.temperature(decodeResult, data[6]);
2826
- ResultFormatter.unknown(decodeResult, data[7]);
2827
- ResultFormatter.unknown(decodeResult, data[8]);
2957
+ decode(message, options = {}) {
2958
+ const decodeResult = this.defaultResult();
2959
+ decodeResult.decoder.name = this.name;
2960
+ decodeResult.formatted.description = "CPDLC Message";
2961
+ decodeResult.message = message;
2962
+ if (options.debug) {
2963
+ console.log("CPDLC: " + message);
2964
+ }
2965
+ return decodeResult;
2828
2966
  }
2829
- if (data.length === 14) {
2830
- ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2831
- processRoute(decodeResult, data[4], data[2], data[6], data[5], void 0);
2832
- ResultFormatter.temperature(decodeResult, data[7]);
2833
- ResultFormatter.groundspeed(decodeResult, Number(data[10]));
2834
- ResultFormatter.unknown(decodeResult, data[1]);
2835
- ResultFormatter.unknown(decodeResult, data[8]);
2836
- ResultFormatter.unknown(decodeResult, data[9]);
2837
- ResultFormatter.unknown(decodeResult, data.slice(11).join(","));
2967
+ };
2968
+
2969
+ // lib/plugins/Label_ColonComma.ts
2970
+ var Label_ColonComma = class extends DecoderPlugin {
2971
+ name = "label-colon-comma";
2972
+ qualifiers() {
2973
+ return {
2974
+ labels: [":;"]
2975
+ };
2838
2976
  }
2839
- }
2840
- function processPosition2(decodeResult, data) {
2841
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2842
- if (position) {
2843
- decodeResult.raw.position = position;
2977
+ decode(message, options = {}) {
2978
+ const decodeResult = this.defaultResult();
2979
+ decodeResult.decoder.name = this.name;
2980
+ decodeResult.raw.frequency = Number(message.text) / 1e3;
2981
+ decodeResult.formatted.description = "Aircraft Transceiver Frequency Change";
2844
2982
  decodeResult.formatted.items.push({
2845
- type: "aircraft_position",
2846
- code: "POS",
2847
- label: "Aircraft Position",
2848
- value: CoordinateUtils.coordinateString(position)
2983
+ type: "frequency",
2984
+ label: "Frequency",
2985
+ value: `${decodeResult.raw.frequency} MHz`,
2986
+ code: "FREQ"
2849
2987
  });
2988
+ decodeResult.decoded = true;
2989
+ decodeResult.decoder.decodeLevel = "full";
2990
+ return decodeResult;
2850
2991
  }
2851
- if (data.length >= 10) {
2852
- ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2853
- processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
2854
- ResultFormatter.temperature(decodeResult, data[7]);
2855
- ResultFormatter.unknown(decodeResult, data[8]);
2856
- ResultFormatter.unknown(decodeResult, data[9]);
2857
- }
2858
- if (data.length >= 14) {
2859
- ResultFormatter.groundspeed(decodeResult, Number(data[10]));
2860
- ResultFormatter.unknown(decodeResult, data[11]);
2861
- ResultFormatter.unknown(decodeResult, data[12]);
2862
- ResultFormatter.unknown(decodeResult, data[13]);
2863
- }
2864
- }
2865
- function processRoute(decodeResult, last, time, next, eta, then, date) {
2866
- const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
2867
- const nextTime = date ? DateTimeUtils.convertDateTimeToEpoch(eta, date) : DateTimeUtils.convertHHMMSSToTod(eta);
2868
- const timeFormat = date ? "epoch" : "tod";
2869
- const lastWaypoint = RouteUtils.getWaypoint(last);
2870
- lastWaypoint.time = lastTime;
2871
- lastWaypoint.timeFormat = timeFormat;
2872
- const nextWaypoint = RouteUtils.getWaypoint(next);
2873
- nextWaypoint.time = nextTime;
2874
- nextWaypoint.timeFormat = timeFormat;
2875
- const thenWaypoint = RouteUtils.getWaypoint(then || "?");
2876
- const waypoints = [lastWaypoint, nextWaypoint, thenWaypoint];
2877
- decodeResult.raw.route = { waypoints };
2878
- decodeResult.formatted.items.push({
2879
- type: "aircraft_route",
2880
- code: "ROUTE",
2881
- label: "Aircraft Route",
2882
- value: RouteUtils.routeToString(decodeResult.raw.route)
2883
- });
2884
- }
2992
+ };
2885
2993
 
2886
2994
  // lib/plugins/Label_H1.ts
2887
2995
  var Label_H1 = class extends DecoderPlugin {
@@ -3040,9 +3148,9 @@ var Label_H1_StarPOS = class extends DecoderPlugin {
3040
3148
  decodeResult.decoder.decodeLevel = "none";
3041
3149
  return decodeResult;
3042
3150
  }
3043
- decodeResult.raw.month = Number(msg.substring(4, 6));
3044
- decodeResult.raw.day_of_month = Number(msg.substring(6, 8));
3045
- ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(msg.substring(8, 12) + "00"));
3151
+ ResultFormatter.month(decodeResult, Number(msg.substring(4, 6)));
3152
+ ResultFormatter.day(decodeResult, Number(msg.substring(6, 8)));
3153
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(msg.substring(8, 12)));
3046
3154
  ResultFormatter.position(decodeResult, {
3047
3155
  // Deg Min, no sec
3048
3156
  latitude: CoordinateUtils.getDirection(msg.substring(12, 13)) * (Number(msg.substring(13, 15)) + Number(msg.substring(15, 17)) / 60),
@@ -3269,7 +3377,7 @@ var Label_QR = class extends DecoderPlugin {
3269
3377
  decodeResult.formatted.description = "ON Report";
3270
3378
  ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3271
3379
  ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3272
- ResultFormatter.on(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3380
+ ResultFormatter.on(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12)));
3273
3381
  ResultFormatter.unknown(decodeResult, message.text.substring(12));
3274
3382
  decodeResult.decoded = true;
3275
3383
  if (!decodeResult.remaining.text)
@@ -3294,7 +3402,7 @@ var Label_QP = class extends DecoderPlugin {
3294
3402
  decodeResult.formatted.description = "OUT Report";
3295
3403
  ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3296
3404
  ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3297
- ResultFormatter.out(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3405
+ ResultFormatter.out(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12)));
3298
3406
  ResultFormatter.unknown(decodeResult, message.text.substring(12));
3299
3407
  decodeResult.decoded = true;
3300
3408
  if (!decodeResult.remaining.text)
@@ -3319,7 +3427,7 @@ var Label_QS = class extends DecoderPlugin {
3319
3427
  decodeResult.formatted.description = "IN Report";
3320
3428
  ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3321
3429
  ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3322
- ResultFormatter.in(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3430
+ ResultFormatter.in(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12)));
3323
3431
  ResultFormatter.unknown(decodeResult, message.text.substring(12));
3324
3432
  decodeResult.decoded = true;
3325
3433
  if (!decodeResult.remaining.text)
@@ -3346,7 +3454,7 @@ var Label_QQ = class extends DecoderPlugin {
3346
3454
  ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3347
3455
  ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3348
3456
  if (message.text.substring(12, 19) === "\r\n001FE") {
3349
- decodeResult.raw.day_of_month = message.text.substring(19, 21);
3457
+ decodeResult.raw.day = message.text.substring(19, 21);
3350
3458
  ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(21, 27)));
3351
3459
  let latdir = message.text.substring(27, 28);
3352
3460
  let latdeg = Number(message.text.substring(28, 30));
@@ -4220,6 +4328,7 @@ var MessageDecoder = class {
4220
4328
  this.registerPlugin(new Label_4A_DIS(this));
4221
4329
  this.registerPlugin(new Label_4A_DOOR(this));
4222
4330
  this.registerPlugin(new Label_4A_Slash_01(this));
4331
+ this.registerPlugin(new Label_4J_POS(this));
4223
4332
  this.registerPlugin(new Label_4N(this));
4224
4333
  this.registerPlugin(new Label_B6_Forwardslash(this));
4225
4334
  this.registerPlugin(new Label_H1_FLR(this));