@airframes/acars-decoder 1.8.2 → 1.8.4

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
@@ -140,7 +140,6 @@ var CoordinateUtils = class _CoordinateUtils {
140
140
  * @returns An object with latitude and longitude properties
141
141
  */
142
142
  static decodeStringCoordinates(stringCoords) {
143
- var results = {};
144
143
  const firstChar = stringCoords.substring(0, 1);
145
144
  let middleChar = stringCoords.substring(6, 7);
146
145
  let longitudeChars = stringCoords.substring(7, 13);
@@ -149,12 +148,12 @@ var CoordinateUtils = class _CoordinateUtils {
149
148
  longitudeChars = stringCoords.substring(8, 14);
150
149
  }
151
150
  if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
152
- results.latitude = Number(stringCoords.substring(1, 6)) / 1e3 * _CoordinateUtils.getDirection(firstChar);
153
- results.longitude = Number(longitudeChars) / 1e3 * _CoordinateUtils.getDirection(middleChar);
154
- } else {
155
- return;
151
+ return {
152
+ latitude: Number(stringCoords.substring(1, 6)) / 1e3 * _CoordinateUtils.getDirection(firstChar),
153
+ longitude: Number(longitudeChars) / 1e3 * _CoordinateUtils.getDirection(middleChar)
154
+ };
156
155
  }
157
- return results;
156
+ return void 0;
158
157
  }
159
158
  /**
160
159
  * Decode a string of coordinates into an object with latitude and longitude in degrees and decimal minutes
@@ -163,7 +162,6 @@ var CoordinateUtils = class _CoordinateUtils {
163
162
  * @returns An object with latitude and longitude properties
164
163
  */
165
164
  static decodeStringCoordinatesDecimalMinutes(stringCoords) {
166
- var results = {};
167
165
  const firstChar = stringCoords.substring(0, 1);
168
166
  let middleChar = stringCoords.substring(6, 7);
169
167
  let longitudeChars = stringCoords.substring(7, 13);
@@ -176,12 +174,12 @@ var CoordinateUtils = class _CoordinateUtils {
176
174
  const lonDeg = Math.trunc(Number(longitudeChars) / 1e3);
177
175
  const lonMin = Number(longitudeChars) % 1e3 / 10;
178
176
  if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
179
- results.latitude = (latDeg + latMin / 60) * _CoordinateUtils.getDirection(firstChar);
180
- results.longitude = (lonDeg + lonMin / 60) * _CoordinateUtils.getDirection(middleChar);
181
- } else {
182
- return;
177
+ return {
178
+ latitude: (latDeg + latMin / 60) * _CoordinateUtils.getDirection(firstChar),
179
+ longitude: (lonDeg + lonMin / 60) * _CoordinateUtils.getDirection(middleChar)
180
+ };
183
181
  }
184
- return results;
182
+ return void 0;
185
183
  }
186
184
  static coordinateString(coords) {
187
185
  const latDir = coords.latitude > 0 ? "N" : "S";
@@ -475,6 +473,15 @@ var ResultFormatter = class {
475
473
  value: decodeResult.raw.fuel_on_board.toString()
476
474
  });
477
475
  }
476
+ static burnedFuel(decodeResult, value) {
477
+ decodeResult.raw.fuel_burned = value;
478
+ decodeResult.formatted.items.push({
479
+ type: "fuel_burned",
480
+ code: "FB",
481
+ label: "Fuel Burned",
482
+ value: decodeResult.raw.fuel_burned.toString()
483
+ });
484
+ }
478
485
  static remainingFuel(decodeResult, value) {
479
486
  decodeResult.raw.fuel_remaining = value;
480
487
  decodeResult.formatted.items.push({
@@ -650,6 +657,24 @@ var ResultFormatter = class {
650
657
  value: text
651
658
  });
652
659
  }
660
+ static mac(decodeResult, mac) {
661
+ decodeResult.raw.mac = mac;
662
+ decodeResult.formatted.items.push({
663
+ type: "mac",
664
+ code: "MAC",
665
+ label: "Mean Aerodynamic Chord",
666
+ value: `${mac} %`
667
+ });
668
+ }
669
+ static trim(decodeResult, trim) {
670
+ decodeResult.raw.trim = trim;
671
+ decodeResult.formatted.items.push({
672
+ type: "trim",
673
+ code: "TRIM",
674
+ label: "Trim",
675
+ value: `${trim} units`
676
+ });
677
+ }
653
678
  static windData(decodeResult, windData) {
654
679
  decodeResult.raw.wind_data = windData;
655
680
  for (const wind of windData) {
@@ -665,6 +690,64 @@ var ResultFormatter = class {
665
690
  });
666
691
  }
667
692
  }
693
+ static cg(decodeResult, value, type = "center") {
694
+ switch (type) {
695
+ case "center":
696
+ decodeResult.raw.center_of_gravity = value;
697
+ decodeResult.formatted.items.push({
698
+ type: "center_of_gravity",
699
+ code: "CG",
700
+ label: "Center of Gravity",
701
+ value: `${decodeResult.raw.center_of_gravity} %`
702
+ });
703
+ break;
704
+ case "lower":
705
+ decodeResult.raw.cg_lower_limit = value;
706
+ decodeResult.formatted.items.push({
707
+ type: "cg_lower_limit",
708
+ code: "CG_LOWER",
709
+ label: "Center of Gravity Lower Limit",
710
+ value: `${decodeResult.raw.cg_lower_limit} %`
711
+ });
712
+ break;
713
+ case "upper":
714
+ decodeResult.raw.cg_upper_limit = value;
715
+ decodeResult.formatted.items.push({
716
+ type: "cg_upper_limit",
717
+ code: "CG_UPPER",
718
+ label: "Center of Gravity Upper Limit",
719
+ value: `${decodeResult.raw.cg_upper_limit} %`
720
+ });
721
+ break;
722
+ }
723
+ }
724
+ static version(decodeResult, value) {
725
+ decodeResult.raw.version = value;
726
+ decodeResult.formatted.items.push({
727
+ type: "version",
728
+ code: "VERSION",
729
+ label: "Message Version",
730
+ value: `v${decodeResult.raw.version.toFixed(1)}`
731
+ });
732
+ }
733
+ static label(decodeResult, value) {
734
+ decodeResult.raw.label = value;
735
+ decodeResult.formatted.items.push({
736
+ type: "label",
737
+ code: "LABEL",
738
+ label: "Message Label",
739
+ value: `${decodeResult.raw.label}`
740
+ });
741
+ }
742
+ static sublabel(decodeResult, value) {
743
+ decodeResult.raw.sublabel = value;
744
+ decodeResult.formatted.items.push({
745
+ type: "sublabel",
746
+ code: "SUBLABEL",
747
+ label: "Message Sublabel",
748
+ value: `${decodeResult.raw.sublabel}`
749
+ });
750
+ }
668
751
  static unknown(decodeResult, value, sep = ",") {
669
752
  if (!decodeResult.remaining.text)
670
753
  decodeResult.remaining.text = value;
@@ -1498,6 +1581,14 @@ var FlightPlanUtils = class _FlightPlanUtils {
1498
1581
  label: "Route Status",
1499
1582
  value: "Route Inactive"
1500
1583
  });
1584
+ } else if (header.startsWith("RM")) {
1585
+ decodeResult.raw.route_status = "RM";
1586
+ decodeResult.formatted.items.push({
1587
+ type: "status",
1588
+ code: "ROUTE_STATUS",
1589
+ label: "Route Status",
1590
+ value: "Route Mapped"
1591
+ });
1501
1592
  } else {
1502
1593
  decodeResult.remaining.text += header;
1503
1594
  allKnownFields = false;
@@ -1573,6 +1664,11 @@ var H1Helper = class _H1Helper {
1573
1664
  static decodeH1Message(decodeResult, message) {
1574
1665
  const checksum = message.slice(-4);
1575
1666
  const data = message.slice(0, message.length - 4);
1667
+ if (calculateChecksum(data) !== checksum) {
1668
+ decodeResult.decoded = false;
1669
+ decodeResult.decoder.decodeLevel = "none";
1670
+ return false;
1671
+ }
1576
1672
  const fields = data.split("/");
1577
1673
  const canDecode = parseMessageType(decodeResult, fields[0]);
1578
1674
  if (!canDecode) {
@@ -1581,53 +1677,71 @@ var H1Helper = class _H1Helper {
1581
1677
  return false;
1582
1678
  }
1583
1679
  for (let i = 1; i < fields.length; ++i) {
1584
- if (fields[i].startsWith("FN")) {
1585
- decodeResult.raw.flight_number = fields[i].substring(2);
1586
- } else if (fields[i].startsWith("SN")) {
1587
- decodeResult.raw.serial_number = fields[i].substring(2);
1588
- } else if (fields[i].startsWith("DC")) {
1589
- processDC(decodeResult, fields[i].substring(2).split(","));
1590
- } else if (fields[i].startsWith("TS")) {
1591
- _H1Helper.processTS(decodeResult, fields[i].substring(2).split(","));
1592
- } else if (fields[i].startsWith("PS")) {
1593
- _H1Helper.processPS(decodeResult, fields[i].substring(2).split(","));
1594
- } else if (fields[i].startsWith("DT")) {
1595
- const data2 = fields[i].substring(2).split(",");
1596
- processDT(decodeResult, data2);
1597
- } else if (fields[i].startsWith("ID")) {
1598
- processIdentification(decodeResult, fields[i].substring(2).split(","));
1599
- } else if (fields[i].startsWith("LR")) {
1600
- const data2 = fields[i].substring(2).split(",");
1601
- processLR(decodeResult, data2);
1602
- } else if (fields[i].startsWith("RI") || fields[i].startsWith("RF") || fields[i].startsWith("RP")) {
1603
- FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
1604
- } else if (fields[i].startsWith("PR")) {
1605
- ResultFormatter.unknown(decodeResult, fields[i], "/");
1606
- } else if (fields[i].startsWith("AF")) {
1607
- processAirField(decodeResult, fields[i].substring(2).split(","));
1608
- } else if (fields[i].startsWith("TD")) {
1609
- processTimeOfDeparture(decodeResult, fields[i].substring(2).split(","));
1610
- } else if (fields[i].startsWith("FX")) {
1611
- ResultFormatter.freetext(decodeResult, fields[i].substring(2));
1612
- } else if (fields[i].startsWith("ET")) {
1613
- if (fields[i].length === 7) {
1614
- ResultFormatter.day(decodeResult, Number(fields[i].substring(2, 3)));
1615
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(3)));
1616
- } else if (fields[i].length === 8) {
1617
- ResultFormatter.day(decodeResult, Number(fields[i].substring(2, 4)));
1618
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(4)));
1619
- } else {
1680
+ const key = fields[i].substring(0, 2);
1681
+ const data2 = fields[i].substring(2);
1682
+ switch (key) {
1683
+ case "AF":
1684
+ processAirField(decodeResult, data2.split(","));
1685
+ break;
1686
+ case "CG":
1687
+ processCenterOfGravity(decodeResult, data2.split(","));
1688
+ break;
1689
+ case "DC":
1690
+ processDateCode(decodeResult, data2.split(","));
1691
+ break;
1692
+ case "DT":
1693
+ processDT(decodeResult, data2.split(","));
1694
+ break;
1695
+ case "ET":
1696
+ processETA(data2, decodeResult, fields, i);
1697
+ break;
1698
+ case "FB":
1699
+ ResultFormatter.currentFuel(decodeResult, parseInt(data2, 10));
1700
+ break;
1701
+ case "FN":
1702
+ decodeResult.raw.flight_number = data2;
1703
+ break;
1704
+ case "FX":
1705
+ ResultFormatter.freetext(decodeResult, data2);
1706
+ break;
1707
+ case "ID":
1708
+ processIdentification(decodeResult, data2.split(","));
1709
+ break;
1710
+ case "LR":
1711
+ processLandingReport(decodeResult, data2.split(","));
1712
+ break;
1713
+ case "PR":
1714
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
1715
+ break;
1716
+ case "PS":
1717
+ _H1Helper.processPS(decodeResult, data2.split(","));
1718
+ break;
1719
+ case "RF":
1720
+ case "RI":
1721
+ case "RM":
1722
+ case "RP":
1723
+ FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
1724
+ break;
1725
+ case "SN":
1726
+ decodeResult.raw.serial_number = data2;
1727
+ break;
1728
+ case "TD":
1729
+ processTimeOfDeparture(decodeResult, data2.split(","));
1730
+ break;
1731
+ case "TS":
1732
+ _H1Helper.processTimeStamp(decodeResult, data2.split(","));
1733
+ break;
1734
+ case "VR":
1735
+ ResultFormatter.version(decodeResult, parseInt(data2, 10) / 10);
1736
+ break;
1737
+ case "WD":
1738
+ processWindData(decodeResult, data2);
1739
+ break;
1740
+ default:
1620
1741
  ResultFormatter.unknown(decodeResult, fields[i], "/");
1621
- }
1622
- } else if (fields[i].startsWith("WD")) {
1623
- processWindData(decodeResult, fields[i].substring(2));
1624
- } else {
1625
- ResultFormatter.unknown(decodeResult, fields[i], "/");
1626
1742
  }
1627
1743
  }
1628
- if (decodeResult.formatted.items.length > 0) {
1629
- ResultFormatter.checksum(decodeResult, checksum);
1630
- }
1744
+ ResultFormatter.checksum(decodeResult, checksum);
1631
1745
  return true;
1632
1746
  }
1633
1747
  static processPS(decodeResult, data) {
@@ -1671,16 +1785,26 @@ var H1Helper = class _H1Helper {
1671
1785
  ResultFormatter.unknownArr(decodeResult, data.slice(10));
1672
1786
  }
1673
1787
  }
1674
- static processTS(decodeResult, data) {
1788
+ static processTimeStamp(decodeResult, data) {
1675
1789
  let time = DateTimeUtils.convertDateTimeToEpoch(data[0], data[1]);
1676
1790
  if (Number.isNaN(time)) {
1677
1791
  const date = data[1].substring(2, 4) + data[1].substring(0, 2) + data[1].substring(4, 6);
1678
1792
  time = DateTimeUtils.convertDateTimeToEpoch(data[0], date);
1679
1793
  }
1680
- decodeResult.raw.message_date = data[1];
1681
1794
  decodeResult.raw.message_timestamp = time;
1682
1795
  }
1683
1796
  };
1797
+ function processETA(data, decodeResult, fields, i) {
1798
+ if (data.length === 5) {
1799
+ ResultFormatter.day(decodeResult, Number(data.substring(0, 1)));
1800
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data.substring(1)));
1801
+ } else if (data.length === 6) {
1802
+ ResultFormatter.day(decodeResult, Number(data.substring(0, 2)));
1803
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data.substring(2)));
1804
+ } else {
1805
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
1806
+ }
1807
+ }
1684
1808
  function processAirField(decodeResult, data) {
1685
1809
  if (data.length === 2) {
1686
1810
  ResultFormatter.departureAirport(decodeResult, data[0]);
@@ -1740,7 +1864,7 @@ function processDT(decodeResult, data) {
1740
1864
  ResultFormatter.unknownArr(decodeResult, data);
1741
1865
  }
1742
1866
  }
1743
- function processLR(decodeResult, data) {
1867
+ function processLandingReport(decodeResult, data) {
1744
1868
  if (data.length === 19) {
1745
1869
  ResultFormatter.unknown(decodeResult, data[1]);
1746
1870
  ResultFormatter.flightNumber(decodeResult, data[2]);
@@ -1752,35 +1876,37 @@ function processLR(decodeResult, data) {
1752
1876
  ResultFormatter.unknown(decodeResult, data.join(","));
1753
1877
  }
1754
1878
  }
1755
- function parseMessageType(decodeResult, messageType) {
1756
- const parts = messageType.split("#");
1757
- if (parts.length == 1) {
1758
- if (parts[0].startsWith("POS")) {
1759
- H1Helper.processPosition(decodeResult, parts[0].substring(3).split(","));
1760
- return processMessageType(decodeResult, "POS");
1761
- } else if (parts[0].length === 13) {
1762
- if (processMessageType(decodeResult, parts[0].substring(10))) {
1763
- ResultFormatter.unknown(decodeResult, parts[0].substring(0, 4));
1764
- ResultFormatter.flightNumber(decodeResult, parts[0].slice(4, 10));
1765
- return true;
1766
- }
1767
- }
1768
- return processMessageType(decodeResult, parts[0].substring(0, 3));
1769
- } else if (parts.length == 2) {
1770
- if (parts[0].length > 0) {
1771
- ResultFormatter.unknown(decodeResult, parts[0].substring(0, 4));
1772
- ResultFormatter.flightNumber(decodeResult, parts[0].substring(4));
1773
- ResultFormatter.unknown(decodeResult, parts[1].length == 5 ? parts[1].substring(0, 2) : parts[1].substring(0, 3), "#");
1774
- }
1775
- const type = parts[1].length == 5 ? parts[1].substring(2, 5) : parts[1].substring(3, 6);
1776
- if (parts[1].substring(3, 6) === "POS" && parts[1].length > 6) {
1777
- H1Helper.processPosition(decodeResult, parts[1].substring(6).split(","));
1778
- }
1779
- return processMessageType(decodeResult, type);
1879
+ function processCenterOfGravity(decodeResult, data) {
1880
+ if (data.length === 1) {
1881
+ if (data[0] !== void 0 && data[0] !== "") {
1882
+ ResultFormatter.cg(decodeResult, parseInt(data[0], 10) / 10);
1883
+ }
1884
+ } else if (data.length === 3) {
1885
+ if (data[0] !== void 0 && data[0] !== "") {
1886
+ ResultFormatter.cg(decodeResult, parseInt(data[0], 10) / 10, "center");
1887
+ }
1888
+ if (data[1] !== void 0 && data[1] !== "") {
1889
+ ResultFormatter.cg(decodeResult, parseInt(data[1], 10) / 10, "lower");
1890
+ }
1891
+ if (data[2] !== void 0 && data[2] !== "") {
1892
+ ResultFormatter.cg(decodeResult, parseInt(data[2], 10) / 10, "upper");
1893
+ }
1780
1894
  } else {
1781
- ResultFormatter.unknown(decodeResult, messageType);
1782
- return false;
1895
+ ResultFormatter.unknown(decodeResult, data.join(","));
1896
+ }
1897
+ }
1898
+ function parseMessageType(decodeResult, messageType) {
1899
+ if (messageType.startsWith("POS")) {
1900
+ H1Helper.processPosition(decodeResult, messageType.substring(3).split(","));
1901
+ return processMessageType(decodeResult, "POS");
1902
+ } else if (messageType.length === 13) {
1903
+ if (processMessageType(decodeResult, messageType.substring(10))) {
1904
+ ResultFormatter.unknown(decodeResult, messageType.substring(0, 4));
1905
+ ResultFormatter.flightNumber(decodeResult, messageType.slice(4, 10));
1906
+ return true;
1907
+ }
1783
1908
  }
1909
+ return processMessageType(decodeResult, messageType.substring(0, 3));
1784
1910
  }
1785
1911
  function processMessageType(decodeResult, type) {
1786
1912
  if (type === "FPN") {
@@ -1789,19 +1915,21 @@ function processMessageType(decodeResult, type) {
1789
1915
  decodeResult.formatted.description = "Free Text";
1790
1916
  } else if (type === "INI") {
1791
1917
  decodeResult.formatted.description = "Flight Plan Initial Report";
1918
+ } else if (type === "PER") {
1919
+ decodeResult.formatted.description = "Performance Report";
1792
1920
  } else if (type === "POS") {
1793
1921
  decodeResult.formatted.description = "Position Report";
1794
1922
  } else if (type === "PRG") {
1795
1923
  decodeResult.formatted.description = "Progress Report";
1796
1924
  } else if (type === "PWI") {
1797
- decodeResult.formatted.description = "Weather Report";
1925
+ decodeResult.formatted.description = "Pilot Weather Information";
1798
1926
  } else {
1799
1927
  decodeResult.formatted.description = "Unknown H1 Message";
1800
1928
  return false;
1801
1929
  }
1802
1930
  return true;
1803
1931
  }
1804
- function processDC(decodeResult, data) {
1932
+ function processDateCode(decodeResult, data) {
1805
1933
  decodeResult.raw.message_date = data[0];
1806
1934
  if (data.length === 1) {
1807
1935
  } else if (data.length === 2) {
@@ -1866,6 +1994,26 @@ function processWindData(decodeResult, message) {
1866
1994
  });
1867
1995
  ResultFormatter.windData(decodeResult, wind);
1868
1996
  }
1997
+ function calculateChecksum(data) {
1998
+ let crc = 65535;
1999
+ const bytes = Buffer.from(data, "ascii");
2000
+ for (const byte of bytes) {
2001
+ crc ^= byte;
2002
+ for (let i = 0; i < 8; i++) {
2003
+ if ((crc & 1) !== 0) {
2004
+ crc = crc >>> 1 ^ 33800;
2005
+ } else {
2006
+ crc = crc >>> 1;
2007
+ }
2008
+ }
2009
+ }
2010
+ crc = (crc ^ 65535) & 65535;
2011
+ const nibble1 = crc >> 12 & 15;
2012
+ const nibble2 = crc >> 8 & 15;
2013
+ const nibble3 = crc >> 4 & 15;
2014
+ const nibble4 = crc & 15;
2015
+ return `${nibble4.toString(16)}${nibble3.toString(16)}${nibble2.toString(16)}${nibble1.toString(16)}`.toUpperCase();
2016
+ }
1869
2017
 
1870
2018
  // lib/plugins/Label_1J_2J_FTX.ts
1871
2019
  var Label_1J_2J_FTX = class extends DecoderPlugin {
@@ -1880,7 +2028,14 @@ var Label_1J_2J_FTX = class extends DecoderPlugin {
1880
2028
  decodeResult.decoder.name = this.name;
1881
2029
  decodeResult.message = message;
1882
2030
  const msg = message.text.replace(/\n|\r/g, "");
1883
- const decoded = H1Helper.decodeH1Message(decodeResult, msg);
2031
+ const parts = msg.split("/");
2032
+ let decoded = false;
2033
+ if (parts[0].length > 3) {
2034
+ decoded = H1Helper.decodeH1Message(decodeResult, msg.slice(parts[0].length - 3));
2035
+ decodeResult.remaining.text = parts[0].slice(0, 3) + "/" + decodeResult.remaining.text;
2036
+ } else {
2037
+ decoded = H1Helper.decodeH1Message(decodeResult, msg);
2038
+ }
1884
2039
  decodeResult.decoded = decoded;
1885
2040
  decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
1886
2041
  if (decodeResult.formatted.items.length === 0) {
@@ -2425,7 +2580,6 @@ var Label_2P_FM3 = class extends DecoderPlugin {
2425
2580
  ResultFormatter.unknown(decodeResult, header[0].substring(0, 4));
2426
2581
  ResultFormatter.flightNumber(decodeResult, header[0].substring(4));
2427
2582
  }
2428
- console.log(header[1]);
2429
2583
  if (header[1].length === 4) {
2430
2584
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(header[1]));
2431
2585
  } else {
@@ -2569,7 +2723,14 @@ var Label_2P_POS = class extends DecoderPlugin {
2569
2723
  decodeResult.decoder.name = this.name;
2570
2724
  decodeResult.message = message;
2571
2725
  const msg = message.text.replace(/\n|\r/g, "");
2572
- const decoded = H1Helper.decodeH1Message(decodeResult, msg);
2726
+ const parts = msg.split("/");
2727
+ let decoded = false;
2728
+ if (parts[0].length > 3) {
2729
+ decoded = H1Helper.decodeH1Message(decodeResult, msg.slice(parts[0].length - 3));
2730
+ decodeResult.remaining.text = parts[0].slice(0, 3) + "/" + decodeResult.remaining.text;
2731
+ } else {
2732
+ decoded = H1Helper.decodeH1Message(decodeResult, msg);
2733
+ }
2573
2734
  decodeResult.decoded = decoded;
2574
2735
  decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
2575
2736
  if (decodeResult.formatted.items.length === 0) {
@@ -3702,7 +3863,18 @@ var Label_H1 = class extends DecoderPlugin {
3702
3863
  decodeResult.decoder.name = this.name;
3703
3864
  decodeResult.message = message;
3704
3865
  const msg = message.text.replace(/\n|\r/g, "");
3705
- const decoded = H1Helper.decodeH1Message(decodeResult, msg);
3866
+ const parts = msg.split("#");
3867
+ let decoded = false;
3868
+ if (parts.length === 1) {
3869
+ decoded = H1Helper.decodeH1Message(decodeResult, msg);
3870
+ } else if (parts.length == 2) {
3871
+ const offset = isNaN(parseInt(parts[1][1])) ? 3 : 4;
3872
+ decoded = H1Helper.decodeH1Message(decodeResult, msg.slice(parts[0].length + offset));
3873
+ if (decoded && parts[0].length > 0) {
3874
+ ResultFormatter.flightNumber(decodeResult, parts[0].substring(4));
3875
+ decodeResult.remaining.text = parts[0].substring(0, 4) + "#" + parts[1].substring(0, offset - 1) + "/" + decodeResult.remaining.text;
3876
+ }
3877
+ }
3706
3878
  decodeResult.decoded = decoded;
3707
3879
  decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
3708
3880
  if (decodeResult.formatted.items.length === 0) {
@@ -3855,7 +4027,7 @@ var Label_H1_FLR = class extends DecoderPlugin {
3855
4027
 
3856
4028
  // lib/plugins/Label_H1_OHMA.ts
3857
4029
  import * as zlib from "minizlib";
3858
- import { Buffer } from "buffer";
4030
+ import { Buffer as Buffer2 } from "buffer";
3859
4031
  var Label_H1_OHMA = class extends DecoderPlugin {
3860
4032
  name = "label-h1-ohma";
3861
4033
  qualifiers() {
@@ -3871,12 +4043,12 @@ var Label_H1_OHMA = class extends DecoderPlugin {
3871
4043
  decodeResult.message = message;
3872
4044
  const data = message.text.split("OHMA")[1];
3873
4045
  try {
3874
- const compressedBuffer = Buffer.from(data, "base64");
3875
- const decompress = new zlib.Inflate({ windowBits: 15 });
4046
+ const compressedBuffer = Buffer2.from(data, "base64");
4047
+ const decompress = new zlib.Inflate({});
3876
4048
  decompress.write(compressedBuffer);
3877
4049
  decompress.flush(zlib.constants.Z_SYNC_FLUSH);
3878
4050
  const result = decompress.read();
3879
- const jsonText = result.toString();
4051
+ const jsonText = result?.toString() || "";
3880
4052
  let formattedMsg;
3881
4053
  let jsonMessage;
3882
4054
  try {
@@ -3947,7 +4119,7 @@ var Label_H1_Slash = class extends DecoderPlugin {
3947
4119
  for (let i = 2; i < fields.length; i++) {
3948
4120
  const field = fields[i];
3949
4121
  if (field.startsWith("TS")) {
3950
- H1Helper.processTS(decodeResult, field.substring(2, 15).split(","));
4122
+ H1Helper.processTimeStamp(decodeResult, field.substring(2, 15).split(","));
3951
4123
  } else if (field.startsWith("PS")) {
3952
4124
  H1Helper.processPS(decodeResult, field.substring(2).split(","));
3953
4125
  } else {
@@ -4102,332 +4274,147 @@ var Label_HX = class extends DecoderPlugin {
4102
4274
  }
4103
4275
  };
4104
4276
 
4105
- // lib/plugins/Label_SQ.ts
4106
- var Label_SQ = class extends DecoderPlugin {
4107
- name = "label-sq";
4108
- qualifiers() {
4109
- return {
4110
- labels: ["SQ"]
4111
- };
4112
- }
4113
- decode(message, options = {}) {
4114
- const decodeResult = this.defaultResult();
4115
- decodeResult.decoder.name = this.name;
4116
- decodeResult.raw.preamble = message.text.substring(0, 4);
4117
- decodeResult.raw.version = message.text.substring(1, 2);
4118
- decodeResult.raw.network = message.text.substring(3, 4);
4119
- if (decodeResult.raw.version === "2") {
4120
- const regex = /0(\d)X(?<org>\w)(?<iata>\w\w\w)(?<icao>\w\w\w\w)(?<station>\d)(?<lat>\d+)(?<latd>[NS])(?<lng>\d+)(?<lngd>[EW])V(?<vfreq>\d+)\/.*/;
4121
- const result = message.text.match(regex);
4122
- if (result?.groups && result.length >= 8) {
4123
- decodeResult.raw.groundStation = {
4124
- number: result.groups.station,
4125
- iataCode: result.groups.iata,
4126
- icaoCode: result.groups.icao,
4127
- coordinates: {
4128
- latitude: Number(result.groups.lat) / 100 * (result.groups.latd === "S" ? -1 : 1),
4129
- longitude: Number(result.groups.lng) / 100 * (result.groups.lngd === "W" ? -1 : 1)
4130
- }
4277
+ // lib/utils/miam.ts
4278
+ import * as Base85 from "base85";
4279
+ import * as zlib2 from "minizlib";
4280
+ import { Buffer as Buffer3 } from "buffer";
4281
+ var MIAMVersion = /* @__PURE__ */ ((MIAMVersion2) => {
4282
+ MIAMVersion2[MIAMVersion2["V1"] = 1] = "V1";
4283
+ MIAMVersion2[MIAMVersion2["V2"] = 2] = "V2";
4284
+ return MIAMVersion2;
4285
+ })(MIAMVersion || {});
4286
+ var MIAMFid = /* @__PURE__ */ ((MIAMFid2) => {
4287
+ MIAMFid2["SingleTransfer"] = "T";
4288
+ MIAMFid2["FileTransferRequest"] = "F";
4289
+ MIAMFid2["FileTransferAccept"] = "K";
4290
+ MIAMFid2["FileSegment"] = "S";
4291
+ MIAMFid2["FileTransferAbort"] = "A";
4292
+ MIAMFid2["XOFFIndication"] = "Y";
4293
+ MIAMFid2["XONIndication"] = "X";
4294
+ return MIAMFid2;
4295
+ })(MIAMFid || {});
4296
+ var MIAMCorePdu = /* @__PURE__ */ ((MIAMCorePdu2) => {
4297
+ MIAMCorePdu2[MIAMCorePdu2["Data"] = 0] = "Data";
4298
+ MIAMCorePdu2[MIAMCorePdu2["Ack"] = 1] = "Ack";
4299
+ MIAMCorePdu2[MIAMCorePdu2["Aloha"] = 2] = "Aloha";
4300
+ MIAMCorePdu2[MIAMCorePdu2["AlohaReply"] = 3] = "AlohaReply";
4301
+ return MIAMCorePdu2;
4302
+ })(MIAMCorePdu || {});
4303
+ var MIAMCoreApp = /* @__PURE__ */ ((MIAMCoreApp2) => {
4304
+ MIAMCoreApp2[MIAMCoreApp2["ACARS2Char"] = 0] = "ACARS2Char";
4305
+ MIAMCoreApp2[MIAMCoreApp2["ACARS4Char"] = 1] = "ACARS4Char";
4306
+ MIAMCoreApp2[MIAMCoreApp2["ACARS6Char"] = 2] = "ACARS6Char";
4307
+ MIAMCoreApp2[MIAMCoreApp2["NonACARS6Char"] = 3] = "NonACARS6Char";
4308
+ return MIAMCoreApp2;
4309
+ })(MIAMCoreApp || {});
4310
+ var MIAMCoreV1CRCLength = 4;
4311
+ var MIAMCoreV2CRCLength = 2;
4312
+ var isMIAMVersion = (x) => Object.values(MIAMVersion).includes(x);
4313
+ var isMIAMFid = (x) => Object.values(MIAMFid).includes(x);
4314
+ var isMIAMCoreApp = (x) => Object.values(MIAMCoreApp).includes(x);
4315
+ var isMIAMCorePdu = (x) => Object.values(MIAMCorePdu).includes(x);
4316
+ var MIAMCoreUtils = class {
4317
+ static AppTypeToAppIdLenTable = {
4318
+ [1 /* V1 */]: {
4319
+ [0 /* ACARS2Char */]: 2,
4320
+ [1 /* ACARS4Char */]: 4,
4321
+ [2 /* ACARS6Char */]: 6,
4322
+ [3 /* NonACARS6Char */]: 6
4323
+ },
4324
+ [2 /* V2 */]: {
4325
+ [0 /* ACARS2Char */]: 2,
4326
+ [1 /* ACARS4Char */]: 4,
4327
+ [2 /* ACARS6Char */]: 6,
4328
+ [3 /* NonACARS6Char */]: 6
4329
+ }
4330
+ };
4331
+ static FidHandlerTable = {
4332
+ ["T" /* SingleTransfer */]: (txt) => {
4333
+ if (txt.length < 3) {
4334
+ return {
4335
+ decoded: false,
4336
+ error: "Raw MIAM message too short (" + txt.length + " < 3) "
4131
4337
  };
4132
- decodeResult.raw.vdlFrequency = Number(result.groups.vfreq) / 1e3;
4133
4338
  }
4134
- }
4135
- decodeResult.formatted.description = "Ground Station Squitter";
4136
- var formattedNetwork = "Unknown";
4137
- if (decodeResult.raw.network == "A") {
4138
- formattedNetwork = "ARINC";
4139
- } else if (decodeResult.raw.network == "S") {
4140
- formattedNetwork = "SITA";
4141
- }
4142
- decodeResult.formatted.items = [
4143
- {
4144
- type: "network",
4145
- code: "NETT",
4146
- label: "Network",
4147
- value: formattedNetwork
4148
- },
4149
- {
4150
- type: "version",
4151
- code: "VER",
4152
- label: "Version",
4153
- value: decodeResult.raw.version
4339
+ let bpad = txt[0];
4340
+ if ("0123-.".indexOf(bpad) === -1) {
4341
+ return {
4342
+ decoded: false,
4343
+ error: "Invalid body padding value: '" + bpad + "'"
4344
+ };
4154
4345
  }
4155
- ];
4156
- if (decodeResult.raw.groundStation) {
4157
- if (decodeResult.raw.groundStation.icaoCode && decodeResult.raw.groundStation.number) {
4158
- decodeResult.formatted.items.push({
4159
- type: "ground_station",
4160
- code: "GNDSTN",
4161
- label: "Ground Station",
4162
- value: `${decodeResult.raw.groundStation.icaoCode}${decodeResult.raw.groundStation.number}`
4163
- });
4346
+ if ("0123".indexOf(txt[1]) === -1) {
4347
+ return {
4348
+ decoded: false,
4349
+ error: "Invalid header padding value: '" + txt[1] + "'"
4350
+ };
4164
4351
  }
4165
- if (decodeResult.raw.groundStation.iataCode) {
4166
- decodeResult.formatted.items.push({
4167
- type: "iataCode",
4168
- code: "IATA",
4169
- label: "IATA",
4170
- value: decodeResult.raw.groundStation.iataCode
4171
- });
4352
+ const hpad = parseInt(txt[1]);
4353
+ const delimIdx = txt.indexOf("|");
4354
+ if (delimIdx === -1) {
4355
+ return {
4356
+ decoded: false,
4357
+ error: "Raw MIAM message missing header-body delimiter"
4358
+ };
4172
4359
  }
4173
- if (decodeResult.raw.groundStation.icaoCode) {
4174
- decodeResult.formatted.items.push({
4175
- type: "icaoCode",
4176
- code: "ICAO",
4177
- label: "ICAO",
4178
- value: decodeResult.raw.groundStation.icaoCode
4179
- });
4360
+ const rawHdr = txt.substring(2, delimIdx);
4361
+ if (rawHdr.length === 0) {
4362
+ return {
4363
+ decoded: false,
4364
+ error: "Empty MIAM message header"
4365
+ };
4180
4366
  }
4181
- if (decodeResult.raw.groundStation.coordinates.latitude) {
4182
- decodeResult.formatted.items.push({
4183
- type: "coordinates",
4184
- code: "COORD",
4185
- label: "Ground Station Location",
4186
- value: `${decodeResult.raw.groundStation.coordinates.latitude}, ${decodeResult.raw.groundStation.coordinates.longitude}`
4187
- });
4367
+ let hdr = Base85.decode("<~" + rawHdr + "~>", "ascii85");
4368
+ if (!hdr || hdr.length < hpad) {
4369
+ return {
4370
+ decoded: false,
4371
+ error: "Ascii85 decode failed for MIAM message header"
4372
+ };
4188
4373
  }
4189
- if (decodeResult.raw.groundStation.airport) {
4190
- decodeResult.formatted.items.push({
4191
- type: "airport",
4192
- code: "APT",
4193
- label: "Airport",
4194
- value: `${decodeResult.raw.groundStation.airport.name} (${decodeResult.raw.groundStation.airport.icao}) in ${decodeResult.raw.groundStation.airport.location}`
4195
- });
4196
- }
4197
- }
4198
- if (decodeResult.raw.vdlFrequency) {
4199
- decodeResult.formatted.items.push({
4200
- type: "vdlFrequency",
4201
- code: "VDLFRQ",
4202
- label: "VDL Frequency",
4203
- value: `${decodeResult.raw.vdlFrequency} MHz`
4204
- });
4205
- }
4206
- decodeResult.decoded = true;
4207
- decodeResult.decoder.decodeLevel = "full";
4208
- return decodeResult;
4209
- }
4210
- };
4211
-
4212
- // lib/plugins/Label_QR.ts
4213
- var Label_QR = class extends DecoderPlugin {
4214
- name = "label-qr";
4215
- qualifiers() {
4216
- return {
4217
- labels: ["QR"]
4218
- };
4219
- }
4220
- decode(message, options = {}) {
4221
- const decodeResult = this.defaultResult();
4222
- decodeResult.decoder.name = this.name;
4223
- decodeResult.formatted.description = "ON Report";
4224
- ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
4225
- ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
4226
- ResultFormatter.on(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12)));
4227
- ResultFormatter.unknown(decodeResult, message.text.substring(12));
4228
- decodeResult.decoded = true;
4229
- if (!decodeResult.remaining.text)
4230
- decodeResult.decoder.decodeLevel = "full";
4231
- else
4232
- decodeResult.decoder.decodeLevel = "partial";
4233
- return decodeResult;
4234
- }
4235
- };
4236
-
4237
- // lib/plugins/Label_QP.ts
4238
- var Label_QP = class extends DecoderPlugin {
4239
- name = "label-qp";
4240
- qualifiers() {
4241
- return {
4242
- labels: ["QP"]
4243
- };
4244
- }
4245
- decode(message, options = {}) {
4246
- const decodeResult = this.defaultResult();
4247
- decodeResult.decoder.name = this.name;
4248
- decodeResult.formatted.description = "OUT Report";
4249
- ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
4250
- ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
4251
- ResultFormatter.out(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12)));
4252
- ResultFormatter.unknown(decodeResult, message.text.substring(12));
4253
- decodeResult.decoded = true;
4254
- if (!decodeResult.remaining.text)
4255
- decodeResult.decoder.decodeLevel = "full";
4256
- else
4257
- decodeResult.decoder.decodeLevel = "partial";
4258
- return decodeResult;
4259
- }
4260
- };
4261
-
4262
- // lib/plugins/Label_QS.ts
4263
- var Label_QS = class extends DecoderPlugin {
4264
- name = "label-qs";
4265
- qualifiers() {
4266
- return {
4267
- labels: ["QS"]
4268
- };
4269
- }
4270
- decode(message, options = {}) {
4271
- const decodeResult = this.defaultResult();
4272
- decodeResult.decoder.name = this.name;
4273
- decodeResult.formatted.description = "IN Report";
4274
- ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
4275
- ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
4276
- ResultFormatter.in(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12)));
4277
- ResultFormatter.unknown(decodeResult, message.text.substring(12));
4278
- decodeResult.decoded = true;
4279
- if (!decodeResult.remaining.text)
4280
- decodeResult.decoder.decodeLevel = "full";
4281
- else
4282
- decodeResult.decoder.decodeLevel = "partial";
4283
- return decodeResult;
4284
- }
4285
- };
4286
-
4287
- // lib/plugins/Label_QQ.ts
4288
- var Label_QQ = class extends DecoderPlugin {
4289
- name = "label-qq";
4290
- qualifiers() {
4291
- return {
4292
- labels: ["QQ"]
4293
- };
4294
- }
4295
- decode(message, options = {}) {
4296
- const decodeResult = this.defaultResult();
4297
- decodeResult.decoder.name = this.name;
4298
- decodeResult.message = message;
4299
- decodeResult.formatted.description = "OFF Report";
4300
- ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
4301
- ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
4302
- if (message.text.substring(12, 19) === "\r\n001FE") {
4303
- decodeResult.raw.day = message.text.substring(19, 21);
4304
- ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(21, 27)));
4305
- let latdir = message.text.substring(27, 28);
4306
- let latdeg = Number(message.text.substring(28, 30));
4307
- let latmin = Number(message.text.substring(30, 34));
4308
- let londir = message.text.substring(34, 35);
4309
- let londeg = Number(message.text.substring(35, 38));
4310
- let lonmin = Number(message.text.substring(38, 42));
4311
- let pos = {
4312
- latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
4313
- longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
4314
- };
4315
- ResultFormatter.unknown(decodeResult, message.text.substring(42, 45));
4316
- ResultFormatter.position(decodeResult, pos);
4317
- if (decodeResult.remaining.text !== "---") {
4318
- ResultFormatter.groundspeed(decodeResult, Number(message.text.substring(45, 48)));
4319
- } else {
4320
- ResultFormatter.unknown(decodeResult, message.text.substring(45, 48));
4321
- }
4322
- ResultFormatter.unknown(decodeResult, message.text.substring(48));
4323
- } else {
4324
- ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
4325
- ResultFormatter.unknown(decodeResult, message.text.substring(12));
4326
- }
4327
- decodeResult.decoded = true;
4328
- if (!decodeResult.remaining.text)
4329
- decodeResult.decoder.decodeLevel = "full";
4330
- else
4331
- decodeResult.decoder.decodeLevel = "partial";
4332
- return decodeResult;
4333
- }
4334
- };
4335
-
4336
- // lib/utils/miam.ts
4337
- import * as Base85 from "base85";
4338
- import * as zlib2 from "minizlib";
4339
- import { Buffer as Buffer2 } from "buffer";
4340
- var MIAMCoreV1CRCLength = 4;
4341
- var MIAMCoreV2CRCLength = 2;
4342
- var MIAMCoreUtils = class {
4343
- static AppTypeToAppIdLenTable = {
4344
- 1: {
4345
- [0 /* ACARS2Char */]: 2,
4346
- [1 /* ACARS4Char */]: 4,
4347
- [2 /* ACARS6Char */]: 6,
4348
- [3 /* NonACARS6Char */]: 6
4349
- },
4350
- 2: {
4351
- [0 /* ACARS2Char */]: 2,
4352
- [1 /* ACARS4Char */]: 4,
4353
- [2 /* ACARS6Char */]: 6,
4354
- [3 /* NonACARS6Char */]: 6
4355
- }
4356
- };
4357
- static FidHandlerTable = {
4358
- ["T" /* SingleTransfer */]: (txt) => {
4359
- if (txt.length < 3) {
4360
- return {
4361
- decoded: false,
4362
- error: "Raw MIAM message too short (" + txt.length + " < 3) "
4363
- };
4364
- }
4365
- let bpad = txt[0];
4366
- if ("0123-.".indexOf(bpad) === -1) {
4367
- return {
4368
- decoded: false,
4369
- error: "Invalid body padding value: '" + bpad + "'"
4370
- };
4371
- }
4372
- if ("0123".indexOf(txt[1]) === -1) {
4373
- return {
4374
- decoded: false,
4375
- error: "Invalid header padding value: '" + txt[1] + "'"
4376
- };
4377
- }
4378
- const hpad = parseInt(txt[1]);
4379
- const delimIdx = txt.indexOf("|");
4380
- if (delimIdx === -1) {
4381
- return {
4382
- decoded: false,
4383
- error: "Raw MIAM message missing header-body delimiter"
4384
- };
4385
- }
4386
- const rawHdr = txt.substring(2, delimIdx);
4387
- if (rawHdr.length === 0) {
4388
- return {
4389
- decoded: false,
4390
- error: "Empty MIAM message header"
4391
- };
4392
- }
4393
- let hdr = Base85.decode("<~" + rawHdr + "~>", "ascii85");
4394
- if (!hdr || hdr.length < hpad) {
4395
- return {
4396
- decoded: false,
4397
- error: "Ascii85 decode failed for MIAM message header"
4398
- };
4399
- }
4400
- let body = void 0;
4401
- const rawBody = txt.substring(delimIdx + 1);
4402
- if (rawBody.length > 0) {
4403
- if ("0123".indexOf(bpad) >= 0) {
4404
- const bpadValue = parseInt(bpad);
4405
- body = Base85.decode("<~" + rawBody + "~>", "ascii85") || void 0;
4406
- if (body && body.length >= bpadValue) {
4407
- body = body.subarray(0, body.length - bpadValue);
4408
- }
4409
- } else if (bpad === "-") {
4410
- body = Buffer2.from(rawBody);
4411
- }
4374
+ let body = void 0;
4375
+ const rawBody = txt.substring(delimIdx + 1);
4376
+ if (rawBody.length > 0) {
4377
+ if ("0123".indexOf(bpad) >= 0) {
4378
+ const bpadValue = parseInt(bpad);
4379
+ body = Base85.decode("<~" + rawBody + "~>", "ascii85") || void 0;
4380
+ if (body && body.length >= bpadValue) {
4381
+ body = body.subarray(0, body.length - bpadValue);
4382
+ }
4383
+ } else if (bpad === "-") {
4384
+ body = Buffer3.from(rawBody);
4385
+ }
4412
4386
  }
4413
4387
  hdr = hdr.subarray(0, hdr.length - hpad);
4414
4388
  const version = hdr.readUInt8(0) & 15;
4415
4389
  const pduType = hdr.readUInt8(0) >> 4 & 15;
4416
- const versionPduHandler = this.VersionPduHandlerTable[version][pduType];
4417
- if (versionPduHandler === void 0) {
4390
+ if (isMIAMVersion(version) && isMIAMCorePdu(pduType)) {
4391
+ const versionPduHandler = this.VersionPduHandlerTable[version][pduType];
4392
+ return versionPduHandler(hdr, body);
4393
+ } else {
4418
4394
  return {
4419
4395
  decoded: false,
4420
4396
  error: "Invalid version and PDU type combination: v=" + version + ", pdu=" + pduType
4421
4397
  };
4422
4398
  }
4423
- return versionPduHandler(hdr, body);
4424
4399
  },
4425
- ["F" /* FileTransferRequest */]: void 0,
4426
- ["K" /* FileTransferAccept */]: void 0,
4427
- ["S" /* FileSegment */]: void 0,
4428
- ["A" /* FileTransferAbort */]: void 0,
4429
- ["Y" /* XOFFIndication */]: void 0,
4430
- ["X" /* XONIndication */]: void 0
4400
+ ["F" /* FileTransferRequest */]: () => {
4401
+ return { decoded: false, error: "File Transfer Request not implemented" };
4402
+ },
4403
+ ["K" /* FileTransferAccept */]: () => {
4404
+ return { decoded: false, error: "File Transfer Accept not implemented" };
4405
+ },
4406
+ ["S" /* FileSegment */]: () => {
4407
+ return { decoded: false, error: "File Segment not implemented" };
4408
+ },
4409
+ ["A" /* FileTransferAbort */]: () => {
4410
+ return { decoded: false, error: "File Transfer Abort not implemented" };
4411
+ },
4412
+ ["Y" /* XOFFIndication */]: () => {
4413
+ return { decoded: false, error: "XOFF Indication not implemented" };
4414
+ },
4415
+ ["X" /* XONIndication */]: () => {
4416
+ return { decoded: false, error: "XON Indication not implemented" };
4417
+ }
4431
4418
  };
4432
4419
  static arincCrc16(buf, seed) {
4433
4420
  const crctable = [
@@ -4961,14 +4948,15 @@ var MIAMCoreUtils = class {
4961
4948
  }
4962
4949
  static parse(txt) {
4963
4950
  const fidType = txt[0];
4964
- const handler = this.FidHandlerTable[fidType];
4965
- if (handler === void 0) {
4951
+ if (isMIAMFid(fidType)) {
4952
+ const handler = this.FidHandlerTable[fidType];
4953
+ return handler(txt.substring(1));
4954
+ } else {
4966
4955
  return {
4967
4956
  decoded: false,
4968
4957
  error: "Unsupported FID type: " + fidType
4969
4958
  };
4970
4959
  }
4971
- return handler(txt.substring(1));
4972
4960
  }
4973
4961
  static corePduDataHandler(version, minHdrSize, crcLen, hdr, body) {
4974
4962
  if (hdr.length < minHdrSize) {
@@ -4983,14 +4971,14 @@ var MIAMCoreUtils = class {
4983
4971
  let pduAppType = 0;
4984
4972
  let pduAppId = "";
4985
4973
  let pduCrc = 0;
4986
- let pduData = void 0;
4974
+ let pduData = null;
4987
4975
  let pduCrcIsOk = false;
4988
4976
  let pduIsComplete = true;
4989
4977
  let pduErrors = [];
4990
4978
  let tail = void 0;
4991
4979
  let msgNum = 0;
4992
4980
  let ackOptions = 0;
4993
- if (version === 1) {
4981
+ if (version === 1 /* V1 */) {
4994
4982
  pduSize = hdr.readUInt8(1) << 16 | hdr.readUInt8(2) << 8 | hdr.readUInt8(3);
4995
4983
  const msgSize = hdr.length + (body === void 0 ? 0 : body.length);
4996
4984
  if (pduSize > msgSize) {
@@ -5000,7 +4988,7 @@ var MIAMCoreUtils = class {
5000
4988
  hdr = hdr.subarray(4);
5001
4989
  tail = hdr.subarray(0, 7).toString("ascii");
5002
4990
  hdr = hdr.subarray(7);
5003
- } else if (version === 2) {
4991
+ } else if (version === 2 /* V2 */) {
5004
4992
  hdr = hdr.subarray(1);
5005
4993
  }
5006
4994
  msgNum = hdr.readUInt8(0) >> 1 & 127;
@@ -5010,9 +4998,11 @@ var MIAMCoreUtils = class {
5010
4998
  pduEncoding = hdr.readUInt8(1) >> 4 & 3;
5011
4999
  pduAppType = hdr.readUInt8(1) & 15;
5012
5000
  hdr = hdr.subarray(2);
5013
- let appIdLen = this.AppTypeToAppIdLenTable[version][pduAppType];
5014
- if (appIdLen === void 0) {
5015
- if (version === 2 && (pduAppType & 8) !== 0 && pduAppType !== 13) {
5001
+ let appIdLen;
5002
+ if (isMIAMCoreApp(pduAppType)) {
5003
+ appIdLen = this.AppTypeToAppIdLenTable[version][pduAppType];
5004
+ } else {
5005
+ if (version === 2 /* V2 */ && (pduAppType & 8) !== 0 && pduAppType !== 13) {
5016
5006
  appIdLen = (pduAppType & 7) + 1;
5017
5007
  } else {
5018
5008
  return {
@@ -5022,9 +5012,6 @@ var MIAMCoreUtils = class {
5022
5012
  }
5023
5013
  }
5024
5014
  const pduIsACARS = [
5025
- 0 /* ACARS2Char */,
5026
- 1 /* ACARS4Char */,
5027
- 2 /* ACARS6Char */,
5028
5015
  0 /* ACARS2Char */,
5029
5016
  1 /* ACARS4Char */,
5030
5017
  2 /* ACARS6Char */
@@ -5046,7 +5033,7 @@ var MIAMCoreUtils = class {
5046
5033
  if (body !== void 0 && body.length > 0) {
5047
5034
  if ([1 /* Deflate */, 1 /* Deflate */].indexOf(pduCompression) >= 0) {
5048
5035
  try {
5049
- const decompress = new zlib2.InflateRaw({ windowBits: 15 });
5036
+ const decompress = new zlib2.InflateRaw({});
5050
5037
  decompress.write(body);
5051
5038
  decompress.flush(zlib2.constants.Z_SYNC_FLUSH);
5052
5039
  pduData = decompress.read();
@@ -5058,18 +5045,18 @@ var MIAMCoreUtils = class {
5058
5045
  } else {
5059
5046
  pduErrors.push("Unsupported v" + version + " compression type: " + pduCompression);
5060
5047
  }
5061
- if (pduData !== void 0) {
5048
+ if (pduData !== null) {
5062
5049
  const crcAlgoHandlerByVersion = {
5063
- 1: (buf, seed) => {
5050
+ [1 /* V1 */]: (buf, seed) => {
5064
5051
  return ~this.arinc665Crc32(buf, seed);
5065
5052
  },
5066
- 2: this.arincCrc16
5053
+ [2 /* V2 */]: this.arincCrc16
5067
5054
  };
5068
5055
  const crcAlgoHandler = crcAlgoHandlerByVersion[version];
5069
5056
  if (crcAlgoHandler === void 0) {
5070
5057
  return {
5071
5058
  decoded: false,
5072
- errors: "No CRC handler for v" + version
5059
+ error: "No CRC handler for v" + version
5073
5060
  };
5074
5061
  }
5075
5062
  const crcCheck = crcAlgoHandler(pduData, 4294967295);
@@ -5117,25 +5104,315 @@ var MIAMCoreUtils = class {
5117
5104
  };
5118
5105
  }
5119
5106
  static VersionPduHandlerTable = {
5120
- 1: {
5107
+ [1 /* V1 */]: {
5121
5108
  [0 /* Data */]: (hdr, body) => {
5122
- return this.corePduDataHandler(1, 20, MIAMCoreV1CRCLength, hdr, body);
5109
+ return this.corePduDataHandler(1 /* V1 */, 20, MIAMCoreV1CRCLength, hdr, body);
5110
+ },
5111
+ [1 /* Ack */]: () => {
5112
+ return { decoded: false, error: "v1 Ack PDU not implemented" };
5113
+ },
5114
+ [2 /* Aloha */]: () => {
5115
+ return { decoded: false, error: "v1 Aloha PDU not implemented" };
5123
5116
  },
5124
- [1 /* Ack */]: void 0,
5125
- [2 /* Aloha */]: void 0,
5126
- [3 /* AlohaReply */]: void 0
5117
+ [3 /* AlohaReply */]: () => {
5118
+ return { decoded: false, error: "v1 AlohaReply PDU not implemented" };
5119
+ }
5127
5120
  },
5128
- 2: {
5121
+ [2 /* V2 */]: {
5129
5122
  [0 /* Data */]: (hdr, body) => {
5130
- return this.corePduDataHandler(2, 7, MIAMCoreV2CRCLength, hdr, body);
5123
+ return this.corePduDataHandler(2 /* V2 */, 7, MIAMCoreV2CRCLength, hdr, body);
5124
+ },
5125
+ [1 /* Ack */]: () => {
5126
+ return { decoded: false, error: "v2 Ack PDU not implemented" };
5127
+ },
5128
+ [2 /* Aloha */]: () => {
5129
+ return { decoded: false, error: "v2 Aloha PDU not implemented" };
5131
5130
  },
5132
- [1 /* Ack */]: void 0,
5133
- [2 /* Aloha */]: void 0,
5134
- [3 /* AlohaReply */]: void 0
5131
+ [3 /* AlohaReply */]: () => {
5132
+ return { decoded: false, error: "v2 Aloha reply PDU not implemented" };
5133
+ }
5135
5134
  }
5136
5135
  };
5137
5136
  };
5138
5137
 
5138
+ // lib/plugins/Label_MA.ts
5139
+ var Label_MA = class extends DecoderPlugin {
5140
+ name = "label-ma";
5141
+ qualifiers() {
5142
+ return {
5143
+ labels: ["MA"]
5144
+ };
5145
+ }
5146
+ decode(message, options = {}) {
5147
+ let decodeResult = this.defaultResult();
5148
+ decodeResult.decoder.name = this.name;
5149
+ decodeResult.message = message;
5150
+ const miamResult = MIAMCoreUtils.parse(message.text);
5151
+ if (miamResult.decoded && miamResult.message.data !== void 0 && miamResult.message.data.crcOk && miamResult.message.data.complete && miamResult.message.data.acars !== void 0) {
5152
+ decodeResult.decoded = true;
5153
+ decodeResult.decoder.decodeLevel = "partial";
5154
+ ResultFormatter.label(decodeResult, miamResult.message.data.acars.label);
5155
+ if (miamResult.message.data.acars.sublabel) {
5156
+ ResultFormatter.sublabel(decodeResult, miamResult.message.data.acars.sublabel);
5157
+ }
5158
+ if (miamResult.message.data.acars.tail) {
5159
+ ResultFormatter.tail(decodeResult, miamResult.message.data.acars.tail);
5160
+ }
5161
+ const messageText = miamResult.message.data.acars.text;
5162
+ if (messageText) {
5163
+ const decoded = this.decoder.decode({
5164
+ label: miamResult.message.data.acars.label,
5165
+ sublabel: miamResult.message.data.acars.sublabel,
5166
+ text: messageText
5167
+ }, options);
5168
+ if (decoded.decoded) {
5169
+ decodeResult.decoder.decodeLevel = decoded.decoder.decodeLevel;
5170
+ decodeResult.raw = { ...decodeResult.raw, ...decoded.raw };
5171
+ decodeResult.formatted.items.push(...decoded.formatted.items);
5172
+ } else {
5173
+ ResultFormatter.text(decodeResult, messageText);
5174
+ }
5175
+ message.text = messageText;
5176
+ }
5177
+ message.label = miamResult.message.data.acars.label;
5178
+ message.sublabel = miamResult.message.data.acars.sublabel;
5179
+ return decodeResult;
5180
+ }
5181
+ return decodeResult;
5182
+ }
5183
+ };
5184
+
5185
+ // lib/plugins/Label_SQ.ts
5186
+ var Label_SQ = class extends DecoderPlugin {
5187
+ name = "label-sq";
5188
+ qualifiers() {
5189
+ return {
5190
+ labels: ["SQ"]
5191
+ };
5192
+ }
5193
+ decode(message, options = {}) {
5194
+ const decodeResult = this.defaultResult();
5195
+ decodeResult.decoder.name = this.name;
5196
+ decodeResult.raw.preamble = message.text.substring(0, 4);
5197
+ decodeResult.raw.version = message.text.substring(1, 2);
5198
+ decodeResult.raw.network = message.text.substring(3, 4);
5199
+ if (decodeResult.raw.version === "2") {
5200
+ const regex = /0(\d)X(?<org>\w)(?<iata>\w\w\w)(?<icao>\w\w\w\w)(?<station>\d)(?<lat>\d+)(?<latd>[NS])(?<lng>\d+)(?<lngd>[EW])V(?<vfreq>\d+)\/.*/;
5201
+ const result = message.text.match(regex);
5202
+ if (result?.groups && result.length >= 8) {
5203
+ decodeResult.raw.groundStation = {
5204
+ number: result.groups.station,
5205
+ iataCode: result.groups.iata,
5206
+ icaoCode: result.groups.icao,
5207
+ coordinates: {
5208
+ latitude: Number(result.groups.lat) / 100 * (result.groups.latd === "S" ? -1 : 1),
5209
+ longitude: Number(result.groups.lng) / 100 * (result.groups.lngd === "W" ? -1 : 1)
5210
+ }
5211
+ };
5212
+ decodeResult.raw.vdlFrequency = Number(result.groups.vfreq) / 1e3;
5213
+ }
5214
+ }
5215
+ decodeResult.formatted.description = "Ground Station Squitter";
5216
+ var formattedNetwork = "Unknown";
5217
+ if (decodeResult.raw.network == "A") {
5218
+ formattedNetwork = "ARINC";
5219
+ } else if (decodeResult.raw.network == "S") {
5220
+ formattedNetwork = "SITA";
5221
+ }
5222
+ decodeResult.formatted.items = [
5223
+ {
5224
+ type: "network",
5225
+ code: "NETT",
5226
+ label: "Network",
5227
+ value: formattedNetwork
5228
+ },
5229
+ {
5230
+ type: "version",
5231
+ code: "VER",
5232
+ label: "Version",
5233
+ value: decodeResult.raw.version
5234
+ }
5235
+ ];
5236
+ if (decodeResult.raw.groundStation) {
5237
+ if (decodeResult.raw.groundStation.icaoCode && decodeResult.raw.groundStation.number) {
5238
+ decodeResult.formatted.items.push({
5239
+ type: "ground_station",
5240
+ code: "GNDSTN",
5241
+ label: "Ground Station",
5242
+ value: `${decodeResult.raw.groundStation.icaoCode}${decodeResult.raw.groundStation.number}`
5243
+ });
5244
+ }
5245
+ if (decodeResult.raw.groundStation.iataCode) {
5246
+ decodeResult.formatted.items.push({
5247
+ type: "iataCode",
5248
+ code: "IATA",
5249
+ label: "IATA",
5250
+ value: decodeResult.raw.groundStation.iataCode
5251
+ });
5252
+ }
5253
+ if (decodeResult.raw.groundStation.icaoCode) {
5254
+ decodeResult.formatted.items.push({
5255
+ type: "icaoCode",
5256
+ code: "ICAO",
5257
+ label: "ICAO",
5258
+ value: decodeResult.raw.groundStation.icaoCode
5259
+ });
5260
+ }
5261
+ if (decodeResult.raw.groundStation.coordinates.latitude) {
5262
+ decodeResult.formatted.items.push({
5263
+ type: "coordinates",
5264
+ code: "COORD",
5265
+ label: "Ground Station Location",
5266
+ value: `${decodeResult.raw.groundStation.coordinates.latitude}, ${decodeResult.raw.groundStation.coordinates.longitude}`
5267
+ });
5268
+ }
5269
+ if (decodeResult.raw.groundStation.airport) {
5270
+ decodeResult.formatted.items.push({
5271
+ type: "airport",
5272
+ code: "APT",
5273
+ label: "Airport",
5274
+ value: `${decodeResult.raw.groundStation.airport.name} (${decodeResult.raw.groundStation.airport.icao}) in ${decodeResult.raw.groundStation.airport.location}`
5275
+ });
5276
+ }
5277
+ }
5278
+ if (decodeResult.raw.vdlFrequency) {
5279
+ decodeResult.formatted.items.push({
5280
+ type: "vdlFrequency",
5281
+ code: "VDLFRQ",
5282
+ label: "VDL Frequency",
5283
+ value: `${decodeResult.raw.vdlFrequency} MHz`
5284
+ });
5285
+ }
5286
+ decodeResult.decoded = true;
5287
+ decodeResult.decoder.decodeLevel = "full";
5288
+ return decodeResult;
5289
+ }
5290
+ };
5291
+
5292
+ // lib/plugins/Label_QR.ts
5293
+ var Label_QR = class extends DecoderPlugin {
5294
+ name = "label-qr";
5295
+ qualifiers() {
5296
+ return {
5297
+ labels: ["QR"]
5298
+ };
5299
+ }
5300
+ decode(message, options = {}) {
5301
+ const decodeResult = this.defaultResult();
5302
+ decodeResult.decoder.name = this.name;
5303
+ decodeResult.formatted.description = "ON Report";
5304
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
5305
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
5306
+ ResultFormatter.on(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12)));
5307
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
5308
+ decodeResult.decoded = true;
5309
+ if (!decodeResult.remaining.text)
5310
+ decodeResult.decoder.decodeLevel = "full";
5311
+ else
5312
+ decodeResult.decoder.decodeLevel = "partial";
5313
+ return decodeResult;
5314
+ }
5315
+ };
5316
+
5317
+ // lib/plugins/Label_QP.ts
5318
+ var Label_QP = class extends DecoderPlugin {
5319
+ name = "label-qp";
5320
+ qualifiers() {
5321
+ return {
5322
+ labels: ["QP"]
5323
+ };
5324
+ }
5325
+ decode(message, options = {}) {
5326
+ const decodeResult = this.defaultResult();
5327
+ decodeResult.decoder.name = this.name;
5328
+ decodeResult.formatted.description = "OUT Report";
5329
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
5330
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
5331
+ ResultFormatter.out(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12)));
5332
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
5333
+ decodeResult.decoded = true;
5334
+ if (!decodeResult.remaining.text)
5335
+ decodeResult.decoder.decodeLevel = "full";
5336
+ else
5337
+ decodeResult.decoder.decodeLevel = "partial";
5338
+ return decodeResult;
5339
+ }
5340
+ };
5341
+
5342
+ // lib/plugins/Label_QS.ts
5343
+ var Label_QS = class extends DecoderPlugin {
5344
+ name = "label-qs";
5345
+ qualifiers() {
5346
+ return {
5347
+ labels: ["QS"]
5348
+ };
5349
+ }
5350
+ decode(message, options = {}) {
5351
+ const decodeResult = this.defaultResult();
5352
+ decodeResult.decoder.name = this.name;
5353
+ decodeResult.formatted.description = "IN Report";
5354
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
5355
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
5356
+ ResultFormatter.in(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12)));
5357
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
5358
+ decodeResult.decoded = true;
5359
+ if (!decodeResult.remaining.text)
5360
+ decodeResult.decoder.decodeLevel = "full";
5361
+ else
5362
+ decodeResult.decoder.decodeLevel = "partial";
5363
+ return decodeResult;
5364
+ }
5365
+ };
5366
+
5367
+ // lib/plugins/Label_QQ.ts
5368
+ var Label_QQ = class extends DecoderPlugin {
5369
+ name = "label-qq";
5370
+ qualifiers() {
5371
+ return {
5372
+ labels: ["QQ"]
5373
+ };
5374
+ }
5375
+ decode(message, options = {}) {
5376
+ const decodeResult = this.defaultResult();
5377
+ decodeResult.decoder.name = this.name;
5378
+ decodeResult.message = message;
5379
+ decodeResult.formatted.description = "OFF Report";
5380
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
5381
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
5382
+ if (message.text.substring(12, 19) === "\r\n001FE") {
5383
+ decodeResult.raw.day = message.text.substring(19, 21);
5384
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(21, 27)));
5385
+ let latdir = message.text.substring(27, 28);
5386
+ let latdeg = Number(message.text.substring(28, 30));
5387
+ let latmin = Number(message.text.substring(30, 34));
5388
+ let londir = message.text.substring(34, 35);
5389
+ let londeg = Number(message.text.substring(35, 38));
5390
+ let lonmin = Number(message.text.substring(38, 42));
5391
+ let pos = {
5392
+ latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
5393
+ longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
5394
+ };
5395
+ ResultFormatter.unknown(decodeResult, message.text.substring(42, 45));
5396
+ ResultFormatter.position(decodeResult, pos);
5397
+ if (decodeResult.remaining.text !== "---") {
5398
+ ResultFormatter.groundspeed(decodeResult, Number(message.text.substring(45, 48)));
5399
+ } else {
5400
+ ResultFormatter.unknown(decodeResult, message.text.substring(45, 48));
5401
+ }
5402
+ ResultFormatter.unknown(decodeResult, message.text.substring(48));
5403
+ } else {
5404
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
5405
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
5406
+ }
5407
+ decodeResult.decoded = true;
5408
+ if (!decodeResult.remaining.text)
5409
+ decodeResult.decoder.decodeLevel = "full";
5410
+ else
5411
+ decodeResult.decoder.decodeLevel = "partial";
5412
+ return decodeResult;
5413
+ }
5414
+ };
5415
+
5139
5416
  // lib/MessageDecoder.ts
5140
5417
  var MessageDecoder = class {
5141
5418
  name;
@@ -5203,6 +5480,7 @@ var MessageDecoder = class {
5203
5480
  this.registerPlugin(new Label_83(this));
5204
5481
  this.registerPlugin(new Label_8E(this));
5205
5482
  this.registerPlugin(new Label_1M_Slash(this));
5483
+ this.registerPlugin(new Label_MA(this));
5206
5484
  this.registerPlugin(new Label_SQ(this));
5207
5485
  this.registerPlugin(new Label_QP(this));
5208
5486
  this.registerPlugin(new Label_QQ(this));
@@ -5215,18 +5493,6 @@ var MessageDecoder = class {
5215
5493
  return true;
5216
5494
  }
5217
5495
  decode(message, options = {}) {
5218
- if (message.label === "MA") {
5219
- const decodeResult = MIAMCoreUtils.parse(message.text);
5220
- if (decodeResult.decoded && decodeResult.message.data !== void 0 && decodeResult.message.data.crcOk && decodeResult.message.data.complete && decodeResult.message.data.acars !== void 0) {
5221
- message = {
5222
- ...message,
5223
- label: decodeResult.message.data.acars.label,
5224
- ...decodeResult.message.data.acars.sublabel ? { sublabel: decodeResult.message.data.acars.sublabel } : {},
5225
- ...decodeResult.message.data.acars.mfi ? { mfi: decodeResult.message.data.acars.mfi } : {},
5226
- ...decodeResult.message.data.acars.text ? { text: decodeResult.message.data.acars.text } : {}
5227
- };
5228
- }
5229
- }
5230
5496
  const usablePlugins = this.plugins.filter((plugin) => {
5231
5497
  const qualifiers = plugin.qualifiers();
5232
5498
  if (qualifiers.labels.includes(message.label)) {
@@ -5276,11 +5542,6 @@ var MessageDecoder = class {
5276
5542
  }
5277
5543
  return result;
5278
5544
  }
5279
- lookupAirportByIata(iata) {
5280
- const airportsArray = [];
5281
- const airport = airportsArray.filter((e) => e.iata === iata);
5282
- return airport;
5283
- }
5284
5545
  };
5285
5546
  export {
5286
5547
  IcaoDecoder,