@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.js CHANGED
@@ -75,10 +75,13 @@ var DateTimeUtils = class {
75
75
  }
76
76
  /**
77
77
  *
78
- * @param time HHMMSS
78
+ * @param time HHMMSS or HHMM
79
79
  * @returns seconds since midnight
80
80
  */
81
81
  static convertHHMMSSToTod(time) {
82
+ if (time.length === 4) {
83
+ time += "00";
84
+ }
82
85
  const h = Number(time.substring(0, 2));
83
86
  const m = Number(time.substring(2, 4));
84
87
  const s = Number(time.substring(4, 6));
@@ -603,27 +606,36 @@ var ResultFormatter = class {
603
606
  });
604
607
  }
605
608
  static day(decodeResult, day) {
606
- decodeResult.raw.day_of_month = day;
609
+ decodeResult.raw.day = day;
607
610
  decodeResult.formatted.items.push({
608
- type: "day_of_month",
611
+ type: "day",
609
612
  code: "MSG_DAY",
610
613
  label: "Day of Month",
611
614
  value: `${day}`
612
615
  });
613
616
  }
617
+ static month(decodeResult, month) {
618
+ decodeResult.raw.month = month;
619
+ decodeResult.formatted.items.push({
620
+ type: "month",
621
+ code: "MSG_MON",
622
+ label: "Month of Year",
623
+ value: `${month}`
624
+ });
625
+ }
614
626
  static departureDay(decodeResult, day) {
615
- decodeResult.raw.departure_day_of_month = day;
627
+ decodeResult.raw.departure_day = day;
616
628
  decodeResult.formatted.items.push({
617
- type: "day_of_month",
629
+ type: "day",
618
630
  code: "DEP_DAY",
619
631
  label: "Departure Day",
620
632
  value: `${day}`
621
633
  });
622
634
  }
623
635
  static arrivalDay(decodeResult, day) {
624
- decodeResult.raw.arrival_day_of_month = day;
636
+ decodeResult.raw.arrival_day = day;
625
637
  decodeResult.formatted.items.push({
626
- type: "day_of_month",
638
+ type: "day",
627
639
  code: "ARR_DAY",
628
640
  label: "Arrival Day",
629
641
  value: `${day}`
@@ -718,14 +730,14 @@ var Label_5Z_Slash = class extends DecoderPlugin {
718
730
  const info = data[2].split(" ");
719
731
  ResultFormatter.departureAirport(decodeResult, info[1]);
720
732
  ResultFormatter.arrivalAirport(decodeResult, info[2]);
721
- decodeResult.raw.day_of_month = Number(info[3]);
733
+ decodeResult.raw.day = Number(info[3]);
722
734
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
723
735
  ResultFormatter.arrivalRunway(decodeResult, info[5].slice(1));
724
736
  ResultFormatter.unknownArr(decodeResult, data.slice(3), "/");
725
737
  } else if (type === "B3") {
726
738
  ResultFormatter.departureAirport(decodeResult, header[1].substring(0, 3), "IATA");
727
739
  ResultFormatter.arrivalAirport(decodeResult, header[1].substring(3), "IATA");
728
- decodeResult.raw.day_of_month = Number(header[2]);
740
+ decodeResult.raw.day = Number(header[2]);
729
741
  ResultFormatter.arrivalRunway(decodeResult, header[3].slice(1));
730
742
  if (header.length > 4) {
731
743
  ResultFormatter.unknownArr(decodeResult, header.slice(4), "/");
@@ -734,7 +746,7 @@ var Label_5Z_Slash = class extends DecoderPlugin {
734
746
  const info = data[2].split(" ");
735
747
  ResultFormatter.departureAirport(decodeResult, info[1]);
736
748
  ResultFormatter.arrivalAirport(decodeResult, info[2]);
737
- decodeResult.raw.day_of_month = Number(info[3]);
749
+ decodeResult.raw.day = Number(info[3]);
738
750
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
739
751
  ResultFormatter.unknownArr(decodeResult, info.slice(5), " ");
740
752
  } else if (type === "C3") {
@@ -744,10 +756,10 @@ var Label_5Z_Slash = class extends DecoderPlugin {
744
756
  const airports = data[2].split(" ");
745
757
  ResultFormatter.departureAirport(decodeResult, airports[1]);
746
758
  ResultFormatter.arrivalAirport(decodeResult, airports[2]);
747
- decodeResult.raw.day_of_month = Number(airports[3]);
759
+ decodeResult.raw.day = Number(airports[3]);
748
760
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(airports[4]));
749
761
  const estimates = data[3].split(" ");
750
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(estimates[1] + "00"));
762
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(estimates[1]));
751
763
  ResultFormatter.unknown(decodeResult, estimates[2]);
752
764
  } else {
753
765
  if (options.debug) {
@@ -891,16 +903,16 @@ var Label_10_Slash = class extends DecoderPlugin {
891
903
  ResultFormatter.heading(decodeResult, Number(parts[5]));
892
904
  ResultFormatter.altitude(decodeResult, 100 * Number(parts[6]));
893
905
  ResultFormatter.arrivalAirport(decodeResult, parts[7]);
894
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[8] + "00"));
906
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[8]));
895
907
  const waypoints = [{
896
908
  name: parts[11]
897
909
  }, {
898
910
  name: parts[12],
899
- time: DateTimeUtils.convertHHMMSSToTod(parts[13] + "00"),
911
+ time: DateTimeUtils.convertHHMMSSToTod(parts[13]),
900
912
  timeFormat: "tod"
901
913
  }, {
902
914
  name: parts[14],
903
- time: DateTimeUtils.convertHHMMSSToTod(parts[15] + "00"),
915
+ time: DateTimeUtils.convertHHMMSSToTod(parts[15]),
904
916
  timeFormat: "tod"
905
917
  }];
906
918
  ResultFormatter.route(decodeResult, { waypoints });
@@ -920,7 +932,7 @@ var Label_12_N_Space = class extends DecoderPlugin {
920
932
  qualifiers() {
921
933
  return {
922
934
  labels: ["12"],
923
- preambles: ["N "]
935
+ preambles: ["N ", "S "]
924
936
  };
925
937
  }
926
938
  decode(message, options = {}) {
@@ -986,7 +998,7 @@ var Label_13Through18_Slash = class extends DecoderPlugin {
986
998
  const data = parts[2].split(" ");
987
999
  ResultFormatter.departureAirport(decodeResult, data[1]);
988
1000
  ResultFormatter.arrivalAirport(decodeResult, data[2]);
989
- decodeResult.raw.day_of_month = Number(data[3]);
1001
+ decodeResult.raw.day = Number(data[3]);
990
1002
  const time = DateTimeUtils.convertHHMMSSToTod(data[4]);
991
1003
  if (labelNumber === 13) {
992
1004
  ResultFormatter.out(decodeResult, time);
@@ -1046,7 +1058,7 @@ function getMsgType(labelNumber) {
1046
1058
 
1047
1059
  // lib/plugins/Label_15.ts
1048
1060
  var Label_15 = class extends DecoderPlugin {
1049
- name = "label-5z";
1061
+ name = "label-15";
1050
1062
  qualifiers() {
1051
1063
  return {
1052
1064
  labels: ["15"],
@@ -1057,10 +1069,28 @@ var Label_15 = class extends DecoderPlugin {
1057
1069
  const decodeResult = this.defaultResult();
1058
1070
  decodeResult.decoder.name = this.name;
1059
1071
  decodeResult.formatted.description = "Position Report";
1060
- const twoZeeRegex = /^\(2(?<between>.+)\(Z$/;
1061
- const results = message.text.match(twoZeeRegex);
1062
- if (results?.groups) {
1063
- ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.between.substr(0, 13)));
1072
+ decodeResult.message = message;
1073
+ if (message.text.startsWith("(2") && message.text.endsWith("(Z")) {
1074
+ const between = message.text.substring(2, message.text.length - 2);
1075
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(between.substring(0, 13)));
1076
+ if (between.length === 25) {
1077
+ ResultFormatter.unknown(decodeResult, between.substring(13, 19));
1078
+ const alt = between.substring(19, 22);
1079
+ if (alt != "---") {
1080
+ ResultFormatter.altitude(decodeResult, 100 * Number(alt));
1081
+ }
1082
+ ResultFormatter.temperature(decodeResult, between.substring(22).replace(" ", "0"));
1083
+ } else {
1084
+ ResultFormatter.unknown(decodeResult, between.substring(13));
1085
+ }
1086
+ } else {
1087
+ if (options.debug) {
1088
+ console.log(`Decoder: Unknown 15 message: ${message.text}`);
1089
+ }
1090
+ ResultFormatter.unknown(decodeResult, message.text);
1091
+ decodeResult.decoded = false;
1092
+ decodeResult.decoder.decodeLevel = "none";
1093
+ return decodeResult;
1064
1094
  }
1065
1095
  decodeResult.decoded = true;
1066
1096
  decodeResult.decoder.decodeLevel = "partial";
@@ -1113,7 +1143,7 @@ var Label_16_N_Space = class extends DecoderPlugin {
1113
1143
  qualifiers() {
1114
1144
  return {
1115
1145
  labels: ["16"],
1116
- preambles: ["N "]
1146
+ preambles: ["N ", "S "]
1117
1147
  };
1118
1148
  }
1119
1149
  decode(message, options = {}) {
@@ -1243,7 +1273,7 @@ var Label_1L_3Line = class extends DecoderPlugin {
1243
1273
  }
1244
1274
  const eta = data.get("ETA");
1245
1275
  if (eta) {
1246
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta + "00"));
1276
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta));
1247
1277
  data.delete("ETA");
1248
1278
  }
1249
1279
  const alt = data.get("ALT");
@@ -1324,8 +1354,8 @@ var Label_1L_070 = class extends DecoderPlugin {
1324
1354
  }
1325
1355
  ResultFormatter.departureAirport(decodeResult, parts[0]);
1326
1356
  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"));
1357
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[2]));
1358
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[3]));
1329
1359
  ResultFormatter.position(decodeResult, {
1330
1360
  latitude: CoordinateUtils.getDirection(parts[4][0]) * Number(parts[4].substring(1)),
1331
1361
  longitude: CoordinateUtils.getDirection(parts[5][0]) * Number(parts[5].substring(1))
@@ -1445,7 +1475,7 @@ var Label_1L_Slash = class extends DecoderPlugin {
1445
1475
  }
1446
1476
  const eta = data.get("ETA");
1447
1477
  if (eta) {
1448
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta + "00"));
1478
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta));
1449
1479
  data.delete("ETA");
1450
1480
  }
1451
1481
  let remaining = "";
@@ -1579,7 +1609,7 @@ var Label_22_OFF = class extends DecoderPlugin {
1579
1609
  ResultFormatter.flightNumber(decodeResult, fields[0]);
1580
1610
  ResultFormatter.departureDay(decodeResult, Number(fields[1].substring(0, 2)));
1581
1611
  ResultFormatter.arrivalDay(decodeResult, Number(fields[1].substring(2, 4)));
1582
- ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(4, 8) + "00"));
1612
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(4, 8)));
1583
1613
  ResultFormatter.departureAirport(decodeResult, fields[1].substring(8, 12));
1584
1614
  ResultFormatter.arrivalAirport(decodeResult, fields[1].substring(12, 16));
1585
1615
  ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 22)));
@@ -1595,7 +1625,7 @@ var Label_22_OFF = class extends DecoderPlugin {
1595
1625
  }
1596
1626
  ResultFormatter.departureAirport(decodeResult, fields[0]);
1597
1627
  ResultFormatter.arrivalAirport(decodeResult, fields[1]);
1598
- ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2] + "00"));
1628
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2]));
1599
1629
  ResultFormatter.unknown(decodeResult, fields[3]);
1600
1630
  decodeResult.decoded = true;
1601
1631
  decodeResult.decoder.decodeLevel = "partial";
@@ -1612,12 +1642,12 @@ var Label_22_OFF = class extends DecoderPlugin {
1612
1642
  ResultFormatter.position(decodeResult, position);
1613
1643
  }
1614
1644
  ResultFormatter.day(decodeResult, Number(fields[1].substring(14, 16)));
1615
- ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 20) + "00"));
1645
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 20)));
1616
1646
  ResultFormatter.departureAirport(decodeResult, fields[1].substring(20, 24));
1617
1647
  ResultFormatter.arrivalAirport(decodeResult, fields[1].substring(24, 28));
1618
- ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(28, 32) + "00"));
1648
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(28, 32)));
1619
1649
  ResultFormatter.unknown(decodeResult, fields[1].substring(32, 36));
1620
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(36, 40) + "00"));
1650
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(36, 40)));
1621
1651
  decodeResult.decoded = true;
1622
1652
  decodeResult.decoder.decodeLevel = "partial";
1623
1653
  } else {
@@ -1699,7 +1729,7 @@ var Label_24_Slash = class extends DecoderPlugin {
1699
1729
  longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1))
1700
1730
  };
1701
1731
  ResultFormatter.position(decodeResult, position);
1702
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[8] + "00"));
1732
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[8]));
1703
1733
  ResultFormatter.unknown(decodeResult, fields[7]);
1704
1734
  decodeResult.decoded = true;
1705
1735
  decodeResult.decoder.decodeLevel = "partial";
@@ -1735,7 +1765,7 @@ var Label_30_Slash_EA = class extends DecoderPlugin {
1735
1765
  console.log(results);
1736
1766
  }
1737
1767
  }
1738
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results[0].substr(2, 4) + "00"));
1768
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results[0].substr(2, 4)));
1739
1769
  if (results[1].substring(0, 2) === "DS") {
1740
1770
  ResultFormatter.arrivalAirport(decodeResult, results[1].substring(2, 6));
1741
1771
  ResultFormatter.unknown(decodeResult, "/".concat(results[2]));
@@ -1762,22 +1792,35 @@ var Label_44_ETA = class extends DecoderPlugin {
1762
1792
  decodeResult.decoder.name = this.name;
1763
1793
  decodeResult.formatted.description = "ETA Report";
1764
1794
  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) {
1795
+ const data = message.text.split(",");
1796
+ if (data.length >= 9) {
1768
1797
  if (options.debug) {
1769
1798
  console.log(`Label 44 ETA Report: groups`);
1770
- console.log(results.groups);
1799
+ console.log(data);
1771
1800
  }
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
- ResultFormatter.remainingFuel(decodeResult, Number(results.groups.fuel_in_tons));
1801
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[1]));
1802
+ ResultFormatter.altitude(decodeResult, 100 * Number(data[2]));
1803
+ ResultFormatter.departureAirport(decodeResult, data[3]);
1804
+ ResultFormatter.arrivalAirport(decodeResult, data[4]);
1805
+ ResultFormatter.month(decodeResult, Number(data[5].substring(0, 2)));
1806
+ ResultFormatter.day(decodeResult, Number(data[5].substring(2, 4)));
1807
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[6]));
1808
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[7]));
1809
+ const fuel = Number(data[8]);
1810
+ if (!isNaN(fuel)) {
1811
+ ResultFormatter.remainingFuel(decodeResult, Number(fuel));
1812
+ }
1813
+ if (data.length > 9) {
1814
+ ResultFormatter.unknownArr(decodeResult, data.slice(9));
1815
+ }
1816
+ } else {
1817
+ if (options.debug) {
1818
+ console.log(`Decoder: Unknown 44 message: ${message.text}`);
1780
1819
  }
1820
+ ResultFormatter.unknown(decodeResult, message.text);
1821
+ decodeResult.decoded = false;
1822
+ decodeResult.decoder.decodeLevel = "none";
1823
+ return decodeResult;
1781
1824
  }
1782
1825
  decodeResult.decoded = true;
1783
1826
  decodeResult.decoder.decodeLevel = "full";
@@ -1799,22 +1842,33 @@ var Label_44_IN = class extends DecoderPlugin {
1799
1842
  decodeResult.decoder.name = this.name;
1800
1843
  decodeResult.formatted.description = "In Air Report";
1801
1844
  decodeResult.message = message;
1802
- const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
1803
- const results = message.text.match(regex);
1804
- if (results?.groups) {
1845
+ const data = message.text.split(",");
1846
+ if (data.length >= 7) {
1805
1847
  if (options.debug) {
1806
1848
  console.log(`Label 44 In Air Report: groups`);
1807
- console.log(results.groups);
1849
+ console.log(data);
1808
1850
  }
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
- if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1816
- decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1851
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[1]));
1852
+ ResultFormatter.departureAirport(decodeResult, data[2]);
1853
+ ResultFormatter.arrivalAirport(decodeResult, data[3]);
1854
+ ResultFormatter.month(decodeResult, Number(data[4].substring(0, 2)));
1855
+ ResultFormatter.day(decodeResult, Number(data[4].substring(2, 4)));
1856
+ ResultFormatter.in(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[5]));
1857
+ const fuel = Number(data[6]);
1858
+ if (!isNaN(fuel)) {
1859
+ ResultFormatter.remainingFuel(decodeResult, Number(fuel));
1860
+ }
1861
+ if (data.length > 7) {
1862
+ ResultFormatter.unknownArr(decodeResult, data.slice(7));
1863
+ }
1864
+ } else {
1865
+ if (options.debug) {
1866
+ console.log(`Decoder: Unknown 44 message: ${message.text}`);
1817
1867
  }
1868
+ ResultFormatter.unknown(decodeResult, message.text);
1869
+ decodeResult.decoded = false;
1870
+ decodeResult.decoder.decodeLevel = "none";
1871
+ return decodeResult;
1818
1872
  }
1819
1873
  decodeResult.decoded = true;
1820
1874
  decodeResult.decoder.decodeLevel = "full";
@@ -1836,25 +1890,34 @@ var Label_44_OFF = class extends DecoderPlugin {
1836
1890
  decodeResult.decoder.name = this.name;
1837
1891
  decodeResult.formatted.description = "Off Runway Report";
1838
1892
  decodeResult.message = message;
1839
- const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<eta_time>.*),(?<fuel_in_tons>.*)$/;
1840
- const results = message.text.match(regex);
1841
- if (results?.groups) {
1893
+ const data = message.text.split(",");
1894
+ if (data.length >= 8) {
1842
1895
  if (options.debug) {
1843
1896
  console.log(`Label 44 Off Runway Report: groups`);
1844
- console.log(results.groups);
1897
+ console.log(data);
1845
1898
  }
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);
1849
- decodeResult.raw.current_time = Date.parse(
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"
1851
- );
1852
- decodeResult.raw.eta_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.eta_time.substr(0, 2) + ":" + results.groups.eta_time.substr(2, 2) + ":00Z"
1854
- );
1855
- if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1856
- decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1899
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[1]));
1900
+ ResultFormatter.departureAirport(decodeResult, data[2]);
1901
+ ResultFormatter.arrivalAirport(decodeResult, data[3]);
1902
+ ResultFormatter.month(decodeResult, Number(data[4].substring(0, 2)));
1903
+ ResultFormatter.day(decodeResult, Number(data[4].substring(2, 4)));
1904
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[5]));
1905
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[6]));
1906
+ const fuel = Number(data[7]);
1907
+ if (!isNaN(fuel)) {
1908
+ ResultFormatter.remainingFuel(decodeResult, Number(fuel));
1909
+ }
1910
+ if (data.length > 8) {
1911
+ ResultFormatter.unknownArr(decodeResult, data.slice(8));
1912
+ }
1913
+ } else {
1914
+ if (options.debug) {
1915
+ console.log(`Decoder: Unknown 44 message: ${message.text}`);
1857
1916
  }
1917
+ ResultFormatter.unknown(decodeResult, message.text);
1918
+ decodeResult.decoded = false;
1919
+ decodeResult.decoder.decodeLevel = "none";
1920
+ return decodeResult;
1858
1921
  }
1859
1922
  decodeResult.decoded = true;
1860
1923
  decodeResult.decoder.decodeLevel = "full";
@@ -1876,22 +1939,33 @@ var Label_44_ON = class extends DecoderPlugin {
1876
1939
  decodeResult.decoder.name = this.name;
1877
1940
  decodeResult.formatted.description = "On Runway Report";
1878
1941
  decodeResult.message = message;
1879
- const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
1880
- const results = message.text.match(regex);
1881
- if (results?.groups) {
1942
+ const data = message.text.split(",");
1943
+ if (data.length >= 7) {
1882
1944
  if (options.debug) {
1883
1945
  console.log(`Label 44 On Runway Report: groups`);
1884
- console.log(results.groups);
1946
+ console.log(data);
1885
1947
  }
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);
1889
- decodeResult.raw.current_time = Date.parse(
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"
1891
- );
1892
- if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1893
- ResultFormatter.remainingFuel(decodeResult, Number(results.groups.fuel_in_tons));
1948
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[1]));
1949
+ ResultFormatter.departureAirport(decodeResult, data[2]);
1950
+ ResultFormatter.arrivalAirport(decodeResult, data[3]);
1951
+ ResultFormatter.month(decodeResult, Number(data[4].substring(0, 2)));
1952
+ ResultFormatter.day(decodeResult, Number(data[4].substring(2, 4)));
1953
+ ResultFormatter.on(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[5]));
1954
+ const fuel = Number(data[6]);
1955
+ if (!isNaN(fuel)) {
1956
+ ResultFormatter.remainingFuel(decodeResult, Number(fuel));
1957
+ }
1958
+ if (data.length > 7) {
1959
+ ResultFormatter.unknownArr(decodeResult, data.slice(7));
1960
+ }
1961
+ } else {
1962
+ if (options.debug) {
1963
+ console.log(`Decoder: Unknown 44 message: ${message.text}`);
1894
1964
  }
1965
+ ResultFormatter.unknown(decodeResult, message.text);
1966
+ decodeResult.decoded = false;
1967
+ decodeResult.decoder.decodeLevel = "none";
1968
+ return decodeResult;
1895
1969
  }
1896
1970
  decodeResult.decoded = true;
1897
1971
  decodeResult.decoder.decodeLevel = "full";
@@ -2150,456 +2224,95 @@ var Label_4A_Slash_01 = class extends DecoderPlugin {
2150
2224
  }
2151
2225
  };
2152
2226
 
2153
- // lib/plugins/Label_4N.ts
2154
- var Label_4N = class extends DecoderPlugin {
2155
- name = "label-4n";
2156
- qualifiers() {
2157
- return {
2158
- labels: ["4N"]
2159
- };
2160
- }
2161
- decode(message, options = {}) {
2162
- const decodeResult = this.defaultResult();
2163
- decodeResult.decoder.name = this.name;
2164
- decodeResult.message = message;
2165
- decodeResult.formatted.description = "Airline Defined";
2166
- let text = message.text;
2167
- if (text.match(/^M\d{2}A\w{6}/)) {
2168
- ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
2169
- text = text.substring(10);
2170
- }
2171
- decodeResult.decoded = true;
2172
- const fields = text.split(",");
2173
- if (text.length === 51) {
2174
- decodeResult.raw.day_of_month = text.substring(0, 2);
2175
- ResultFormatter.departureAirport(decodeResult, text.substring(8, 11));
2176
- ResultFormatter.arrivalAirport(decodeResult, text.substring(13, 16));
2177
- ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(30, 45).replace(/^(.)0/, "$1")));
2178
- ResultFormatter.altitude(decodeResult, Number(text.substring(48, 51)) * 100);
2179
- ResultFormatter.unknownArr(decodeResult, [text.substring(2, 4), text.substring(19, 29)], " ");
2180
- } else if (fields.length === 33) {
2181
- decodeResult.raw.date = fields[3];
2182
- if (fields[1] === "B") {
2183
- ResultFormatter.position(decodeResult, { latitude: Number(fields[4]), longitude: Number(fields[5]) });
2184
- ResultFormatter.altitude(decodeResult, Number(fields[6]));
2185
- }
2186
- ResultFormatter.departureAirport(decodeResult, fields[8]);
2187
- ResultFormatter.arrivalAirport(decodeResult, fields[9]);
2188
- ResultFormatter.alternateAirport(decodeResult, fields[10]);
2189
- ResultFormatter.arrivalRunway(decodeResult, fields[11].split("/")[0]);
2190
- if (fields[12].length > 1) {
2191
- ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
2227
+ // lib/utils/flight_plan_utils.ts
2228
+ var FlightPlanUtils = class _FlightPlanUtils {
2229
+ /**
2230
+ * Processes flight plan data
2231
+ *
2232
+ * Expected format is [header, key1, val1, ... keyN, valN]
2233
+ *
2234
+ * @param decodeResult - results
2235
+ * @param data - original message split by ':'
2236
+ * @returns whether all fields were processed or not
2237
+ */
2238
+ static processFlightPlan(decodeResult, data) {
2239
+ let allKnownFields = _FlightPlanUtils.parseHeader(decodeResult, data[0]);
2240
+ for (let i = 1; i < data.length; i += 2) {
2241
+ const key = data[i];
2242
+ const value = data[i + 1];
2243
+ switch (key) {
2244
+ case "A":
2245
+ addProcedure(decodeResult, value, "arrival");
2246
+ break;
2247
+ case "AA":
2248
+ addArrivalAirport(decodeResult, value);
2249
+ break;
2250
+ case "AP":
2251
+ addProcedure(decodeResult, value, "approach");
2252
+ break;
2253
+ case "CR":
2254
+ addCompanyRoute(decodeResult, value);
2255
+ break;
2256
+ case "D":
2257
+ addProcedure(decodeResult, value, "departure");
2258
+ break;
2259
+ case "DA":
2260
+ addDepartureAirport(decodeResult, value);
2261
+ break;
2262
+ case "F":
2263
+ addRoute(decodeResult, value);
2264
+ break;
2265
+ case "R":
2266
+ addRunway(decodeResult, value);
2267
+ break;
2268
+ // case 'WS': // something about routes, has altitude, so current parsing won't work
2269
+ // break;
2270
+ default:
2271
+ if (allKnownFields) {
2272
+ decodeResult.remaining.text = "";
2273
+ allKnownFields = false;
2274
+ }
2275
+ decodeResult.remaining.text += `:${key}:${value}`;
2276
+ decodeResult.decoder.decodeLevel = "partial";
2192
2277
  }
2193
- ResultFormatter.checksum(decodeResult, fields[32]);
2194
- ResultFormatter.unknownArr(decodeResult, [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != ""));
2195
- } else {
2196
- decodeResult.decoded = false;
2197
- ResultFormatter.unknown(decodeResult, text);
2198
2278
  }
2199
- if (decodeResult.decoded) {
2200
- if (!decodeResult.remaining.text)
2201
- decodeResult.decoder.decodeLevel = "full";
2202
- else
2203
- decodeResult.decoder.decodeLevel = "partial";
2279
+ return allKnownFields;
2280
+ }
2281
+ static parseHeader(decodeResult, header) {
2282
+ let allKnownFields = true;
2283
+ if (header.startsWith("RF")) {
2284
+ decodeResult.formatted.items.push({
2285
+ type: "status",
2286
+ code: "ROUTE_STATUS",
2287
+ label: "Route Status",
2288
+ value: "Route Filed"
2289
+ });
2290
+ decodeResult.raw.route_status = "RF";
2291
+ if (header.length > 2) {
2292
+ addRoute(decodeResult, header.substring(2));
2293
+ }
2294
+ } else if (header.startsWith("RP")) {
2295
+ decodeResult.raw.route_status = "RP";
2296
+ decodeResult.formatted.items.push({
2297
+ type: "status",
2298
+ code: "ROUTE_STATUS",
2299
+ label: "Route Status",
2300
+ value: "Route Planned"
2301
+ });
2302
+ decodeResult.raw.route_status = header;
2303
+ } else if (header.startsWith("RI")) {
2304
+ decodeResult.raw.route_status = "RI";
2305
+ decodeResult.formatted.items.push({
2306
+ type: "status",
2307
+ code: "ROUTE_STATUS",
2308
+ label: "Route Status",
2309
+ value: "Route Inactive"
2310
+ });
2204
2311
  } else {
2205
- decodeResult.decoder.decodeLevel = "none";
2312
+ decodeResult.remaining.text += header;
2313
+ allKnownFields = false;
2206
2314
  }
2207
- return decodeResult;
2208
- }
2209
- };
2210
-
2211
- // lib/plugins/Label_80.ts
2212
- var Label_80 = class extends DecoderPlugin {
2213
- name = "label-80";
2214
- descriptions = {
2215
- ALT: "Altitude",
2216
- DWND: "Wind Direction",
2217
- ETA: "Estimated Time of Arrival",
2218
- FOB: "Fuel on Board",
2219
- FL: "Flight Level",
2220
- HDG: "Heading",
2221
- MCH: "Aircraft Speed",
2222
- NWYP: "Next Waypoint",
2223
- POS: "Aircraft Position",
2224
- SAT: "Static Air Temperature",
2225
- SWND: "Wind Speed",
2226
- TAS: "True Airspeed",
2227
- WYP: "Waypoint"
2228
- };
2229
- qualifiers() {
2230
- return {
2231
- labels: ["80"],
2232
- preambles: ["3N01 POSRPT"]
2233
- };
2234
- }
2235
- decode(message, options = {}) {
2236
- const decodeResult = this.defaultResult();
2237
- decodeResult.decoder.name = this.name;
2238
- decodeResult.formatted.description = "Airline Defined Position Report";
2239
- const parts = message.text.split("\n");
2240
- let posRptRegex = /^3N01 POSRPT \d\d\d\d\/\d\d (?<orig>\w+)\/(?<dest>\w+) \.(?<tail>[\w-]+)(\/(?<agate>.+) (?<sta>\w+:\w+))*/;
2241
- let results = parts[0].match(posRptRegex);
2242
- if (!results?.groups) {
2243
- decodeResult.decoded = false;
2244
- decodeResult.decoder.decodeLevel = "none";
2245
- return decodeResult;
2246
- }
2247
- if (results && results.length > 0) {
2248
- ResultFormatter.departureAirport(decodeResult, results.groups.orig);
2249
- ResultFormatter.arrivalAirport(decodeResult, results.groups.dest);
2250
- ResultFormatter.tail(decodeResult, results.groups.tail);
2251
- if (results.groups.agate) {
2252
- decodeResult.raw.arrival_gate = results.groups.agate;
2253
- decodeResult.formatted.items.push({
2254
- type: "arrival_gate",
2255
- code: "ARG",
2256
- label: "Arrival Gate",
2257
- value: `${results.groups.agate}`
2258
- });
2259
- decodeResult.raw.scheduled_time_of_arrival = results.groups.sta;
2260
- decodeResult.formatted.items.push({
2261
- type: "scheduled_time_of_arrival",
2262
- code: "STA",
2263
- label: "Scheduled Time of Arrival",
2264
- value: `${results.groups.sta}`
2265
- });
2266
- }
2267
- posRptRegex = /\/(?<field>\w+)\s(?<value>[\w\+\-:\.]+)\s*/gi;
2268
- const remainingParts = parts.slice(1);
2269
- for (const part of remainingParts) {
2270
- const matches = part.matchAll(posRptRegex);
2271
- for (const match of matches) {
2272
- switch (match.groups?.field) {
2273
- case "ALT": {
2274
- ResultFormatter.altitude(decodeResult, Number(match.groups.value));
2275
- break;
2276
- }
2277
- case "DWND": {
2278
- decodeResult.raw.wind_direction = Number(match.groups.value);
2279
- decodeResult.formatted.items.push({
2280
- type: "wind_direction",
2281
- code: "DWND",
2282
- label: this.descriptions[match.groups.field],
2283
- value: decodeResult.raw.wind_direction
2284
- });
2285
- break;
2286
- }
2287
- case "FL": {
2288
- const flight_level = Number(match.groups.value);
2289
- ResultFormatter.altitude(decodeResult, flight_level * 100);
2290
- break;
2291
- }
2292
- case "FOB": {
2293
- const fob = Number(match.groups.value);
2294
- if (!isNaN(fob)) {
2295
- ResultFormatter.currentFuel(decodeResult, fob);
2296
- }
2297
- break;
2298
- }
2299
- case "HDG": {
2300
- ResultFormatter.heading(decodeResult, Number(match.groups.value));
2301
- break;
2302
- }
2303
- case "MCH": {
2304
- decodeResult.raw.mach = Number(match.groups.value) / 1e3;
2305
- decodeResult.formatted.items.push({
2306
- type: "mach",
2307
- code: "MCH",
2308
- label: this.descriptions[match.groups.field],
2309
- value: `${decodeResult.raw.mach} Mach`
2310
- });
2311
- break;
2312
- }
2313
- case "NWYP": {
2314
- decodeResult.raw.next_waypoint = match.groups.value;
2315
- decodeResult.formatted.items.push({
2316
- type: "next_waypoint",
2317
- code: "NWYP",
2318
- label: this.descriptions[match.groups.field],
2319
- value: decodeResult.raw.next_waypoint
2320
- });
2321
- break;
2322
- }
2323
- case "POS": {
2324
- const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
2325
- const posResult = match.groups.value.match(posRegex);
2326
- const lat = Number(posResult?.groups?.lat) * (posResult?.groups?.lngd === "S" ? -1 : 1);
2327
- const lon = Number(posResult?.groups?.lng) * (posResult?.groups?.lngd === "W" ? -1 : 1);
2328
- const position = {
2329
- latitude: Number.isInteger(lat) ? lat / 1e3 : lat / 100,
2330
- longitude: Number.isInteger(lon) ? lon / 1e3 : lon / 100
2331
- };
2332
- ResultFormatter.position(decodeResult, position);
2333
- break;
2334
- }
2335
- case "SWND": {
2336
- decodeResult.raw.wind_speed = Number(match.groups.value);
2337
- decodeResult.formatted.items.push({
2338
- type: "wind_speed",
2339
- code: "SWND",
2340
- label: this.descriptions[match.groups.field],
2341
- value: decodeResult.raw.wind_speed
2342
- });
2343
- break;
2344
- }
2345
- default: {
2346
- if (match.groups?.field != void 0) {
2347
- const description = this.descriptions[match.groups.field] ? this.descriptions[match.groups.field] : "Unknown";
2348
- decodeResult.formatted.items.push({
2349
- type: match.groups.field,
2350
- code: match.groups.field,
2351
- label: description || `Unknown (${match.groups.field})`,
2352
- value: `${match.groups.value}`
2353
- });
2354
- }
2355
- }
2356
- }
2357
- }
2358
- }
2359
- decodeResult.decoded = true;
2360
- decodeResult.decoder.decodeLevel = "partial";
2361
- }
2362
- return decodeResult;
2363
- }
2364
- };
2365
-
2366
- // lib/plugins/Label_83.ts
2367
- var Label_83 = class extends DecoderPlugin {
2368
- name = "label-83";
2369
- qualifiers() {
2370
- return {
2371
- labels: ["83"]
2372
- };
2373
- }
2374
- decode(message, options = {}) {
2375
- const decodeResult = this.defaultResult();
2376
- decodeResult.decoder.name = this.name;
2377
- decodeResult.message = message;
2378
- decodeResult.formatted.description = "Airline Defined";
2379
- let text = message.text;
2380
- if (text.match(/^M\d{2}A\w{6}/)) {
2381
- ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
2382
- text = text.substring(10);
2383
- }
2384
- decodeResult.decoded = true;
2385
- if (text.substring(0, 10) === "4DH3 ETAT2") {
2386
- const fields = text.split(/\s+/);
2387
- if (fields[2].length > 5) {
2388
- decodeResult.raw.day_of_month = fields[2].substring(5);
2389
- }
2390
- ResultFormatter.unknown(decodeResult, fields[2].substring(0, 4));
2391
- const subfields = fields[3].split("/");
2392
- ResultFormatter.departureAirport(decodeResult, subfields[0]);
2393
- ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
2394
- ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
2395
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[6] + "00"));
2396
- } else if (text.substring(0, 5) === "001PR") {
2397
- decodeResult.raw.day_of_month = text.substring(5, 7);
2398
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(13, 28).replace(/\./g, ""));
2399
- if (position) {
2400
- ResultFormatter.position(decodeResult, position);
2401
- }
2402
- ResultFormatter.altitude(decodeResult, Number(text.substring(28, 33)));
2403
- ResultFormatter.unknown(decodeResult, text.substring(33));
2404
- } else {
2405
- const fields = text.replace(/\s/g, "").split(",");
2406
- if (fields.length === 9) {
2407
- ResultFormatter.departureAirport(decodeResult, fields[0]);
2408
- ResultFormatter.arrivalAirport(decodeResult, fields[1]);
2409
- decodeResult.raw.day_of_month = fields[2].substring(0, 2);
2410
- decodeResult.raw.time = fields[2].substring(2);
2411
- ResultFormatter.position(
2412
- decodeResult,
2413
- {
2414
- latitude: Number(fields[3].replace(/\s/g, "")),
2415
- longitude: Number(fields[4].replace(/\s/g, ""))
2416
- }
2417
- );
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]);
2422
- } else {
2423
- decodeResult.decoded = false;
2424
- ResultFormatter.unknown(decodeResult, message.text);
2425
- }
2426
- }
2427
- if (decodeResult.decoded) {
2428
- if (!decodeResult.remaining.text)
2429
- decodeResult.decoder.decodeLevel = "full";
2430
- else
2431
- decodeResult.decoder.decodeLevel = "partial";
2432
- } else {
2433
- decodeResult.decoder.decodeLevel = "none";
2434
- }
2435
- return decodeResult;
2436
- }
2437
- };
2438
-
2439
- // lib/plugins/Label_8E.ts
2440
- var Label_8E = class extends DecoderPlugin {
2441
- name = "label-8e";
2442
- qualifiers() {
2443
- return {
2444
- labels: ["8E"]
2445
- };
2446
- }
2447
- decode(message, options = {}) {
2448
- const decodeResult = this.defaultResult();
2449
- decodeResult.decoder.name = this.name;
2450
- decodeResult.formatted.description = "ETA Report";
2451
- decodeResult.message = message;
2452
- const regex = /^(?<arrival_icao>\w{4}),(?<arrival_eta>\d{4})$/;
2453
- const results = message.text.match(regex);
2454
- if (results?.groups) {
2455
- if (options.debug) {
2456
- console.log(`Label 8E ETA: groups`);
2457
- console.log(results.groups);
2458
- }
2459
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta + "00"));
2460
- ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
2461
- }
2462
- decodeResult.decoded = true;
2463
- decodeResult.decoder.decodeLevel = "full";
2464
- return decodeResult;
2465
- }
2466
- };
2467
-
2468
- // lib/plugins/Label_B6.ts
2469
- var Label_B6_Forwardslash = class extends DecoderPlugin {
2470
- name = "label-b6-forwardslash";
2471
- qualifiers() {
2472
- return {
2473
- labels: ["B6"],
2474
- preambles: ["/"]
2475
- };
2476
- }
2477
- decode(message, options = {}) {
2478
- const decodeResult = this.defaultResult();
2479
- decodeResult.decoder.name = this.name;
2480
- decodeResult.formatted.description = "CPDLC Message";
2481
- decodeResult.message = message;
2482
- if (options.debug) {
2483
- console.log("CPDLC: " + message);
2484
- }
2485
- return decodeResult;
2486
- }
2487
- };
2488
-
2489
- // lib/plugins/Label_ColonComma.ts
2490
- var Label_ColonComma = class extends DecoderPlugin {
2491
- name = "label-colon-comma";
2492
- qualifiers() {
2493
- return {
2494
- labels: [":;"]
2495
- };
2496
- }
2497
- decode(message, options = {}) {
2498
- const decodeResult = this.defaultResult();
2499
- decodeResult.decoder.name = this.name;
2500
- decodeResult.raw.frequency = Number(message.text) / 1e3;
2501
- decodeResult.formatted.description = "Aircraft Transceiver Frequency Change";
2502
- decodeResult.formatted.items.push({
2503
- type: "frequency",
2504
- label: "Frequency",
2505
- value: `${decodeResult.raw.frequency} MHz`,
2506
- code: "FREQ"
2507
- });
2508
- decodeResult.decoded = true;
2509
- decodeResult.decoder.decodeLevel = "full";
2510
- return decodeResult;
2511
- }
2512
- };
2513
-
2514
- // lib/utils/flight_plan_utils.ts
2515
- var FlightPlanUtils = class _FlightPlanUtils {
2516
- /**
2517
- * Processes flight plan data
2518
- *
2519
- * Expected format is [header, key1, val1, ... keyN, valN]
2520
- *
2521
- * @param decodeResult - results
2522
- * @param data - original message split by ':'
2523
- * @returns whether all fields were processed or not
2524
- */
2525
- static processFlightPlan(decodeResult, data) {
2526
- let allKnownFields = _FlightPlanUtils.parseHeader(decodeResult, data[0]);
2527
- for (let i = 1; i < data.length; i += 2) {
2528
- const key = data[i];
2529
- const value = data[i + 1];
2530
- switch (key) {
2531
- case "A":
2532
- addProcedure(decodeResult, value, "arrival");
2533
- break;
2534
- case "AA":
2535
- addArrivalAirport(decodeResult, value);
2536
- break;
2537
- case "AP":
2538
- addProcedure(decodeResult, value, "approach");
2539
- break;
2540
- case "CR":
2541
- addCompanyRoute(decodeResult, value);
2542
- break;
2543
- case "D":
2544
- addProcedure(decodeResult, value, "departure");
2545
- break;
2546
- case "DA":
2547
- addDepartureAirport(decodeResult, value);
2548
- break;
2549
- case "F":
2550
- addRoute(decodeResult, value);
2551
- break;
2552
- case "R":
2553
- addRunway(decodeResult, value);
2554
- break;
2555
- // case 'WS': // something about routes, has altitude, so current parsing won't work
2556
- // break;
2557
- default:
2558
- if (allKnownFields) {
2559
- decodeResult.remaining.text = "";
2560
- allKnownFields = false;
2561
- }
2562
- decodeResult.remaining.text += `:${key}:${value}`;
2563
- decodeResult.decoder.decodeLevel = "partial";
2564
- }
2565
- }
2566
- return allKnownFields;
2567
- }
2568
- static parseHeader(decodeResult, header) {
2569
- let allKnownFields = true;
2570
- if (header.startsWith("RF")) {
2571
- decodeResult.formatted.items.push({
2572
- type: "status",
2573
- code: "ROUTE_STATUS",
2574
- label: "Route Status",
2575
- value: "Route Filed"
2576
- });
2577
- decodeResult.raw.route_status = "RF";
2578
- if (header.length > 2) {
2579
- addRoute(decodeResult, header.substring(2));
2580
- }
2581
- } else if (header.startsWith("RP")) {
2582
- decodeResult.raw.route_status = "RP";
2583
- decodeResult.formatted.items.push({
2584
- type: "status",
2585
- code: "ROUTE_STATUS",
2586
- label: "Route Status",
2587
- value: "Route Planned"
2588
- });
2589
- decodeResult.raw.route_status = header;
2590
- } else if (header.startsWith("RI")) {
2591
- decodeResult.raw.route_status = "RI";
2592
- decodeResult.formatted.items.push({
2593
- type: "status",
2594
- code: "ROUTE_STATUS",
2595
- label: "Route Status",
2596
- value: "Route Inactive"
2597
- });
2598
- } else {
2599
- decodeResult.remaining.text += header;
2600
- allKnownFields = false;
2601
- }
2602
- return allKnownFields;
2315
+ return allKnownFields;
2603
2316
  }
2604
2317
  };
2605
2318
  function addArrivalAirport(decodeResult, value) {
@@ -2711,9 +2424,11 @@ var H1Helper = class {
2711
2424
  ResultFormatter.freetext(decodeResult, fields[i].substring(2));
2712
2425
  } else if (fields[i].startsWith("ET")) {
2713
2426
  if (fields[i].length === 7) {
2714
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(3) + "00"));
2427
+ ResultFormatter.day(decodeResult, Number(fields[i].substring(2, 3)));
2428
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(3)));
2715
2429
  } else if (fields[i].length === 8) {
2716
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(4) + "00"));
2430
+ ResultFormatter.day(decodeResult, Number(fields[i].substring(2, 4)));
2431
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(4)));
2717
2432
  } else {
2718
2433
  ResultFormatter.unknown(decodeResult, fields[i], "/");
2719
2434
  }
@@ -2764,161 +2479,554 @@ function processIdentification(decodeResult, data) {
2764
2479
  decodeResult.raw.mission_number = data[2];
2765
2480
  }
2766
2481
  }
2767
- function processDT(decodeResult, data) {
2768
- if (!decodeResult.raw.arrival_icao) {
2769
- ResultFormatter.arrivalAirport(decodeResult, data[0]);
2770
- } else if (decodeResult.raw.arrival_icao != data[0]) {
2771
- ResultFormatter.unknownArr(decodeResult, data);
2482
+ function processDT(decodeResult, data) {
2483
+ if (!decodeResult.raw.arrival_icao) {
2484
+ ResultFormatter.arrivalAirport(decodeResult, data[0]);
2485
+ } else if (decodeResult.raw.arrival_icao != data[0]) {
2486
+ ResultFormatter.unknownArr(decodeResult, data);
2487
+ }
2488
+ if (data.length > 1) {
2489
+ ResultFormatter.arrivalRunway(decodeResult, data[1]);
2490
+ }
2491
+ if (data.length > 2) {
2492
+ ResultFormatter.currentFuel(decodeResult, Number(data[2]));
2493
+ }
2494
+ if (data.length > 3) {
2495
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[3]));
2496
+ }
2497
+ if (data.length > 4) {
2498
+ ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
2499
+ }
2500
+ if (data.length > 5) {
2501
+ ResultFormatter.unknownArr(decodeResult, data);
2502
+ }
2503
+ }
2504
+ function processLR(decodeResult, data) {
2505
+ if (data.length === 19) {
2506
+ ResultFormatter.unknown(decodeResult, data[1]);
2507
+ ResultFormatter.flightNumber(decodeResult, data[2]);
2508
+ ResultFormatter.departureAirport(decodeResult, data[3]);
2509
+ ResultFormatter.arrivalAirport(decodeResult, data[4]);
2510
+ ResultFormatter.arrivalRunway(decodeResult, data[5]);
2511
+ ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
2512
+ } else {
2513
+ ResultFormatter.unknown(decodeResult, data.join(","));
2514
+ }
2515
+ }
2516
+ function parseMessageType(decodeResult, messageType) {
2517
+ const parts = messageType.split("#");
2518
+ if (parts.length == 1) {
2519
+ const type = parts[0].substring(0, 3);
2520
+ if (type === "POS" && parts[0].length !== 3) {
2521
+ processPosition2(decodeResult, parts[0].substring(3).split(","));
2522
+ }
2523
+ return processMessageType(decodeResult, type);
2524
+ } else if (parts.length == 2) {
2525
+ if (parts[0].length > 0) {
2526
+ ResultFormatter.unknown(decodeResult, parts[0].substring(0, 3));
2527
+ decodeResult.raw.flight_number = parts[0].substring(3);
2528
+ ResultFormatter.unknown(decodeResult, parts[1].length == 5 ? parts[1].substring(0, 2) : parts[1].substring(0, 3), "#");
2529
+ }
2530
+ const type = parts[1].length == 5 ? parts[1].substring(2, 5) : parts[1].substring(3, 6);
2531
+ if (parts[1].substring(3, 6) === "POS" && parts[1].length > 6) {
2532
+ processPosition2(decodeResult, parts[1].substring(6).split(","));
2533
+ }
2534
+ processMessageType(decodeResult, type);
2535
+ } else {
2536
+ ResultFormatter.unknown(decodeResult, messageType);
2537
+ }
2538
+ }
2539
+ function processMessageType(decodeResult, type) {
2540
+ if (type === "FPN") {
2541
+ decodeResult.formatted.description = "Flight Plan";
2542
+ } else if (type === "FTX") {
2543
+ decodeResult.formatted.description = "Free Text";
2544
+ } else if (type === "INI") {
2545
+ decodeResult.formatted.description = "Flight Plan Initial Report";
2546
+ } else if (type === "POS") {
2547
+ decodeResult.formatted.description = "Position Report";
2548
+ } else if (type === "PRG") {
2549
+ decodeResult.formatted.description = "Progress Report";
2550
+ } else {
2551
+ decodeResult.formatted.description = "Unknown H1 Message";
2552
+ }
2553
+ }
2554
+ function processDC(decodeResult, data) {
2555
+ decodeResult.raw.message_date = data[0];
2556
+ if (data.length === 1) {
2557
+ } else if (data.length === 2) {
2558
+ const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
2559
+ const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
2560
+ decodeResult.raw.message_timestamp = time;
2561
+ }
2562
+ }
2563
+ function processPS(decodeResult, data) {
2564
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2565
+ if (position) {
2566
+ decodeResult.raw.position = position;
2567
+ decodeResult.formatted.items.push({
2568
+ type: "aircraft_position",
2569
+ code: "POS",
2570
+ label: "Aircraft Position",
2571
+ value: CoordinateUtils.coordinateString(position)
2572
+ });
2573
+ }
2574
+ if (data.length === 9) {
2575
+ processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
2576
+ ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
2577
+ ResultFormatter.temperature(decodeResult, data[6]);
2578
+ ResultFormatter.unknown(decodeResult, data[7]);
2579
+ ResultFormatter.unknown(decodeResult, data[8]);
2580
+ }
2581
+ if (data.length === 14) {
2582
+ ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2583
+ processRoute(decodeResult, data[4], data[2], data[6], data[5], void 0);
2584
+ ResultFormatter.temperature(decodeResult, data[7]);
2585
+ ResultFormatter.groundspeed(decodeResult, Number(data[10]));
2586
+ ResultFormatter.unknown(decodeResult, data[1]);
2587
+ ResultFormatter.unknown(decodeResult, data[8]);
2588
+ ResultFormatter.unknown(decodeResult, data[9]);
2589
+ ResultFormatter.unknown(decodeResult, data.slice(11).join(","));
2590
+ }
2591
+ }
2592
+ function processPosition2(decodeResult, data) {
2593
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2594
+ if (position) {
2595
+ decodeResult.raw.position = position;
2596
+ decodeResult.formatted.items.push({
2597
+ type: "aircraft_position",
2598
+ code: "POS",
2599
+ label: "Aircraft Position",
2600
+ value: CoordinateUtils.coordinateString(position)
2601
+ });
2602
+ }
2603
+ if (data.length >= 10) {
2604
+ ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2605
+ processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
2606
+ ResultFormatter.temperature(decodeResult, data[7]);
2607
+ ResultFormatter.unknown(decodeResult, data[8]);
2608
+ ResultFormatter.unknown(decodeResult, data[9]);
2609
+ }
2610
+ if (data.length >= 14) {
2611
+ ResultFormatter.groundspeed(decodeResult, Number(data[10]));
2612
+ ResultFormatter.unknown(decodeResult, data[11]);
2613
+ ResultFormatter.unknown(decodeResult, data[12]);
2614
+ ResultFormatter.unknown(decodeResult, data[13]);
2615
+ }
2616
+ }
2617
+ function processRoute(decodeResult, last, time, next, eta, then, date) {
2618
+ const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
2619
+ const nextTime = date ? DateTimeUtils.convertDateTimeToEpoch(eta, date) : DateTimeUtils.convertHHMMSSToTod(eta);
2620
+ const timeFormat = date ? "epoch" : "tod";
2621
+ const lastWaypoint = RouteUtils.getWaypoint(last);
2622
+ lastWaypoint.time = lastTime;
2623
+ lastWaypoint.timeFormat = timeFormat;
2624
+ const nextWaypoint = RouteUtils.getWaypoint(next);
2625
+ nextWaypoint.time = nextTime;
2626
+ nextWaypoint.timeFormat = timeFormat;
2627
+ const thenWaypoint = RouteUtils.getWaypoint(then || "?");
2628
+ const waypoints = [lastWaypoint, nextWaypoint, thenWaypoint];
2629
+ decodeResult.raw.route = { waypoints };
2630
+ decodeResult.formatted.items.push({
2631
+ type: "aircraft_route",
2632
+ code: "ROUTE",
2633
+ label: "Aircraft Route",
2634
+ value: RouteUtils.routeToString(decodeResult.raw.route)
2635
+ });
2636
+ }
2637
+
2638
+ // lib/plugins/Label_4J_POS.ts
2639
+ var Label_4J_POS = class extends DecoderPlugin {
2640
+ name = "label-4j-pos";
2641
+ qualifiers() {
2642
+ return {
2643
+ labels: ["4J"],
2644
+ preambles: ["POS/"]
2645
+ };
2772
2646
  }
2773
- if (data.length > 1) {
2774
- ResultFormatter.arrivalRunway(decodeResult, data[1]);
2647
+ // copied from Label_H1.ts since i don't really want to have to have
2648
+ // something named like that decode more than 1 type
2649
+ // if we figure out a good name, i'll combine them
2650
+ decode(message, options = {}) {
2651
+ let decodeResult = this.defaultResult();
2652
+ decodeResult.decoder.name = this.name;
2653
+ decodeResult.message = message;
2654
+ const msg = message.text.replace(/\n|\r/g, "");
2655
+ const decoded = H1Helper.decodeH1Message(decodeResult, msg);
2656
+ decodeResult.decoded = decoded;
2657
+ decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
2658
+ if (decodeResult.formatted.items.length === 0) {
2659
+ if (options.debug) {
2660
+ console.log(`Decoder: Unknown H1 message: ${message.text}`);
2661
+ }
2662
+ ResultFormatter.unknown(decodeResult, message.text);
2663
+ decodeResult.decoded = false;
2664
+ decodeResult.decoder.decodeLevel = "none";
2665
+ }
2666
+ return decodeResult;
2775
2667
  }
2776
- if (data.length > 2) {
2777
- ResultFormatter.currentFuel(decodeResult, Number(data[2]));
2668
+ };
2669
+
2670
+ // lib/plugins/Label_4N.ts
2671
+ var Label_4N = class extends DecoderPlugin {
2672
+ name = "label-4n";
2673
+ qualifiers() {
2674
+ return {
2675
+ labels: ["4N"]
2676
+ };
2778
2677
  }
2779
- if (data.length > 3) {
2780
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[3]));
2678
+ decode(message, options = {}) {
2679
+ const decodeResult = this.defaultResult();
2680
+ decodeResult.decoder.name = this.name;
2681
+ decodeResult.message = message;
2682
+ decodeResult.formatted.description = "Airline Defined";
2683
+ let text = message.text;
2684
+ if (text.match(/^M\d{2}A\w{6}/)) {
2685
+ ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
2686
+ text = text.substring(10);
2687
+ }
2688
+ decodeResult.decoded = true;
2689
+ const fields = text.split(",");
2690
+ if (text.length === 51) {
2691
+ decodeResult.raw.day = text.substring(0, 2);
2692
+ ResultFormatter.departureAirport(decodeResult, text.substring(8, 11));
2693
+ ResultFormatter.arrivalAirport(decodeResult, text.substring(13, 16));
2694
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(30, 45).replace(/^(.)0/, "$1")));
2695
+ ResultFormatter.altitude(decodeResult, Number(text.substring(48, 51)) * 100);
2696
+ ResultFormatter.unknownArr(decodeResult, [text.substring(2, 4), text.substring(19, 29)], " ");
2697
+ } else if (fields.length === 33) {
2698
+ decodeResult.raw.date = fields[3];
2699
+ if (fields[1] === "B") {
2700
+ ResultFormatter.position(decodeResult, { latitude: Number(fields[4]), longitude: Number(fields[5]) });
2701
+ ResultFormatter.altitude(decodeResult, Number(fields[6]));
2702
+ }
2703
+ ResultFormatter.departureAirport(decodeResult, fields[8]);
2704
+ ResultFormatter.arrivalAirport(decodeResult, fields[9]);
2705
+ ResultFormatter.alternateAirport(decodeResult, fields[10]);
2706
+ ResultFormatter.arrivalRunway(decodeResult, fields[11].split("/")[0]);
2707
+ if (fields[12].length > 1) {
2708
+ ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
2709
+ }
2710
+ ResultFormatter.checksum(decodeResult, fields[32]);
2711
+ ResultFormatter.unknownArr(decodeResult, [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != ""));
2712
+ } else {
2713
+ decodeResult.decoded = false;
2714
+ ResultFormatter.unknown(decodeResult, text);
2715
+ }
2716
+ if (decodeResult.decoded) {
2717
+ if (!decodeResult.remaining.text)
2718
+ decodeResult.decoder.decodeLevel = "full";
2719
+ else
2720
+ decodeResult.decoder.decodeLevel = "partial";
2721
+ } else {
2722
+ decodeResult.decoder.decodeLevel = "none";
2723
+ }
2724
+ return decodeResult;
2781
2725
  }
2782
- if (data.length > 4) {
2783
- ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
2726
+ };
2727
+
2728
+ // lib/plugins/Label_80.ts
2729
+ var Label_80 = class extends DecoderPlugin {
2730
+ name = "label-80";
2731
+ descriptions = {
2732
+ ALT: "Altitude",
2733
+ DWND: "Wind Direction",
2734
+ ETA: "Estimated Time of Arrival",
2735
+ FOB: "Fuel on Board",
2736
+ FL: "Flight Level",
2737
+ HDG: "Heading",
2738
+ MCH: "Aircraft Speed",
2739
+ NWYP: "Next Waypoint",
2740
+ POS: "Aircraft Position",
2741
+ SAT: "Static Air Temperature",
2742
+ SWND: "Wind Speed",
2743
+ TAS: "True Airspeed",
2744
+ WYP: "Waypoint"
2745
+ };
2746
+ qualifiers() {
2747
+ return {
2748
+ labels: ["80"],
2749
+ preambles: ["3N01 POSRPT"]
2750
+ };
2784
2751
  }
2785
- if (data.length > 5) {
2786
- ResultFormatter.unknownArr(decodeResult, data);
2752
+ decode(message, options = {}) {
2753
+ const decodeResult = this.defaultResult();
2754
+ decodeResult.decoder.name = this.name;
2755
+ decodeResult.formatted.description = "Airline Defined Position Report";
2756
+ const parts = message.text.split("\n");
2757
+ let posRptRegex = /^3N01 POSRPT \d\d\d\d\/\d\d (?<orig>\w+)\/(?<dest>\w+) \.(?<tail>[\w-]+)(\/(?<agate>.+) (?<sta>\w+:\w+))*/;
2758
+ let results = parts[0].match(posRptRegex);
2759
+ if (!results?.groups) {
2760
+ decodeResult.decoded = false;
2761
+ decodeResult.decoder.decodeLevel = "none";
2762
+ return decodeResult;
2763
+ }
2764
+ if (results && results.length > 0) {
2765
+ ResultFormatter.departureAirport(decodeResult, results.groups.orig);
2766
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.dest);
2767
+ ResultFormatter.tail(decodeResult, results.groups.tail);
2768
+ if (results.groups.agate) {
2769
+ decodeResult.raw.arrival_gate = results.groups.agate;
2770
+ decodeResult.formatted.items.push({
2771
+ type: "arrival_gate",
2772
+ code: "ARG",
2773
+ label: "Arrival Gate",
2774
+ value: `${results.groups.agate}`
2775
+ });
2776
+ decodeResult.raw.scheduled_time_of_arrival = results.groups.sta;
2777
+ decodeResult.formatted.items.push({
2778
+ type: "scheduled_time_of_arrival",
2779
+ code: "STA",
2780
+ label: "Scheduled Time of Arrival",
2781
+ value: `${results.groups.sta}`
2782
+ });
2783
+ }
2784
+ posRptRegex = /\/(?<field>\w+)\s(?<value>[\w\+\-:\.]+)\s*/gi;
2785
+ const remainingParts = parts.slice(1);
2786
+ for (const part of remainingParts) {
2787
+ const matches = part.matchAll(posRptRegex);
2788
+ for (const match of matches) {
2789
+ switch (match.groups?.field) {
2790
+ case "ALT": {
2791
+ ResultFormatter.altitude(decodeResult, Number(match.groups.value));
2792
+ break;
2793
+ }
2794
+ case "DWND": {
2795
+ decodeResult.raw.wind_direction = Number(match.groups.value);
2796
+ decodeResult.formatted.items.push({
2797
+ type: "wind_direction",
2798
+ code: "DWND",
2799
+ label: this.descriptions[match.groups.field],
2800
+ value: decodeResult.raw.wind_direction
2801
+ });
2802
+ break;
2803
+ }
2804
+ case "FL": {
2805
+ const flight_level = Number(match.groups.value);
2806
+ ResultFormatter.altitude(decodeResult, flight_level * 100);
2807
+ break;
2808
+ }
2809
+ case "FOB": {
2810
+ const fob = Number(match.groups.value);
2811
+ if (!isNaN(fob)) {
2812
+ ResultFormatter.currentFuel(decodeResult, fob);
2813
+ }
2814
+ break;
2815
+ }
2816
+ case "HDG": {
2817
+ ResultFormatter.heading(decodeResult, Number(match.groups.value));
2818
+ break;
2819
+ }
2820
+ case "MCH": {
2821
+ decodeResult.raw.mach = Number(match.groups.value) / 1e3;
2822
+ decodeResult.formatted.items.push({
2823
+ type: "mach",
2824
+ code: "MCH",
2825
+ label: this.descriptions[match.groups.field],
2826
+ value: `${decodeResult.raw.mach} Mach`
2827
+ });
2828
+ break;
2829
+ }
2830
+ case "NWYP": {
2831
+ decodeResult.raw.next_waypoint = match.groups.value;
2832
+ decodeResult.formatted.items.push({
2833
+ type: "next_waypoint",
2834
+ code: "NWYP",
2835
+ label: this.descriptions[match.groups.field],
2836
+ value: decodeResult.raw.next_waypoint
2837
+ });
2838
+ break;
2839
+ }
2840
+ case "POS": {
2841
+ const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
2842
+ const posResult = match.groups.value.match(posRegex);
2843
+ const lat = Number(posResult?.groups?.lat) * (posResult?.groups?.lngd === "S" ? -1 : 1);
2844
+ const lon = Number(posResult?.groups?.lng) * (posResult?.groups?.lngd === "W" ? -1 : 1);
2845
+ const position = {
2846
+ latitude: Number.isInteger(lat) ? lat / 1e3 : lat / 100,
2847
+ longitude: Number.isInteger(lon) ? lon / 1e3 : lon / 100
2848
+ };
2849
+ ResultFormatter.position(decodeResult, position);
2850
+ break;
2851
+ }
2852
+ case "SWND": {
2853
+ decodeResult.raw.wind_speed = Number(match.groups.value);
2854
+ decodeResult.formatted.items.push({
2855
+ type: "wind_speed",
2856
+ code: "SWND",
2857
+ label: this.descriptions[match.groups.field],
2858
+ value: decodeResult.raw.wind_speed
2859
+ });
2860
+ break;
2861
+ }
2862
+ default: {
2863
+ if (match.groups?.field != void 0) {
2864
+ const description = this.descriptions[match.groups.field] ? this.descriptions[match.groups.field] : "Unknown";
2865
+ decodeResult.formatted.items.push({
2866
+ type: match.groups.field,
2867
+ code: match.groups.field,
2868
+ label: description || `Unknown (${match.groups.field})`,
2869
+ value: `${match.groups.value}`
2870
+ });
2871
+ }
2872
+ }
2873
+ }
2874
+ }
2875
+ }
2876
+ decodeResult.decoded = true;
2877
+ decodeResult.decoder.decodeLevel = "partial";
2878
+ }
2879
+ return decodeResult;
2787
2880
  }
2788
- }
2789
- function processLR(decodeResult, data) {
2790
- if (data.length === 19) {
2791
- ResultFormatter.unknown(decodeResult, data[1]);
2792
- ResultFormatter.flightNumber(decodeResult, data[2]);
2793
- ResultFormatter.departureAirport(decodeResult, data[3]);
2794
- ResultFormatter.arrivalAirport(decodeResult, data[4]);
2795
- ResultFormatter.arrivalRunway(decodeResult, data[5]);
2796
- ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
2797
- } else {
2798
- ResultFormatter.unknown(decodeResult, data.join(","));
2881
+ };
2882
+
2883
+ // lib/plugins/Label_83.ts
2884
+ var Label_83 = class extends DecoderPlugin {
2885
+ name = "label-83";
2886
+ qualifiers() {
2887
+ return {
2888
+ labels: ["83"]
2889
+ };
2799
2890
  }
2800
- }
2801
- function parseMessageType(decodeResult, messageType) {
2802
- const parts = messageType.split("#");
2803
- if (parts.length == 1) {
2804
- const type = parts[0].substring(0, 3);
2805
- if (type === "POS" && parts[0].length !== 3) {
2806
- processPosition2(decodeResult, parts[0].substring(3).split(","));
2891
+ decode(message, options = {}) {
2892
+ const decodeResult = this.defaultResult();
2893
+ decodeResult.decoder.name = this.name;
2894
+ decodeResult.message = message;
2895
+ decodeResult.formatted.description = "Airline Defined";
2896
+ let text = message.text;
2897
+ if (text.match(/^M\d{2}A\w{6}/)) {
2898
+ ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
2899
+ text = text.substring(10);
2807
2900
  }
2808
- return processMessageType(decodeResult, type);
2809
- } else if (parts.length == 2) {
2810
- if (parts[0].length > 0) {
2811
- ResultFormatter.unknown(decodeResult, parts[0].substring(0, 3));
2812
- decodeResult.raw.flight_number = parts[0].substring(3);
2813
- ResultFormatter.unknown(decodeResult, parts[1].length == 5 ? parts[1].substring(0, 2) : parts[1].substring(0, 3), "#");
2901
+ decodeResult.decoded = true;
2902
+ if (text.substring(0, 10) === "4DH3 ETAT2") {
2903
+ const fields = text.split(/\s+/);
2904
+ if (fields[2].length > 5) {
2905
+ decodeResult.raw.day = fields[2].substring(5);
2906
+ }
2907
+ ResultFormatter.unknown(decodeResult, fields[2].substring(0, 4));
2908
+ const subfields = fields[3].split("/");
2909
+ ResultFormatter.departureAirport(decodeResult, subfields[0]);
2910
+ ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
2911
+ ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
2912
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[6] + "00"));
2913
+ } else if (text.substring(0, 5) === "001PR") {
2914
+ decodeResult.raw.day = text.substring(5, 7);
2915
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(13, 28).replace(/\./g, ""));
2916
+ if (position) {
2917
+ ResultFormatter.position(decodeResult, position);
2918
+ }
2919
+ ResultFormatter.altitude(decodeResult, Number(text.substring(28, 33)));
2920
+ ResultFormatter.unknown(decodeResult, text.substring(33));
2921
+ } else {
2922
+ const fields = text.replace(/\s/g, "").split(",");
2923
+ if (fields.length === 9) {
2924
+ ResultFormatter.departureAirport(decodeResult, fields[0]);
2925
+ ResultFormatter.arrivalAirport(decodeResult, fields[1]);
2926
+ decodeResult.raw.day = fields[2].substring(0, 2);
2927
+ decodeResult.raw.time = fields[2].substring(2);
2928
+ ResultFormatter.position(
2929
+ decodeResult,
2930
+ {
2931
+ latitude: Number(fields[3].replace(/\s/g, "")),
2932
+ longitude: Number(fields[4].replace(/\s/g, ""))
2933
+ }
2934
+ );
2935
+ ResultFormatter.altitude(decodeResult, Number(fields[5]));
2936
+ ResultFormatter.groundspeed(decodeResult, Number(fields[6]));
2937
+ ResultFormatter.heading(decodeResult, Number(fields[7]));
2938
+ ResultFormatter.unknown(decodeResult, fields[8]);
2939
+ } else {
2940
+ decodeResult.decoded = false;
2941
+ ResultFormatter.unknown(decodeResult, message.text);
2942
+ }
2814
2943
  }
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(","));
2944
+ if (decodeResult.decoded) {
2945
+ if (!decodeResult.remaining.text)
2946
+ decodeResult.decoder.decodeLevel = "full";
2947
+ else
2948
+ decodeResult.decoder.decodeLevel = "partial";
2949
+ } else {
2950
+ decodeResult.decoder.decodeLevel = "none";
2818
2951
  }
2819
- processMessageType(decodeResult, type);
2820
- } else {
2821
- ResultFormatter.unknown(decodeResult, messageType);
2952
+ return decodeResult;
2822
2953
  }
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";
2954
+ };
2955
+
2956
+ // lib/plugins/Label_8E.ts
2957
+ var Label_8E = class extends DecoderPlugin {
2958
+ name = "label-8e";
2959
+ qualifiers() {
2960
+ return {
2961
+ labels: ["8E"]
2962
+ };
2837
2963
  }
2838
- }
2839
- function processDC(decodeResult, data) {
2840
- decodeResult.raw.message_date = data[0];
2841
- if (data.length === 1) {
2842
- } else if (data.length === 2) {
2843
- const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
2844
- const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
2845
- decodeResult.raw.message_timestamp = time;
2964
+ decode(message, options = {}) {
2965
+ const decodeResult = this.defaultResult();
2966
+ decodeResult.decoder.name = this.name;
2967
+ decodeResult.formatted.description = "ETA Report";
2968
+ decodeResult.message = message;
2969
+ const regex = /^(?<arrival_icao>\w{4}),(?<arrival_eta>\d{4})$/;
2970
+ const results = message.text.match(regex);
2971
+ if (results?.groups) {
2972
+ if (options.debug) {
2973
+ console.log(`Label 8E ETA: groups`);
2974
+ console.log(results.groups);
2975
+ }
2976
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta));
2977
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
2978
+ }
2979
+ decodeResult.decoded = true;
2980
+ decodeResult.decoder.decodeLevel = "full";
2981
+ return decodeResult;
2846
2982
  }
2847
- }
2848
- function processPS(decodeResult, data) {
2849
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2850
- if (position) {
2851
- decodeResult.raw.position = position;
2852
- decodeResult.formatted.items.push({
2853
- type: "aircraft_position",
2854
- code: "POS",
2855
- label: "Aircraft Position",
2856
- value: CoordinateUtils.coordinateString(position)
2857
- });
2983
+ };
2984
+
2985
+ // lib/plugins/Label_B6.ts
2986
+ var Label_B6_Forwardslash = class extends DecoderPlugin {
2987
+ name = "label-b6-forwardslash";
2988
+ qualifiers() {
2989
+ return {
2990
+ labels: ["B6"],
2991
+ preambles: ["/"]
2992
+ };
2858
2993
  }
2859
- if (data.length === 9) {
2860
- processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
2861
- ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
2862
- ResultFormatter.temperature(decodeResult, data[6]);
2863
- ResultFormatter.unknown(decodeResult, data[7]);
2864
- ResultFormatter.unknown(decodeResult, data[8]);
2994
+ decode(message, options = {}) {
2995
+ const decodeResult = this.defaultResult();
2996
+ decodeResult.decoder.name = this.name;
2997
+ decodeResult.formatted.description = "CPDLC Message";
2998
+ decodeResult.message = message;
2999
+ if (options.debug) {
3000
+ console.log("CPDLC: " + message);
3001
+ }
3002
+ return decodeResult;
2865
3003
  }
2866
- if (data.length === 14) {
2867
- ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2868
- processRoute(decodeResult, data[4], data[2], data[6], data[5], void 0);
2869
- ResultFormatter.temperature(decodeResult, data[7]);
2870
- ResultFormatter.groundspeed(decodeResult, Number(data[10]));
2871
- ResultFormatter.unknown(decodeResult, data[1]);
2872
- ResultFormatter.unknown(decodeResult, data[8]);
2873
- ResultFormatter.unknown(decodeResult, data[9]);
2874
- ResultFormatter.unknown(decodeResult, data.slice(11).join(","));
3004
+ };
3005
+
3006
+ // lib/plugins/Label_ColonComma.ts
3007
+ var Label_ColonComma = class extends DecoderPlugin {
3008
+ name = "label-colon-comma";
3009
+ qualifiers() {
3010
+ return {
3011
+ labels: [":;"]
3012
+ };
2875
3013
  }
2876
- }
2877
- function processPosition2(decodeResult, data) {
2878
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2879
- if (position) {
2880
- decodeResult.raw.position = position;
3014
+ decode(message, options = {}) {
3015
+ const decodeResult = this.defaultResult();
3016
+ decodeResult.decoder.name = this.name;
3017
+ decodeResult.raw.frequency = Number(message.text) / 1e3;
3018
+ decodeResult.formatted.description = "Aircraft Transceiver Frequency Change";
2881
3019
  decodeResult.formatted.items.push({
2882
- type: "aircraft_position",
2883
- code: "POS",
2884
- label: "Aircraft Position",
2885
- value: CoordinateUtils.coordinateString(position)
3020
+ type: "frequency",
3021
+ label: "Frequency",
3022
+ value: `${decodeResult.raw.frequency} MHz`,
3023
+ code: "FREQ"
2886
3024
  });
3025
+ decodeResult.decoded = true;
3026
+ decodeResult.decoder.decodeLevel = "full";
3027
+ return decodeResult;
2887
3028
  }
2888
- if (data.length >= 10) {
2889
- ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2890
- processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
2891
- ResultFormatter.temperature(decodeResult, data[7]);
2892
- ResultFormatter.unknown(decodeResult, data[8]);
2893
- ResultFormatter.unknown(decodeResult, data[9]);
2894
- }
2895
- if (data.length >= 14) {
2896
- ResultFormatter.groundspeed(decodeResult, Number(data[10]));
2897
- ResultFormatter.unknown(decodeResult, data[11]);
2898
- ResultFormatter.unknown(decodeResult, data[12]);
2899
- ResultFormatter.unknown(decodeResult, data[13]);
2900
- }
2901
- }
2902
- function processRoute(decodeResult, last, time, next, eta, then, date) {
2903
- const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
2904
- const nextTime = date ? DateTimeUtils.convertDateTimeToEpoch(eta, date) : DateTimeUtils.convertHHMMSSToTod(eta);
2905
- const timeFormat = date ? "epoch" : "tod";
2906
- const lastWaypoint = RouteUtils.getWaypoint(last);
2907
- lastWaypoint.time = lastTime;
2908
- lastWaypoint.timeFormat = timeFormat;
2909
- const nextWaypoint = RouteUtils.getWaypoint(next);
2910
- nextWaypoint.time = nextTime;
2911
- nextWaypoint.timeFormat = timeFormat;
2912
- const thenWaypoint = RouteUtils.getWaypoint(then || "?");
2913
- const waypoints = [lastWaypoint, nextWaypoint, thenWaypoint];
2914
- decodeResult.raw.route = { waypoints };
2915
- decodeResult.formatted.items.push({
2916
- type: "aircraft_route",
2917
- code: "ROUTE",
2918
- label: "Aircraft Route",
2919
- value: RouteUtils.routeToString(decodeResult.raw.route)
2920
- });
2921
- }
3029
+ };
2922
3030
 
2923
3031
  // lib/plugins/Label_H1.ts
2924
3032
  var Label_H1 = class extends DecoderPlugin {
@@ -3077,9 +3185,9 @@ var Label_H1_StarPOS = class extends DecoderPlugin {
3077
3185
  decodeResult.decoder.decodeLevel = "none";
3078
3186
  return decodeResult;
3079
3187
  }
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"));
3188
+ ResultFormatter.month(decodeResult, Number(msg.substring(4, 6)));
3189
+ ResultFormatter.day(decodeResult, Number(msg.substring(6, 8)));
3190
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(msg.substring(8, 12)));
3083
3191
  ResultFormatter.position(decodeResult, {
3084
3192
  // Deg Min, no sec
3085
3193
  latitude: CoordinateUtils.getDirection(msg.substring(12, 13)) * (Number(msg.substring(13, 15)) + Number(msg.substring(15, 17)) / 60),
@@ -3306,7 +3414,7 @@ var Label_QR = class extends DecoderPlugin {
3306
3414
  decodeResult.formatted.description = "ON Report";
3307
3415
  ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3308
3416
  ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3309
- ResultFormatter.on(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3417
+ ResultFormatter.on(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12)));
3310
3418
  ResultFormatter.unknown(decodeResult, message.text.substring(12));
3311
3419
  decodeResult.decoded = true;
3312
3420
  if (!decodeResult.remaining.text)
@@ -3331,7 +3439,7 @@ var Label_QP = class extends DecoderPlugin {
3331
3439
  decodeResult.formatted.description = "OUT Report";
3332
3440
  ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3333
3441
  ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3334
- ResultFormatter.out(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3442
+ ResultFormatter.out(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12)));
3335
3443
  ResultFormatter.unknown(decodeResult, message.text.substring(12));
3336
3444
  decodeResult.decoded = true;
3337
3445
  if (!decodeResult.remaining.text)
@@ -3356,7 +3464,7 @@ var Label_QS = class extends DecoderPlugin {
3356
3464
  decodeResult.formatted.description = "IN Report";
3357
3465
  ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3358
3466
  ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3359
- ResultFormatter.in(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3467
+ ResultFormatter.in(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12)));
3360
3468
  ResultFormatter.unknown(decodeResult, message.text.substring(12));
3361
3469
  decodeResult.decoded = true;
3362
3470
  if (!decodeResult.remaining.text)
@@ -3383,7 +3491,7 @@ var Label_QQ = class extends DecoderPlugin {
3383
3491
  ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3384
3492
  ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3385
3493
  if (message.text.substring(12, 19) === "\r\n001FE") {
3386
- decodeResult.raw.day_of_month = message.text.substring(19, 21);
3494
+ decodeResult.raw.day = message.text.substring(19, 21);
3387
3495
  ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(21, 27)));
3388
3496
  let latdir = message.text.substring(27, 28);
3389
3497
  let latdeg = Number(message.text.substring(28, 30));
@@ -4257,6 +4365,7 @@ var MessageDecoder = class {
4257
4365
  this.registerPlugin(new Label_4A_DIS(this));
4258
4366
  this.registerPlugin(new Label_4A_DOOR(this));
4259
4367
  this.registerPlugin(new Label_4A_Slash_01(this));
4368
+ this.registerPlugin(new Label_4J_POS(this));
4260
4369
  this.registerPlugin(new Label_4N(this));
4261
4370
  this.registerPlugin(new Label_B6_Forwardslash(this));
4262
4371
  this.registerPlugin(new Label_H1_FLR(this));