@airframes/acars-decoder 1.8.2 → 1.8.3

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
@@ -512,6 +512,15 @@ var ResultFormatter = class {
512
512
  value: decodeResult.raw.fuel_on_board.toString()
513
513
  });
514
514
  }
515
+ static burnedFuel(decodeResult, value) {
516
+ decodeResult.raw.fuel_burned = value;
517
+ decodeResult.formatted.items.push({
518
+ type: "fuel_burned",
519
+ code: "FB",
520
+ label: "Fuel Burned",
521
+ value: decodeResult.raw.fuel_burned.toString()
522
+ });
523
+ }
515
524
  static remainingFuel(decodeResult, value) {
516
525
  decodeResult.raw.fuel_remaining = value;
517
526
  decodeResult.formatted.items.push({
@@ -687,6 +696,24 @@ var ResultFormatter = class {
687
696
  value: text
688
697
  });
689
698
  }
699
+ static mac(decodeResult, mac) {
700
+ decodeResult.raw.mac = mac;
701
+ decodeResult.formatted.items.push({
702
+ type: "mac",
703
+ code: "MAC",
704
+ label: "Mean Aerodynamic Chord",
705
+ value: `${mac} %`
706
+ });
707
+ }
708
+ static trim(decodeResult, trim) {
709
+ decodeResult.raw.trim = trim;
710
+ decodeResult.formatted.items.push({
711
+ type: "trim",
712
+ code: "TRIM",
713
+ label: "Trim",
714
+ value: `${trim} units`
715
+ });
716
+ }
690
717
  static windData(decodeResult, windData) {
691
718
  decodeResult.raw.wind_data = windData;
692
719
  for (const wind of windData) {
@@ -702,6 +729,46 @@ var ResultFormatter = class {
702
729
  });
703
730
  }
704
731
  }
732
+ static cg(decodeResult, value, type = "center") {
733
+ switch (type) {
734
+ case "center":
735
+ decodeResult.raw.center_of_gravity = value;
736
+ decodeResult.formatted.items.push({
737
+ type: "center_of_gravity",
738
+ code: "CG",
739
+ label: "Center of Gravity",
740
+ value: `${decodeResult.raw.center_of_gravity} %`
741
+ });
742
+ break;
743
+ case "lower":
744
+ decodeResult.raw.cg_lower_limit = value;
745
+ decodeResult.formatted.items.push({
746
+ type: "cg_lower_limit",
747
+ code: "CG_LOWER",
748
+ label: "Center of Gravity Lower Limit",
749
+ value: `${decodeResult.raw.cg_lower_limit} %`
750
+ });
751
+ break;
752
+ case "upper":
753
+ decodeResult.raw.cg_upper_limit = value;
754
+ decodeResult.formatted.items.push({
755
+ type: "cg_upper_limit",
756
+ code: "CG_UPPER",
757
+ label: "Center of Gravity Upper Limit",
758
+ value: `${decodeResult.raw.cg_upper_limit} %`
759
+ });
760
+ break;
761
+ }
762
+ }
763
+ static version(decodeResult, value) {
764
+ decodeResult.raw.version = value;
765
+ decodeResult.formatted.items.push({
766
+ type: "version",
767
+ code: "VERSION",
768
+ label: "Message Version",
769
+ value: `v${decodeResult.raw.version.toFixed(1)}`
770
+ });
771
+ }
705
772
  static unknown(decodeResult, value, sep = ",") {
706
773
  if (!decodeResult.remaining.text)
707
774
  decodeResult.remaining.text = value;
@@ -1535,6 +1602,14 @@ var FlightPlanUtils = class _FlightPlanUtils {
1535
1602
  label: "Route Status",
1536
1603
  value: "Route Inactive"
1537
1604
  });
1605
+ } else if (header.startsWith("RM")) {
1606
+ decodeResult.raw.route_status = "RM";
1607
+ decodeResult.formatted.items.push({
1608
+ type: "status",
1609
+ code: "ROUTE_STATUS",
1610
+ label: "Route Status",
1611
+ value: "Route Mapped"
1612
+ });
1538
1613
  } else {
1539
1614
  decodeResult.remaining.text += header;
1540
1615
  allKnownFields = false;
@@ -1610,6 +1685,11 @@ var H1Helper = class _H1Helper {
1610
1685
  static decodeH1Message(decodeResult, message) {
1611
1686
  const checksum = message.slice(-4);
1612
1687
  const data = message.slice(0, message.length - 4);
1688
+ if (calculateChecksum(data) !== checksum) {
1689
+ decodeResult.decoded = false;
1690
+ decodeResult.decoder.decodeLevel = "none";
1691
+ return false;
1692
+ }
1613
1693
  const fields = data.split("/");
1614
1694
  const canDecode = parseMessageType(decodeResult, fields[0]);
1615
1695
  if (!canDecode) {
@@ -1618,53 +1698,71 @@ var H1Helper = class _H1Helper {
1618
1698
  return false;
1619
1699
  }
1620
1700
  for (let i = 1; i < fields.length; ++i) {
1621
- if (fields[i].startsWith("FN")) {
1622
- decodeResult.raw.flight_number = fields[i].substring(2);
1623
- } else if (fields[i].startsWith("SN")) {
1624
- decodeResult.raw.serial_number = fields[i].substring(2);
1625
- } else if (fields[i].startsWith("DC")) {
1626
- processDC(decodeResult, fields[i].substring(2).split(","));
1627
- } else if (fields[i].startsWith("TS")) {
1628
- _H1Helper.processTS(decodeResult, fields[i].substring(2).split(","));
1629
- } else if (fields[i].startsWith("PS")) {
1630
- _H1Helper.processPS(decodeResult, fields[i].substring(2).split(","));
1631
- } else if (fields[i].startsWith("DT")) {
1632
- const data2 = fields[i].substring(2).split(",");
1633
- processDT(decodeResult, data2);
1634
- } else if (fields[i].startsWith("ID")) {
1635
- processIdentification(decodeResult, fields[i].substring(2).split(","));
1636
- } else if (fields[i].startsWith("LR")) {
1637
- const data2 = fields[i].substring(2).split(",");
1638
- processLR(decodeResult, data2);
1639
- } else if (fields[i].startsWith("RI") || fields[i].startsWith("RF") || fields[i].startsWith("RP")) {
1640
- FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
1641
- } else if (fields[i].startsWith("PR")) {
1642
- ResultFormatter.unknown(decodeResult, fields[i], "/");
1643
- } else if (fields[i].startsWith("AF")) {
1644
- processAirField(decodeResult, fields[i].substring(2).split(","));
1645
- } else if (fields[i].startsWith("TD")) {
1646
- processTimeOfDeparture(decodeResult, fields[i].substring(2).split(","));
1647
- } else if (fields[i].startsWith("FX")) {
1648
- ResultFormatter.freetext(decodeResult, fields[i].substring(2));
1649
- } else if (fields[i].startsWith("ET")) {
1650
- if (fields[i].length === 7) {
1651
- ResultFormatter.day(decodeResult, Number(fields[i].substring(2, 3)));
1652
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(3)));
1653
- } else if (fields[i].length === 8) {
1654
- ResultFormatter.day(decodeResult, Number(fields[i].substring(2, 4)));
1655
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(4)));
1656
- } else {
1701
+ const key = fields[i].substring(0, 2);
1702
+ const data2 = fields[i].substring(2);
1703
+ switch (key) {
1704
+ case "AF":
1705
+ processAirField(decodeResult, data2.split(","));
1706
+ break;
1707
+ case "CG":
1708
+ processCenterOfGravity(decodeResult, data2.split(","));
1709
+ break;
1710
+ case "DC":
1711
+ processDateCode(decodeResult, data2.split(","));
1712
+ break;
1713
+ case "DT":
1714
+ processDT(decodeResult, data2.split(","));
1715
+ break;
1716
+ case "ET":
1717
+ processETA(data2, decodeResult, fields, i);
1718
+ break;
1719
+ case "FB":
1720
+ ResultFormatter.currentFuel(decodeResult, parseInt(data2, 10));
1721
+ break;
1722
+ case "FN":
1723
+ decodeResult.raw.flight_number = data2;
1724
+ break;
1725
+ case "FX":
1726
+ ResultFormatter.freetext(decodeResult, data2);
1727
+ break;
1728
+ case "ID":
1729
+ processIdentification(decodeResult, data2.split(","));
1730
+ break;
1731
+ case "LR":
1732
+ processLandingReport(decodeResult, data2.split(","));
1733
+ break;
1734
+ case "PR":
1735
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
1736
+ break;
1737
+ case "PS":
1738
+ _H1Helper.processPS(decodeResult, data2.split(","));
1739
+ break;
1740
+ case "RF":
1741
+ case "RI":
1742
+ case "RM":
1743
+ case "RP":
1744
+ FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
1745
+ break;
1746
+ case "SN":
1747
+ decodeResult.raw.serial_number = data2;
1748
+ break;
1749
+ case "TD":
1750
+ processTimeOfDeparture(decodeResult, data2.split(","));
1751
+ break;
1752
+ case "TS":
1753
+ _H1Helper.processTimeStamp(decodeResult, data2.split(","));
1754
+ break;
1755
+ case "VR":
1756
+ ResultFormatter.version(decodeResult, parseInt(data2, 10) / 10);
1757
+ break;
1758
+ case "WD":
1759
+ processWindData(decodeResult, data2);
1760
+ break;
1761
+ default:
1657
1762
  ResultFormatter.unknown(decodeResult, fields[i], "/");
1658
- }
1659
- } else if (fields[i].startsWith("WD")) {
1660
- processWindData(decodeResult, fields[i].substring(2));
1661
- } else {
1662
- ResultFormatter.unknown(decodeResult, fields[i], "/");
1663
1763
  }
1664
1764
  }
1665
- if (decodeResult.formatted.items.length > 0) {
1666
- ResultFormatter.checksum(decodeResult, checksum);
1667
- }
1765
+ ResultFormatter.checksum(decodeResult, checksum);
1668
1766
  return true;
1669
1767
  }
1670
1768
  static processPS(decodeResult, data) {
@@ -1708,16 +1806,26 @@ var H1Helper = class _H1Helper {
1708
1806
  ResultFormatter.unknownArr(decodeResult, data.slice(10));
1709
1807
  }
1710
1808
  }
1711
- static processTS(decodeResult, data) {
1809
+ static processTimeStamp(decodeResult, data) {
1712
1810
  let time = DateTimeUtils.convertDateTimeToEpoch(data[0], data[1]);
1713
1811
  if (Number.isNaN(time)) {
1714
1812
  const date = data[1].substring(2, 4) + data[1].substring(0, 2) + data[1].substring(4, 6);
1715
1813
  time = DateTimeUtils.convertDateTimeToEpoch(data[0], date);
1716
1814
  }
1717
- decodeResult.raw.message_date = data[1];
1718
1815
  decodeResult.raw.message_timestamp = time;
1719
1816
  }
1720
1817
  };
1818
+ function processETA(data, decodeResult, fields, i) {
1819
+ if (data.length === 5) {
1820
+ ResultFormatter.day(decodeResult, Number(data.substring(0, 1)));
1821
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data.substring(1)));
1822
+ } else if (data.length === 6) {
1823
+ ResultFormatter.day(decodeResult, Number(data.substring(0, 2)));
1824
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data.substring(2)));
1825
+ } else {
1826
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
1827
+ }
1828
+ }
1721
1829
  function processAirField(decodeResult, data) {
1722
1830
  if (data.length === 2) {
1723
1831
  ResultFormatter.departureAirport(decodeResult, data[0]);
@@ -1777,7 +1885,7 @@ function processDT(decodeResult, data) {
1777
1885
  ResultFormatter.unknownArr(decodeResult, data);
1778
1886
  }
1779
1887
  }
1780
- function processLR(decodeResult, data) {
1888
+ function processLandingReport(decodeResult, data) {
1781
1889
  if (data.length === 19) {
1782
1890
  ResultFormatter.unknown(decodeResult, data[1]);
1783
1891
  ResultFormatter.flightNumber(decodeResult, data[2]);
@@ -1789,36 +1897,38 @@ function processLR(decodeResult, data) {
1789
1897
  ResultFormatter.unknown(decodeResult, data.join(","));
1790
1898
  }
1791
1899
  }
1792
- function parseMessageType(decodeResult, messageType) {
1793
- const parts = messageType.split("#");
1794
- if (parts.length == 1) {
1795
- if (parts[0].startsWith("POS")) {
1796
- H1Helper.processPosition(decodeResult, parts[0].substring(3).split(","));
1797
- return processMessageType(decodeResult, "POS");
1798
- } else if (parts[0].length === 13) {
1799
- if (processMessageType(decodeResult, parts[0].substring(10))) {
1800
- ResultFormatter.unknown(decodeResult, parts[0].substring(0, 4));
1801
- ResultFormatter.flightNumber(decodeResult, parts[0].slice(4, 10));
1802
- return true;
1803
- }
1804
- }
1805
- return processMessageType(decodeResult, parts[0].substring(0, 3));
1806
- } else if (parts.length == 2) {
1807
- if (parts[0].length > 0) {
1808
- ResultFormatter.unknown(decodeResult, parts[0].substring(0, 4));
1809
- ResultFormatter.flightNumber(decodeResult, parts[0].substring(4));
1810
- ResultFormatter.unknown(decodeResult, parts[1].length == 5 ? parts[1].substring(0, 2) : parts[1].substring(0, 3), "#");
1811
- }
1812
- const type = parts[1].length == 5 ? parts[1].substring(2, 5) : parts[1].substring(3, 6);
1813
- if (parts[1].substring(3, 6) === "POS" && parts[1].length > 6) {
1814
- H1Helper.processPosition(decodeResult, parts[1].substring(6).split(","));
1815
- }
1816
- return processMessageType(decodeResult, type);
1900
+ function processCenterOfGravity(decodeResult, data) {
1901
+ if (data.length === 1) {
1902
+ if (data[0] !== void 0 && data[0] !== "") {
1903
+ ResultFormatter.cg(decodeResult, parseInt(data[0], 10) / 10);
1904
+ }
1905
+ } else if (data.length === 3) {
1906
+ if (data[0] !== void 0 && data[0] !== "") {
1907
+ ResultFormatter.cg(decodeResult, parseInt(data[0], 10) / 10, "center");
1908
+ }
1909
+ if (data[1] !== void 0 && data[1] !== "") {
1910
+ ResultFormatter.cg(decodeResult, parseInt(data[1], 10) / 10, "lower");
1911
+ }
1912
+ if (data[2] !== void 0 && data[2] !== "") {
1913
+ ResultFormatter.cg(decodeResult, parseInt(data[2], 10) / 10, "upper");
1914
+ }
1817
1915
  } else {
1818
- ResultFormatter.unknown(decodeResult, messageType);
1819
- return false;
1916
+ ResultFormatter.unknown(decodeResult, data.join(","));
1820
1917
  }
1821
1918
  }
1919
+ function parseMessageType(decodeResult, messageType) {
1920
+ if (messageType.startsWith("POS")) {
1921
+ H1Helper.processPosition(decodeResult, messageType.substring(3).split(","));
1922
+ return processMessageType(decodeResult, "POS");
1923
+ } else if (messageType.length === 13) {
1924
+ if (processMessageType(decodeResult, messageType.substring(10))) {
1925
+ ResultFormatter.unknown(decodeResult, messageType.substring(0, 4));
1926
+ ResultFormatter.flightNumber(decodeResult, messageType.slice(4, 10));
1927
+ return true;
1928
+ }
1929
+ }
1930
+ return processMessageType(decodeResult, messageType.substring(0, 3));
1931
+ }
1822
1932
  function processMessageType(decodeResult, type) {
1823
1933
  if (type === "FPN") {
1824
1934
  decodeResult.formatted.description = "Flight Plan";
@@ -1826,19 +1936,21 @@ function processMessageType(decodeResult, type) {
1826
1936
  decodeResult.formatted.description = "Free Text";
1827
1937
  } else if (type === "INI") {
1828
1938
  decodeResult.formatted.description = "Flight Plan Initial Report";
1939
+ } else if (type === "PER") {
1940
+ decodeResult.formatted.description = "Performance Report";
1829
1941
  } else if (type === "POS") {
1830
1942
  decodeResult.formatted.description = "Position Report";
1831
1943
  } else if (type === "PRG") {
1832
1944
  decodeResult.formatted.description = "Progress Report";
1833
1945
  } else if (type === "PWI") {
1834
- decodeResult.formatted.description = "Weather Report";
1946
+ decodeResult.formatted.description = "Pilot Weather Information";
1835
1947
  } else {
1836
1948
  decodeResult.formatted.description = "Unknown H1 Message";
1837
1949
  return false;
1838
1950
  }
1839
1951
  return true;
1840
1952
  }
1841
- function processDC(decodeResult, data) {
1953
+ function processDateCode(decodeResult, data) {
1842
1954
  decodeResult.raw.message_date = data[0];
1843
1955
  if (data.length === 1) {
1844
1956
  } else if (data.length === 2) {
@@ -1903,6 +2015,26 @@ function processWindData(decodeResult, message) {
1903
2015
  });
1904
2016
  ResultFormatter.windData(decodeResult, wind);
1905
2017
  }
2018
+ function calculateChecksum(data) {
2019
+ let crc = 65535;
2020
+ const bytes = Buffer.from(data, "ascii");
2021
+ for (const byte of bytes) {
2022
+ crc ^= byte;
2023
+ for (let i = 0; i < 8; i++) {
2024
+ if ((crc & 1) !== 0) {
2025
+ crc = crc >>> 1 ^ 33800;
2026
+ } else {
2027
+ crc = crc >>> 1;
2028
+ }
2029
+ }
2030
+ }
2031
+ crc = (crc ^ 65535) & 65535;
2032
+ const nibble1 = crc >> 12 & 15;
2033
+ const nibble2 = crc >> 8 & 15;
2034
+ const nibble3 = crc >> 4 & 15;
2035
+ const nibble4 = crc & 15;
2036
+ return `${nibble4.toString(16)}${nibble3.toString(16)}${nibble2.toString(16)}${nibble1.toString(16)}`.toUpperCase();
2037
+ }
1906
2038
 
1907
2039
  // lib/plugins/Label_1J_2J_FTX.ts
1908
2040
  var Label_1J_2J_FTX = class extends DecoderPlugin {
@@ -1917,7 +2049,14 @@ var Label_1J_2J_FTX = class extends DecoderPlugin {
1917
2049
  decodeResult.decoder.name = this.name;
1918
2050
  decodeResult.message = message;
1919
2051
  const msg = message.text.replace(/\n|\r/g, "");
1920
- const decoded = H1Helper.decodeH1Message(decodeResult, msg);
2052
+ const parts = msg.split("/");
2053
+ let decoded = false;
2054
+ if (parts[0].length > 3) {
2055
+ decoded = H1Helper.decodeH1Message(decodeResult, msg.slice(parts[0].length - 3));
2056
+ decodeResult.remaining.text = parts[0].slice(0, 3) + "/" + decodeResult.remaining.text;
2057
+ } else {
2058
+ decoded = H1Helper.decodeH1Message(decodeResult, msg);
2059
+ }
1921
2060
  decodeResult.decoded = decoded;
1922
2061
  decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
1923
2062
  if (decodeResult.formatted.items.length === 0) {
@@ -2462,7 +2601,6 @@ var Label_2P_FM3 = class extends DecoderPlugin {
2462
2601
  ResultFormatter.unknown(decodeResult, header[0].substring(0, 4));
2463
2602
  ResultFormatter.flightNumber(decodeResult, header[0].substring(4));
2464
2603
  }
2465
- console.log(header[1]);
2466
2604
  if (header[1].length === 4) {
2467
2605
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(header[1]));
2468
2606
  } else {
@@ -2606,7 +2744,14 @@ var Label_2P_POS = class extends DecoderPlugin {
2606
2744
  decodeResult.decoder.name = this.name;
2607
2745
  decodeResult.message = message;
2608
2746
  const msg = message.text.replace(/\n|\r/g, "");
2609
- const decoded = H1Helper.decodeH1Message(decodeResult, msg);
2747
+ const parts = msg.split("/");
2748
+ let decoded = false;
2749
+ if (parts[0].length > 3) {
2750
+ decoded = H1Helper.decodeH1Message(decodeResult, msg.slice(parts[0].length - 3));
2751
+ decodeResult.remaining.text = parts[0].slice(0, 3) + "/" + decodeResult.remaining.text;
2752
+ } else {
2753
+ decoded = H1Helper.decodeH1Message(decodeResult, msg);
2754
+ }
2610
2755
  decodeResult.decoded = decoded;
2611
2756
  decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
2612
2757
  if (decodeResult.formatted.items.length === 0) {
@@ -3739,7 +3884,18 @@ var Label_H1 = class extends DecoderPlugin {
3739
3884
  decodeResult.decoder.name = this.name;
3740
3885
  decodeResult.message = message;
3741
3886
  const msg = message.text.replace(/\n|\r/g, "");
3742
- const decoded = H1Helper.decodeH1Message(decodeResult, msg);
3887
+ const parts = msg.split("#");
3888
+ let decoded = false;
3889
+ if (parts.length === 1) {
3890
+ decoded = H1Helper.decodeH1Message(decodeResult, msg);
3891
+ } else if (parts.length == 2) {
3892
+ const offset = isNaN(parseInt(parts[1][1])) ? 3 : 4;
3893
+ decoded = H1Helper.decodeH1Message(decodeResult, msg.slice(parts[0].length + offset));
3894
+ if (decoded && parts[0].length > 0) {
3895
+ ResultFormatter.flightNumber(decodeResult, parts[0].substring(4));
3896
+ decodeResult.remaining.text = parts[0].substring(0, 4) + "#" + parts[1].substring(0, offset - 1) + "/" + decodeResult.remaining.text;
3897
+ }
3898
+ }
3743
3899
  decodeResult.decoded = decoded;
3744
3900
  decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
3745
3901
  if (decodeResult.formatted.items.length === 0) {
@@ -3909,11 +4065,11 @@ var Label_H1_OHMA = class extends DecoderPlugin {
3909
4065
  const data = message.text.split("OHMA")[1];
3910
4066
  try {
3911
4067
  const compressedBuffer = import_node_buffer.Buffer.from(data, "base64");
3912
- const decompress = new zlib.Inflate({ windowBits: 15 });
4068
+ const decompress = new zlib.Inflate({});
3913
4069
  decompress.write(compressedBuffer);
3914
4070
  decompress.flush(zlib.constants.Z_SYNC_FLUSH);
3915
4071
  const result = decompress.read();
3916
- const jsonText = result.toString();
4072
+ const jsonText = result?.toString() || "";
3917
4073
  let formattedMsg;
3918
4074
  let jsonMessage;
3919
4075
  try {
@@ -3984,7 +4140,7 @@ var Label_H1_Slash = class extends DecoderPlugin {
3984
4140
  for (let i = 2; i < fields.length; i++) {
3985
4141
  const field = fields[i];
3986
4142
  if (field.startsWith("TS")) {
3987
- H1Helper.processTS(decodeResult, field.substring(2, 15).split(","));
4143
+ H1Helper.processTimeStamp(decodeResult, field.substring(2, 15).split(","));
3988
4144
  } else if (field.startsWith("PS")) {
3989
4145
  H1Helper.processPS(decodeResult, field.substring(2).split(","));
3990
4146
  } else {