@airframes/acars-decoder 1.8.10 → 1.8.12

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
@@ -404,15 +404,6 @@ var ResultFormatter = class {
404
404
  value: `${from} -> ${to}`
405
405
  });
406
406
  }
407
- static freetext(decodeResult, value) {
408
- decodeResult.raw.freetext = value;
409
- decodeResult.formatted.items.push({
410
- type: "freetext",
411
- code: "FREE_TEXT",
412
- label: "Free Text",
413
- value
414
- });
415
- }
416
407
  static door_event(decodeResult, name, state) {
417
408
  decodeResult.raw.door_event = {
418
409
  door: name,
@@ -929,6 +920,24 @@ var ResultFormatter = class {
929
920
  value: DateTimeUtils.timestampToString(value, "epoch")
930
921
  });
931
922
  }
923
+ static sequenceNumber(decodeResult, value) {
924
+ decodeResult.raw.sequence_number = value;
925
+ decodeResult.formatted.items.push({
926
+ type: "sequence",
927
+ code: "SEQ",
928
+ label: "Sequence Number",
929
+ value: decodeResult.raw.sequence_number
930
+ });
931
+ }
932
+ static sequenceResponse(decodeResult, value) {
933
+ decodeResult.raw.sequence_response = value;
934
+ decodeResult.formatted.items.push({
935
+ type: "sequence",
936
+ code: "SEQ_RESP",
937
+ label: "Sequence Response",
938
+ value: decodeResult.raw.sequence_response
939
+ });
940
+ }
932
941
  static unknown(decodeResult, value, sep = ",") {
933
942
  if (!decodeResult.remaining.text) decodeResult.remaining.text = value;
934
943
  else decodeResult.remaining.text += sep + value;
@@ -1830,890 +1839,546 @@ var Label_16_TOD = class extends DecoderPlugin {
1830
1839
  }
1831
1840
  };
1832
1841
 
1833
- // lib/utils/flight_plan_utils.ts
1834
- var FlightPlanUtils = class _FlightPlanUtils {
1835
- /**
1836
- * Processes flight plan data
1837
- *
1838
- * Expected format is [header, key1, val1, ... keyN, valN]
1839
- *
1840
- * @param decodeResult - results
1841
- * @param data - original message split by ':'
1842
- * @returns whether all fields were processed or not
1843
- */
1844
- static processFlightPlan(decodeResult, data) {
1845
- let allKnownFields = _FlightPlanUtils.parseHeader(decodeResult, data[0]);
1846
- for (let i = 1; i < data.length; i += 2) {
1847
- const key = data[i];
1848
- const value = data[i + 1];
1849
- switch (key) {
1850
- case "A":
1851
- _FlightPlanUtils.addProcedure(decodeResult, value, "arrival");
1852
- break;
1853
- case "AA":
1854
- addArrivalAirport(decodeResult, value);
1855
- break;
1856
- case "AP":
1857
- _FlightPlanUtils.addProcedure(decodeResult, value, "approach");
1858
- break;
1859
- case "CR":
1860
- addCompanyRoute(decodeResult, value);
1861
- break;
1862
- case "D":
1863
- _FlightPlanUtils.addProcedure(decodeResult, value, "departure");
1864
- break;
1865
- case "DA":
1866
- addDepartureAirport(decodeResult, value);
1867
- break;
1868
- case "F":
1869
- addRoute(decodeResult, value);
1870
- break;
1871
- case "FP":
1872
- ResultFormatter.flightPlan(decodeResult, value.trim());
1873
- break;
1874
- case "R":
1875
- addRunway(decodeResult, value);
1876
- break;
1877
- // case 'WS': // something about routes, has altitude, so current parsing won't work
1878
- // break;
1879
- default:
1880
- if (allKnownFields) {
1881
- decodeResult.remaining.text = "";
1882
- allKnownFields = false;
1883
- }
1884
- decodeResult.remaining.text += `:${key}:${value}`;
1885
- decodeResult.decoder.decodeLevel = "partial";
1886
- }
1887
- }
1888
- return allKnownFields;
1842
+ // lib/plugins/Label_1M_Slash.ts
1843
+ var Label_1M_Slash = class extends DecoderPlugin {
1844
+ name = "label-1m-slash";
1845
+ qualifiers() {
1846
+ return {
1847
+ labels: ["1M"],
1848
+ preambles: ["/"]
1849
+ };
1889
1850
  }
1890
- static parseHeader(decodeResult, header) {
1891
- let allKnownFields = true;
1892
- if (header.startsWith("RF")) {
1893
- decodeResult.formatted.items.push({
1894
- type: "status",
1895
- code: "ROUTE_STATUS",
1896
- label: "Route Status",
1897
- value: "Route Filed"
1898
- });
1899
- decodeResult.raw.route_status = "RF";
1900
- if (header.length > 2) {
1901
- addRoute(decodeResult, header.substring(2));
1851
+ decode(message, options = {}) {
1852
+ const decodeResult = this.defaultResult();
1853
+ decodeResult.decoder.name = this.name;
1854
+ decodeResult.formatted.description = "ETA Report";
1855
+ decodeResult.message = message;
1856
+ const results = message.text.split(/\n|\//).slice(1);
1857
+ if (results) {
1858
+ if (options.debug) {
1859
+ console.log("Label 1M ETA: results");
1860
+ console.log(results);
1902
1861
  }
1903
- } else if (header.startsWith("RP")) {
1904
- decodeResult.raw.route_status = "RP";
1905
- decodeResult.formatted.items.push({
1906
- type: "status",
1907
- code: "ROUTE_STATUS",
1908
- label: "Route Status",
1909
- value: "Route Planned"
1910
- });
1911
- decodeResult.raw.route_status = header;
1912
- } else if (header.startsWith("RI")) {
1913
- decodeResult.raw.route_status = "RI";
1914
- decodeResult.formatted.items.push({
1915
- type: "status",
1916
- code: "ROUTE_STATUS",
1917
- label: "Route Status",
1918
- value: "Route Inactive"
1919
- });
1920
- } else if (header.startsWith("RM")) {
1921
- decodeResult.raw.route_status = "RM";
1922
- decodeResult.formatted.items.push({
1923
- type: "status",
1924
- code: "ROUTE_STATUS",
1925
- label: "Route Status",
1926
- value: "Route Mapped"
1927
- });
1928
- } else if (header.startsWith("RS")) {
1929
- decodeResult.raw.route_status = "RS";
1930
- decodeResult.formatted.items.push({
1931
- type: "status",
1932
- code: "ROUTE_STATUS",
1933
- label: "Route Status",
1934
- value: "Route Saved"
1935
- });
1936
- } else {
1937
- decodeResult.remaining.text += header;
1938
- allKnownFields = false;
1939
- }
1940
- return allKnownFields;
1941
- }
1942
- static addProcedure(decodeResult, value, type) {
1943
- if (decodeResult.raw.procedures === void 0) {
1944
- decodeResult.raw.procedures = [];
1945
- }
1946
- const data = value.split(".");
1947
- let waypoints;
1948
- if (data.length > 1) {
1949
- waypoints = data.slice(1).map((leg) => RouteUtils.getWaypoint(leg));
1862
+ decodeResult.raw.flight_number = results[0];
1863
+ ResultFormatter.departureAirport(decodeResult, results[3]);
1864
+ ResultFormatter.arrivalAirport(decodeResult, results[4]);
1865
+ ResultFormatter.alternateAirport(decodeResult, results[5]);
1866
+ ResultFormatter.arrivalRunway(
1867
+ decodeResult,
1868
+ results[8].replace(results[4], "")
1869
+ );
1870
+ const yymmdd = results[2];
1871
+ ResultFormatter.eta(
1872
+ decodeResult,
1873
+ DateTimeUtils.convertDateTimeToEpoch(
1874
+ results[7] + "00",
1875
+ yymmdd.substring(4, 6) + yymmdd.substring(2, 4) + yymmdd.substring(0, 2)
1876
+ ),
1877
+ "epoch"
1878
+ );
1950
1879
  }
1951
- const route = { name: data[0], waypoints };
1952
- decodeResult.raw.procedures.push({ type, route });
1953
- const procedureName = type.substring(0, 1).toUpperCase() + type.slice(1);
1954
- decodeResult.formatted.items.push({
1955
- type: "procedure",
1956
- code: "proc",
1957
- label: `${procedureName} Procedure`,
1958
- value: RouteUtils.routeToString(route)
1959
- });
1880
+ decodeResult.decoded = true;
1881
+ decodeResult.decoder.decodeLevel = "partial";
1882
+ return decodeResult;
1960
1883
  }
1961
1884
  };
1962
- function addArrivalAirport(decodeResult, value) {
1963
- ResultFormatter.arrivalAirport(decodeResult, value);
1964
- }
1965
- function addDepartureAirport(decodeResult, value) {
1966
- ResultFormatter.departureAirport(decodeResult, value);
1967
- }
1968
- function addRunway(decodeResult, value) {
1969
- if (value.length === 8) {
1970
- ResultFormatter.arrivalRunway(decodeResult, value.substring(4, 7));
1971
- }
1972
- ResultFormatter.departureRunway(decodeResult, value.substring(0, 3));
1973
- }
1974
- function addRoute(decodeResult, value) {
1975
- const route = value.split(".");
1976
- ResultFormatter.route(decodeResult, {
1977
- waypoints: route.map((leg) => RouteUtils.getWaypoint(leg))
1978
- });
1979
- }
1980
- function addCompanyRoute(decodeResult, value) {
1981
- const segments = value.split(".");
1982
- const parens_idx = segments[0].indexOf("(");
1983
- let name;
1984
- let runway;
1985
- if (parens_idx === -1) {
1986
- name = segments[0];
1987
- } else {
1988
- name = segments[0].slice(0, parens_idx);
1989
- runway = segments[0].slice(parens_idx + 1, segments[0].indexOf(")"));
1990
- }
1991
- let waypoints;
1992
- if (segments.length > 1) {
1993
- waypoints = segments.slice(1).map((leg) => RouteUtils.getWaypoint(leg));
1994
- }
1995
- decodeResult.raw.company_route = {
1996
- name,
1997
- runway,
1998
- waypoints
1999
- };
2000
- decodeResult.formatted.items.push({
2001
- type: "company_route",
2002
- code: "CR",
2003
- label: "Company Route",
2004
- value: RouteUtils.routeToString(decodeResult.raw.company_route)
2005
- });
2006
- }
2007
1885
 
2008
- // lib/utils/h1_helper.ts
2009
- var H1Helper = class _H1Helper {
2010
- static decodeH1Message(decodeResult, message) {
2011
- const checksum = parseInt(message.slice(-4), 16);
2012
- const data = message.slice(0, message.length - 4);
2013
- let checksumAlgorithmUsed = "";
2014
- if (crc16IbmSdlcRev(data) === checksum) {
2015
- checksumAlgorithmUsed = "IBM-SDLC reversed";
2016
- } else if (crc16Genibus(data) === checksum) {
2017
- checksumAlgorithmUsed = "GENIBUS";
2018
- } else {
1886
+ // lib/plugins/Label_1L_3-line.ts
1887
+ var Label_1L_3Line = class extends DecoderPlugin {
1888
+ name = "label-1l-3-line";
1889
+ qualifiers() {
1890
+ return {
1891
+ labels: ["1L"]
1892
+ };
1893
+ }
1894
+ decode(message, options = {}) {
1895
+ const decodeResult = this.defaultResult();
1896
+ decodeResult.decoder.name = this.name;
1897
+ decodeResult.formatted.description = "Position Report";
1898
+ decodeResult.message = message;
1899
+ const lines = message.text.split("\r\n");
1900
+ if (lines.length !== 3) {
1901
+ if (options.debug) {
1902
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1903
+ }
1904
+ decodeResult.remaining.text = message.text;
2019
1905
  decodeResult.decoded = false;
2020
1906
  decodeResult.decoder.decodeLevel = "none";
2021
- return false;
1907
+ return decodeResult;
2022
1908
  }
2023
- const fields = data.split("/");
2024
- const canDecode = parseMessageType(decodeResult, fields[0]);
2025
- if (!canDecode) {
2026
- decodeResult.decoded = false;
2027
- decodeResult.decoder.decodeLevel = "none";
2028
- return false;
1909
+ const parts = message.text.replaceAll("\r\n", "/").split("/");
1910
+ const data = /* @__PURE__ */ new Map();
1911
+ data.set("", parts[0]);
1912
+ for (let i = 1; i < parts.length; i++) {
1913
+ const part = parts[i].split(" ");
1914
+ data.set(part[0], part.slice(1).join(" "));
2029
1915
  }
2030
- for (let i = 1; i < fields.length; ++i) {
2031
- const key = fields[i].substring(0, 2);
2032
- const data2 = fields[i].substring(2);
2033
- switch (key) {
2034
- case "AF":
2035
- processAirField(decodeResult, data2.split(","));
2036
- break;
2037
- case "AK":
2038
- ResultFormatter.unknown(decodeResult, fields[i], "/");
2039
- break;
2040
- case "CG":
2041
- processCenterOfGravity(decodeResult, data2.split(","));
2042
- break;
2043
- case "DC":
2044
- processDateCode(decodeResult, data2.split(","));
2045
- break;
2046
- case "DI":
2047
- ResultFormatter.unknown(decodeResult, fields[i], "/");
2048
- break;
2049
- case "DT":
2050
- processDT(decodeResult, data2.split(","));
2051
- break;
2052
- case "DQ":
2053
- ResultFormatter.desiredAltitude(
2054
- decodeResult,
2055
- parseInt(data2, 10) * 100
2056
- );
2057
- break;
2058
- case "ET":
2059
- processETA(data2, decodeResult, fields, i);
2060
- break;
2061
- case "FB":
2062
- ResultFormatter.currentFuel(decodeResult, parseInt(data2, 10));
2063
- break;
2064
- case "FN":
2065
- decodeResult.raw.flight_number = data2;
2066
- break;
2067
- case "FX":
2068
- ResultFormatter.freetext(decodeResult, data2);
2069
- break;
2070
- case "GA":
2071
- ResultFormatter.groundAddress(decodeResult, data2);
2072
- break;
2073
- case "ID":
2074
- processIdentification(decodeResult, data2.split(","));
2075
- break;
2076
- case "LR":
2077
- processLandingReport(decodeResult, data2.split(","));
2078
- break;
2079
- case "PR":
2080
- ResultFormatter.unknown(decodeResult, fields[i], "/");
2081
- break;
2082
- case "PS":
2083
- _H1Helper.processPS(decodeResult, data2.split(","));
2084
- break;
2085
- case "RF":
2086
- case "RI":
2087
- case "RM":
2088
- case "RP":
2089
- case "RS":
2090
- FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
2091
- break;
2092
- case "RN":
2093
- ResultFormatter.routeNumber(decodeResult, data2);
2094
- break;
2095
- case "RW":
2096
- processRunway(decodeResult, data2.split(":"));
2097
- break;
2098
- case "SN":
2099
- decodeResult.raw.serial_number = data2;
2100
- break;
2101
- case "SP":
2102
- ResultFormatter.startPoint(decodeResult, data2);
2103
- break;
2104
- case "TD":
2105
- processTimeOfDeparture(decodeResult, data2.split(","));
2106
- break;
2107
- case "TS":
2108
- _H1Helper.processTimeStamp(decodeResult, data2.split(","));
2109
- break;
2110
- case "VR":
2111
- ResultFormatter.version(decodeResult, parseInt(data2, 10) / 10);
2112
- break;
2113
- case "WD":
2114
- processWindData(decodeResult, data2);
2115
- break;
2116
- case "WQ":
2117
- processWeatherQuery(decodeResult, data2.split(":"));
2118
- break;
2119
- default:
2120
- ResultFormatter.unknown(decodeResult, fields[i], "/");
2121
- }
2122
- }
2123
- ResultFormatter.checksumAlgorithm(decodeResult, checksumAlgorithmUsed);
2124
- ResultFormatter.checksum(decodeResult, checksum);
2125
- return true;
2126
- }
2127
- static processPS(decodeResult, data) {
2128
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
2129
- data[0]
2130
- );
2131
- if (position) {
2132
- ResultFormatter.position(decodeResult, position);
1916
+ const dep = data.get("DEP");
1917
+ if (dep) {
1918
+ ResultFormatter.departureAirport(decodeResult, dep);
1919
+ data.delete("DEP");
2133
1920
  }
2134
- if (data.length === 9) {
2135
- processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
2136
- ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
2137
- ResultFormatter.temperature(decodeResult, data[6]);
2138
- ResultFormatter.unknown(decodeResult, data[7]);
2139
- ResultFormatter.unknown(decodeResult, data[8]);
1921
+ const des = data.get("DES");
1922
+ if (des) {
1923
+ ResultFormatter.arrivalAirport(decodeResult, des);
1924
+ data.delete("DES");
2140
1925
  }
2141
- if (data.length === 14) {
2142
- ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2143
- processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
2144
- ResultFormatter.temperature(decodeResult, data[7]);
2145
- ResultFormatter.unknownArr(decodeResult, data.slice(8));
1926
+ const eta = data.get("ETA");
1927
+ if (eta) {
1928
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta));
1929
+ data.delete("ETA");
2146
1930
  }
2147
- }
2148
- static processPosition(decodeResult, data) {
2149
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
2150
- data[0]
2151
- );
2152
- if (position) {
2153
- ResultFormatter.position(decodeResult, position);
1931
+ const alt = data.get("ALT");
1932
+ if (alt) {
1933
+ ResultFormatter.altitude(decodeResult, Number(alt));
1934
+ data.delete("ALT");
2154
1935
  }
2155
- if (data.length >= 10) {
2156
- ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2157
- processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
2158
- ResultFormatter.temperature(decodeResult, data[7]);
2159
- ResultFormatter.unknown(decodeResult, data[8]);
2160
- ResultFormatter.unknown(decodeResult, data[9]);
1936
+ const fn = data.get("FN");
1937
+ if (fn) {
1938
+ ResultFormatter.flightNumber(decodeResult, fn);
1939
+ data.delete("FN");
2161
1940
  }
2162
- if (data.length >= 14) {
2163
- ResultFormatter.unknownArr(decodeResult, data.slice(10));
1941
+ const day = data.get("DAY");
1942
+ const utc = data.get("UTC");
1943
+ if (day && utc) {
1944
+ decodeResult.raw.message_timestamp = Date.parse(day + " GMT+0000") / 1e3 + DateTimeUtils.convertHHMMSSToTod(utc);
1945
+ data.delete("DAY");
1946
+ data.delete("UTC");
2164
1947
  }
2165
- }
2166
- static processTimeStamp(decodeResult, data) {
2167
- if (data.length > 2) {
2168
- const positionData = data.slice(1);
2169
- positionData[0] = positionData[0].substring(6);
2170
- this.processPosition(decodeResult, positionData);
1948
+ const lat = data.get("LAT");
1949
+ const lon = data.get("LON");
1950
+ if (lat && lon) {
1951
+ ResultFormatter.position(decodeResult, {
1952
+ latitude: CoordinateUtils.getDirection(lat[0]) * Number(lat.substring(1)),
1953
+ longitude: CoordinateUtils.getDirection(lon[0]) * Number(lon.substring(1))
1954
+ });
1955
+ data.delete("LAT");
1956
+ data.delete("LON");
2171
1957
  }
2172
- let time = DateTimeUtils.convertDateTimeToEpoch(
2173
- data[0],
2174
- data[1].substring(0, 6)
2175
- );
2176
- if (Number.isNaN(time)) {
2177
- const date = data[1].substring(2, 4) + data[1].substring(0, 2) + data[1].substring(4, 6);
2178
- time = DateTimeUtils.convertDateTimeToEpoch(data[0], date);
1958
+ let remaining = "";
1959
+ for (const [key, value] of data.entries()) {
1960
+ if (key === "") {
1961
+ remaining += value;
1962
+ } else {
1963
+ remaining += `/${key} ${value}`;
1964
+ }
2179
1965
  }
2180
- decodeResult.raw.message_timestamp = time;
1966
+ decodeResult.remaining.text = remaining;
1967
+ decodeResult.decoded = true;
1968
+ decodeResult.decoder.decodeLevel = "partial";
1969
+ return decodeResult;
2181
1970
  }
2182
1971
  };
2183
- function processETA(data, decodeResult, fields, i) {
2184
- if (data.length === 5) {
2185
- ResultFormatter.day(decodeResult, Number(data.substring(0, 1)));
2186
- ResultFormatter.eta(
1972
+
1973
+ // lib/plugins/Label_1L_070.ts
1974
+ var Label_1L_070 = class extends DecoderPlugin {
1975
+ name = "label-1l-070";
1976
+ qualifiers() {
1977
+ return {
1978
+ labels: ["1L"],
1979
+ preambles: ["000000070"]
1980
+ };
1981
+ }
1982
+ decode(message, options = {}) {
1983
+ const decodeResult = this.defaultResult();
1984
+ decodeResult.decoder.name = this.name;
1985
+ decodeResult.formatted.description = "Position Report";
1986
+ decodeResult.message = message;
1987
+ if (!message.text.startsWith("000000070")) {
1988
+ if (options.debug) {
1989
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1990
+ }
1991
+ decodeResult.remaining.text = message.text;
1992
+ decodeResult.decoded = false;
1993
+ decodeResult.decoder.decodeLevel = "none";
1994
+ return decodeResult;
1995
+ }
1996
+ const parts = message.text.substring(9).split(",");
1997
+ if (parts.length !== 7) {
1998
+ if (options.debug) {
1999
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
2000
+ }
2001
+ decodeResult.remaining.text = message.text;
2002
+ decodeResult.decoded = false;
2003
+ decodeResult.decoder.decodeLevel = "none";
2004
+ return decodeResult;
2005
+ }
2006
+ ResultFormatter.departureAirport(decodeResult, parts[0]);
2007
+ ResultFormatter.arrivalAirport(decodeResult, parts[1]);
2008
+ ResultFormatter.time_of_day(
2187
2009
  decodeResult,
2188
- DateTimeUtils.convertHHMMSSToTod(data.substring(1))
2010
+ DateTimeUtils.convertHHMMSSToTod(parts[2])
2189
2011
  );
2190
- } else if (data.length === 6) {
2191
- ResultFormatter.day(decodeResult, Number(data.substring(0, 2)));
2192
2012
  ResultFormatter.eta(
2193
2013
  decodeResult,
2194
- DateTimeUtils.convertHHMMSSToTod(data.substring(2))
2014
+ DateTimeUtils.convertHHMMSSToTod(parts[3])
2195
2015
  );
2196
- } else {
2197
- ResultFormatter.unknown(decodeResult, fields[i], "/");
2016
+ ResultFormatter.position(decodeResult, {
2017
+ latitude: CoordinateUtils.getDirection(parts[4][0]) * Number(parts[4].substring(1)),
2018
+ longitude: CoordinateUtils.getDirection(parts[5][0]) * Number(parts[5].substring(1))
2019
+ });
2020
+ decodeResult.remaining.text = parts[6];
2021
+ decodeResult.decoded = true;
2022
+ decodeResult.decoder.decodeLevel = "partial";
2023
+ return decodeResult;
2198
2024
  }
2199
- }
2200
- function processAirField(decodeResult, data) {
2201
- if (data.length === 2) {
2202
- ResultFormatter.departureAirport(decodeResult, data[0]);
2203
- ResultFormatter.arrivalAirport(decodeResult, data[1]);
2204
- } else {
2205
- ResultFormatter.unknown(decodeResult, data.join(","), "AF/");
2025
+ };
2026
+
2027
+ // lib/plugins/Label_1L_660.ts
2028
+ var Label_1L_660 = class extends DecoderPlugin {
2029
+ name = "label-1l-660";
2030
+ qualifiers() {
2031
+ return {
2032
+ labels: ["1L"],
2033
+ preambles: ["000000660"]
2034
+ };
2206
2035
  }
2207
- }
2208
- function processTimeOfDeparture(decodeResult, data) {
2209
- if (data.length === 2) {
2210
- decodeResult.raw.plannedDepartureTime = data[0];
2211
- decodeResult.formatted.items.push({
2212
- type: "ptd",
2213
- code: "ptd",
2214
- label: "Planned Departure Time",
2215
- value: `YYYY-MM-${data[0].substring(0, 2)}T${data[0].substring(2, 4)}:${data[0].substring(4)}:00Z`
2216
- });
2217
- decodeResult.raw.plannedDepartureTime = data[1];
2218
- decodeResult.formatted.items.push({
2219
- type: "etd",
2220
- code: "etd",
2221
- label: "Estimated Departure Time",
2222
- value: `${data[1].substring(0, 2)}:${data[1].substring(2)}`
2223
- });
2224
- } else {
2225
- ResultFormatter.unknown(decodeResult, data.join(","), "/TD");
2226
- }
2227
- }
2228
- function processIdentification(decodeResult, data) {
2229
- ResultFormatter.tail(decodeResult, data[0]);
2230
- if (data.length > 1) {
2231
- ResultFormatter.flightNumber(decodeResult, data[1]);
2232
- }
2233
- if (data.length > 2) {
2234
- decodeResult.raw.mission_number = data[2];
2235
- }
2236
- }
2237
- function processDT(decodeResult, data) {
2238
- if (data.length === 9) {
2239
- ResultFormatter.unknown(decodeResult, data[0]);
2240
- if (!decodeResult.raw.arrival_icao) {
2241
- ResultFormatter.arrivalAirport(decodeResult, data[1]);
2036
+ decode(message, options = {}) {
2037
+ const decodeResult = this.defaultResult();
2038
+ decodeResult.decoder.name = this.name;
2039
+ decodeResult.formatted.description = "Position Report";
2040
+ decodeResult.message = message;
2041
+ if (!message.text.startsWith("000000660")) {
2042
+ if (options.debug) {
2043
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
2044
+ }
2045
+ decodeResult.remaining.text = message.text;
2046
+ decodeResult.decoded = false;
2047
+ decodeResult.decoder.decodeLevel = "none";
2048
+ return decodeResult;
2242
2049
  }
2243
- ResultFormatter.arrivalRunway(decodeResult, data[2]);
2244
- ResultFormatter.currentFuel(decodeResult, parseInt(data[3], 10));
2245
- ResultFormatter.eta(
2246
- decodeResult,
2247
- DateTimeUtils.convertHHMMSSToTod(data[4])
2248
- );
2249
- ResultFormatter.unknown(decodeResult, data[5]);
2250
- ResultFormatter.position(
2251
- decodeResult,
2252
- CoordinateUtils.decodeStringCoordinates(data[6])
2050
+ const parts = message.text.substring(9).split(",");
2051
+ if (parts.length !== 5) {
2052
+ if (options.debug) {
2053
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
2054
+ }
2055
+ decodeResult.remaining.text = message.text;
2056
+ decodeResult.decoded = false;
2057
+ decodeResult.decoder.decodeLevel = "none";
2058
+ return decodeResult;
2059
+ }
2060
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
2061
+ parts[0]
2253
2062
  );
2254
- ResultFormatter.unknown(decodeResult, data[7]);
2255
- ResultFormatter.unknown(decodeResult, data[8]);
2256
- return;
2257
- }
2258
- if (data.length === 4 || data.length === 5) {
2259
- if (!decodeResult.raw.arrival_icao) {
2260
- ResultFormatter.arrivalAirport(decodeResult, data[0]);
2063
+ if (position) {
2064
+ ResultFormatter.position(decodeResult, position);
2261
2065
  }
2262
- ResultFormatter.arrivalRunway(decodeResult, data[1]);
2263
- ResultFormatter.currentFuel(decodeResult, parseInt(data[2], 10));
2264
- ResultFormatter.eta(
2066
+ const hhmmss = parts[1].substring(0, 6);
2067
+ ResultFormatter.time_of_day(
2265
2068
  decodeResult,
2266
- DateTimeUtils.convertHHMMSSToTod(data[3])
2069
+ DateTimeUtils.convertHHMMSSToTod(hhmmss)
2267
2070
  );
2268
- if (data.length > 4) {
2269
- ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
2270
- }
2271
- return;
2071
+ const fl = parts[1].substring(6, 9);
2072
+ ResultFormatter.altitude(decodeResult, Number(fl) * 100);
2073
+ const next = parts[1].substring(9);
2074
+ ResultFormatter.route(decodeResult, { waypoints: [{ name: next.trim() }] });
2075
+ decodeResult.remaining.text = parts.slice(2).join(",");
2076
+ decodeResult.decoded = true;
2077
+ decodeResult.decoder.decodeLevel = "partial";
2078
+ return decodeResult;
2272
2079
  }
2273
- ResultFormatter.unknownArr(decodeResult, data, ",");
2274
- }
2275
- function processLandingReport(decodeResult, data) {
2276
- if (data.length === 19) {
2277
- ResultFormatter.unknown(decodeResult, data[1]);
2278
- ResultFormatter.flightNumber(decodeResult, data[2]);
2279
- ResultFormatter.departureAirport(decodeResult, data[3]);
2280
- ResultFormatter.arrivalAirport(decodeResult, data[4]);
2281
- ResultFormatter.arrivalRunway(decodeResult, data[5]);
2282
- ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
2283
- } else {
2284
- ResultFormatter.unknown(decodeResult, data.join(","));
2080
+ };
2081
+
2082
+ // lib/plugins/Label_1L_Slash.ts
2083
+ var Label_1L_Slash = class extends DecoderPlugin {
2084
+ name = "label-1l-1-line";
2085
+ qualifiers() {
2086
+ return {
2087
+ labels: ["1L"],
2088
+ preambles: ["+", "-"]
2089
+ };
2285
2090
  }
2286
- }
2287
- function processCenterOfGravity(decodeResult, data) {
2288
- if (data.length === 1) {
2289
- if (data[0] !== void 0 && data[0] !== "") {
2290
- ResultFormatter.cg(decodeResult, parseInt(data[0], 10) / 10);
2091
+ decode(message, options = {}) {
2092
+ const decodeResult = this.defaultResult();
2093
+ decodeResult.decoder.name = this.name;
2094
+ decodeResult.formatted.description = "Position Report";
2095
+ decodeResult.message = message;
2096
+ const parts = message.text.split("/");
2097
+ if (parts.length !== 7) {
2098
+ if (options.debug) {
2099
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
2100
+ }
2101
+ decodeResult.remaining.text = message.text;
2102
+ decodeResult.decoded = false;
2103
+ decodeResult.decoder.decodeLevel = "none";
2104
+ return decodeResult;
2291
2105
  }
2292
- } else if (data.length === 3) {
2293
- if (data[0] !== void 0 && data[0] !== "") {
2294
- ResultFormatter.cg(decodeResult, parseInt(data[0], 10) / 10, "center");
2106
+ const data = /* @__PURE__ */ new Map();
2107
+ data.set("LAT", parts[0].replaceAll(" ", ""));
2108
+ data.set("LON", parts[1].replaceAll(" ", ""));
2109
+ for (let i = 2; i < parts.length; i++) {
2110
+ const part = parts[i].split(" ");
2111
+ data.set(part[0], part.slice(1).join(" "));
2295
2112
  }
2296
- if (data[1] !== void 0 && data[1] !== "") {
2297
- ResultFormatter.cg(decodeResult, parseInt(data[1], 10) / 10, "lower");
2113
+ const position = {
2114
+ latitude: Number(data.get("LAT")),
2115
+ longitude: Number(data.get("LON"))
2116
+ };
2117
+ data.delete("LAT");
2118
+ data.delete("LON");
2119
+ ResultFormatter.position(decodeResult, position);
2120
+ const utc = data.get("UTC");
2121
+ if (utc) {
2122
+ ResultFormatter.time_of_day(
2123
+ decodeResult,
2124
+ DateTimeUtils.convertHHMMSSToTod(utc)
2125
+ );
2126
+ data.delete("UTC");
2298
2127
  }
2299
- if (data[2] !== void 0 && data[2] !== "") {
2300
- ResultFormatter.cg(decodeResult, parseInt(data[2], 10) / 10, "upper");
2128
+ const alt = data.get("ALT");
2129
+ if (alt) {
2130
+ ResultFormatter.altitude(decodeResult, Number(alt));
2131
+ data.delete("ALT");
2301
2132
  }
2302
- } else {
2303
- ResultFormatter.unknown(decodeResult, data.join(","));
2133
+ const fob = data.get("FOB");
2134
+ if (fob) {
2135
+ ResultFormatter.currentFuel(decodeResult, Number(fob));
2136
+ data.delete("FOB");
2137
+ }
2138
+ const eta = data.get("ETA");
2139
+ if (eta) {
2140
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta));
2141
+ data.delete("ETA");
2142
+ }
2143
+ let remaining = "";
2144
+ for (const [key, value] of data.entries()) {
2145
+ remaining += `/${key} ${value}`;
2146
+ }
2147
+ decodeResult.remaining.text = remaining;
2148
+ decodeResult.decoded = true;
2149
+ decodeResult.decoder.decodeLevel = "partial";
2150
+ return decodeResult;
2304
2151
  }
2305
- }
2306
- function parseMessageType(decodeResult, messagePart) {
2307
- const messageParts = messagePart.split(",");
2308
- const messageType = messageParts[0];
2309
- if (messageType.startsWith("POS")) {
2310
- H1Helper.processPosition(decodeResult, messagePart.substring(3).split(","));
2311
- return processMessageType(decodeResult, "POS");
2312
- } else if (messageType.length === 6) {
2313
- const part1 = processMessageType(decodeResult, messageType.substring(0, 3));
2314
- const description = decodeResult.formatted.description;
2315
- const part2 = processMessageType(decodeResult, messageType.substring(3, 6));
2316
- decodeResult.formatted.description = description + " for " + decodeResult.formatted.description;
2317
- if (messageParts.length > 1) {
2318
- ResultFormatter.unknown(
2152
+ };
2153
+
2154
+ // lib/plugins/Label_20_POS.ts
2155
+ var Label_20_POS = class extends DecoderPlugin {
2156
+ name = "label-20-pos";
2157
+ qualifiers() {
2158
+ return {
2159
+ labels: ["20"],
2160
+ preambles: ["POS"]
2161
+ };
2162
+ }
2163
+ decode(message, options = {}) {
2164
+ const decodeResult = this.defaultResult();
2165
+ decodeResult.decoder.name = this.name;
2166
+ decodeResult.formatted.description = "Position Report";
2167
+ decodeResult.message = message;
2168
+ decodeResult.raw.preamble = message.text.substring(0, 3);
2169
+ const content = message.text.substring(3);
2170
+ const fields = content.split(",");
2171
+ if (fields.length == 11) {
2172
+ if (options.debug) {
2173
+ console.log(`DEBUG: ${this.name}: Variation 1 detected`);
2174
+ }
2175
+ const rawCoords = fields[0];
2176
+ ResultFormatter.position(
2319
2177
  decodeResult,
2320
- messageParts.slice(1).join(","),
2321
- "/"
2178
+ CoordinateUtils.decodeStringCoordinates(rawCoords)
2322
2179
  );
2180
+ decodeResult.decoded = true;
2181
+ decodeResult.decoder.decodeLevel = "full";
2182
+ } else if (fields.length == 5) {
2183
+ if (options.debug) {
2184
+ console.log(`DEBUG: ${this.name}: Variation 2 detected`);
2185
+ }
2186
+ const position = CoordinateUtils.decodeStringCoordinates(fields[0]);
2187
+ if (position) {
2188
+ ResultFormatter.position(decodeResult, position);
2189
+ }
2190
+ decodeResult.decoded = true;
2191
+ decodeResult.decoder.decodeLevel = "full";
2192
+ } else {
2193
+ if (options.debug) {
2194
+ console.log(
2195
+ `DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`
2196
+ );
2197
+ }
2198
+ decodeResult.decoded = false;
2199
+ decodeResult.decoder.decodeLevel = "none";
2323
2200
  }
2324
- return part1 && part2;
2325
- }
2326
- if (messageParts.length > 1) {
2327
- ResultFormatter.unknown(decodeResult, messageParts.slice(1).join(","), "/");
2201
+ return decodeResult;
2328
2202
  }
2329
- return processMessageType(decodeResult, messageType);
2330
- }
2331
- function processMessageType(decodeResult, type) {
2332
- if (type === "FPN") {
2333
- decodeResult.formatted.description = "Flight Plan";
2334
- } else if (type === "FTX") {
2335
- decodeResult.formatted.description = "Free Text";
2336
- } else if (type === "INI") {
2337
- decodeResult.formatted.description = "Initial Report";
2338
- } else if (type === "INR") {
2339
- decodeResult.formatted.description = "In-Range Report";
2340
- } else if (type === "LDI") {
2341
- decodeResult.formatted.description = "Load Distribution Information";
2342
- } else if (type === "PER") {
2343
- decodeResult.formatted.description = "Performance Report";
2344
- } else if (type === "POS") {
2345
- decodeResult.formatted.description = "Position Report";
2346
- } else if (type === "PRG") {
2347
- decodeResult.formatted.description = "Progress Report";
2348
- } else if (type === "PWI") {
2349
- decodeResult.formatted.description = "Pilot Weather Information";
2350
- } else if (type === "WXR") {
2351
- decodeResult.formatted.description = "Weather Report";
2352
- } else if (type === "REJ") {
2353
- decodeResult.formatted.description = "Reject";
2354
- } else if (type === "REQ") {
2355
- decodeResult.formatted.description = "Request";
2356
- } else if (type === "RES") {
2357
- decodeResult.formatted.description = "Response";
2358
- } else {
2359
- decodeResult.formatted.description = "Unknown H1 Message";
2360
- return false;
2361
- }
2362
- return true;
2363
- }
2364
- function processDateCode(decodeResult, data) {
2365
- if (data.length === 1) {
2366
- } else if (data.length === 2) {
2367
- const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
2368
- const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
2369
- decodeResult.raw.message_timestamp = time;
2370
- }
2371
- }
2372
- function processWeatherQuery(decodeResult, data) {
2373
- if (data.length !== 2) {
2374
- ResultFormatter.unknown(decodeResult, data.join(":"), "WQ/");
2375
- return;
2376
- }
2377
- const alts = data[0].split(".");
2378
- const route = data[1].split(".");
2379
- ResultFormatter.requestedAltitudes(
2380
- decodeResult,
2381
- alts.map((a) => parseInt(a, 10) * 100)
2382
- );
2383
- const waypoints = route.map((wp) => {
2384
- return { name: wp };
2385
- });
2386
- ResultFormatter.route(decodeResult, { waypoints });
2387
- }
2388
- function processRoute(decodeResult, last, time, next, eta, then, date) {
2389
- const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
2390
- const nextTime = date ? DateTimeUtils.convertDateTimeToEpoch(eta, date) : DateTimeUtils.convertHHMMSSToTod(eta);
2391
- const timeFormat = date ? "epoch" : "tod";
2392
- const lastWaypoint = RouteUtils.getWaypoint(last);
2393
- lastWaypoint.time = lastTime;
2394
- lastWaypoint.timeFormat = timeFormat;
2395
- const nextWaypoint = RouteUtils.getWaypoint(next);
2396
- nextWaypoint.time = nextTime;
2397
- nextWaypoint.timeFormat = timeFormat;
2398
- const thenWaypoint = RouteUtils.getWaypoint(then || "?");
2399
- const waypoints = [lastWaypoint, nextWaypoint, thenWaypoint];
2400
- ResultFormatter.route(decodeResult, { waypoints });
2401
- }
2402
- function processWindData(decodeResult, message) {
2403
- const wind = [];
2404
- const flightLevel = Number(message.slice(0, 3));
2405
- const fields = message.slice(4).split(".");
2406
- fields.forEach((field) => {
2407
- if (field.length < 4) {
2408
- return;
2409
- }
2410
- const data = field.split(",");
2411
- const waypoint = { name: data[0] };
2412
- const windData = data[1];
2413
- const windDirection = parseInt(windData.slice(0, 3), 10);
2414
- const windSpeed = parseInt(windData.slice(3), 10);
2415
- if (data.length === 3) {
2416
- const tempData = data[2];
2417
- const tempFlightLevel = Number(tempData.slice(0, 3));
2418
- const tempString = tempData.slice(3);
2419
- const tempDegrees = Number(tempString.substring(1)) * (tempString.charAt(0) === "M" ? -1 : 1);
2420
- wind.push({
2421
- waypoint,
2422
- flightLevel,
2423
- windDirection,
2424
- windSpeed,
2425
- temperature: {
2426
- flightLevel: tempFlightLevel,
2427
- degreesC: tempDegrees
2428
- }
2429
- });
2430
- } else {
2431
- wind.push({
2432
- waypoint,
2433
- flightLevel,
2434
- windDirection,
2435
- windSpeed
2436
- });
2437
- }
2438
- });
2439
- ResultFormatter.windData(decodeResult, wind);
2440
- }
2441
- function processRunway(decodeResult, data) {
2442
- const parts = data[0].split(".");
2443
- const more = parts[0].split(",");
2444
- ResultFormatter.departureRunway(decodeResult, more[0]);
2445
- ResultFormatter.unknownArr(decodeResult, more.slice(1), ",");
2446
- ResultFormatter.unknownArr(decodeResult, parts.slice(1), ".");
2447
- ResultFormatter.departureAirport(decodeResult, data[1].split(",")[0]);
2448
- ResultFormatter.unknownArr(decodeResult, data[1].split(",").slice(1), ",");
2449
- }
2450
- function crc16IbmSdlcRev(data) {
2451
- let crc = 65535;
2452
- const bytes = Buffer.from(data, "ascii");
2453
- for (const byte of bytes) {
2454
- crc ^= byte;
2455
- for (let i = 0; i < 8; i++) {
2456
- if ((crc & 1) !== 0) {
2457
- crc = crc >>> 1 ^ 33800;
2458
- } else {
2459
- crc = crc >>> 1;
2460
- }
2461
- }
2462
- }
2463
- crc = (crc ^ 65535) & 65535;
2464
- const nibble1 = crc >> 12 & 15;
2465
- const nibble2 = crc >> 8 & 15;
2466
- const nibble3 = crc >> 4 & 15;
2467
- const nibble4 = crc & 15;
2468
- return nibble4 << 12 | nibble3 << 8 | nibble2 << 4 | nibble1;
2469
- }
2470
- function crc16Genibus(data) {
2471
- let crc = 65535;
2472
- const polynomial = 4129;
2473
- const bytes = Buffer.from(data, "ascii");
2474
- for (const byte of bytes) {
2475
- crc ^= byte << 8;
2476
- for (let i = 0; i < 8; i++) {
2477
- if ((crc & 32768) !== 0) {
2478
- crc = (crc << 1 ^ polynomial) & 65535;
2479
- } else {
2480
- crc = crc << 1 & 65535;
2481
- }
2482
- }
2483
- }
2484
- return (crc ^ 65535) & 65535;
2485
- }
2203
+ };
2486
2204
 
2487
- // lib/plugins/Label_1J_2J_FTX.ts
2488
- var Label_1J_2J_FTX = class extends DecoderPlugin {
2489
- name = "label-1j-2j-ftx";
2205
+ // lib/plugins/Label_21_POS.ts
2206
+ var Label_21_POS = class extends DecoderPlugin {
2207
+ name = "label-21-pos";
2490
2208
  qualifiers() {
2491
2209
  return {
2492
- labels: ["1J", "2J"]
2210
+ labels: ["21"],
2211
+ preambles: ["POS"]
2493
2212
  };
2494
2213
  }
2495
2214
  decode(message, options = {}) {
2496
- let decodeResult = this.defaultResult();
2215
+ const decodeResult = this.defaultResult();
2497
2216
  decodeResult.decoder.name = this.name;
2217
+ decodeResult.formatted.description = "Position Report";
2498
2218
  decodeResult.message = message;
2499
- const msg = message.text.replace(/\n|\r/g, "");
2500
- const parts = msg.split("/");
2501
- let decoded = false;
2502
- if (parts[0].length > 3) {
2503
- decoded = H1Helper.decodeH1Message(
2219
+ decodeResult.raw.preamble = message.text.substring(0, 3);
2220
+ const content = message.text.substring(3);
2221
+ const fields = content.split(",");
2222
+ if (fields.length == 9) {
2223
+ processPosition(decodeResult, fields[0].trim());
2224
+ ResultFormatter.time_of_day(
2225
+ decodeResult,
2226
+ DateTimeUtils.convertHHMMSSToTod(fields[2])
2227
+ );
2228
+ ResultFormatter.altitude(decodeResult, Number(fields[3]));
2229
+ ResultFormatter.temperature(decodeResult, fields[6].replace(/ /g, ""));
2230
+ ResultFormatter.eta(
2504
2231
  decodeResult,
2505
- msg.slice(parts[0].length - 3)
2232
+ DateTimeUtils.convertHHMMSSToTod(fields[7])
2506
2233
  );
2507
- decodeResult.remaining.text = parts[0].slice(0, 3) + "/" + decodeResult.remaining.text;
2234
+ ResultFormatter.arrivalAirport(decodeResult, fields[8]);
2235
+ ResultFormatter.unknownArr(decodeResult, [
2236
+ fields[1],
2237
+ fields[4],
2238
+ fields[5]
2239
+ ]);
2240
+ decodeResult.decoded = true;
2241
+ decodeResult.decoder.decodeLevel = "partial";
2508
2242
  } else {
2509
- decoded = H1Helper.decodeH1Message(decodeResult, msg);
2510
- }
2511
- decodeResult.decoded = decoded;
2512
- decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
2513
- if (decodeResult.formatted.items.length === 0) {
2514
2243
  if (options.debug) {
2515
- console.log(`Decoder: Unknown 1J/2J message: ${message.text}`);
2244
+ console.log(
2245
+ `DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`
2246
+ );
2516
2247
  }
2517
- ResultFormatter.unknown(decodeResult, message.text);
2518
2248
  decodeResult.decoded = false;
2519
2249
  decodeResult.decoder.decodeLevel = "none";
2520
2250
  }
2521
2251
  return decodeResult;
2522
2252
  }
2523
2253
  };
2254
+ function processPosition(decodeResult, value) {
2255
+ if (value.length !== 16 && value[0] !== "N" && value[0] !== "S" && value[8] !== "W" && value[8] !== "E") {
2256
+ return;
2257
+ }
2258
+ const latDir = value[0] === "N" ? 1 : -1;
2259
+ const lonDir = value[8] === "E" ? 1 : -1;
2260
+ const position = {
2261
+ latitude: latDir * Number(value.substring(1, 7)),
2262
+ longitude: lonDir * Number(value.substring(9, 15))
2263
+ };
2264
+ ResultFormatter.position(decodeResult, position);
2265
+ }
2524
2266
 
2525
- // lib/plugins/Label_1M_Slash.ts
2526
- var Label_1M_Slash = class extends DecoderPlugin {
2527
- name = "label-1m-slash";
2267
+ // lib/plugins/Label_22_OFF.ts
2268
+ var Label_22_OFF = class extends DecoderPlugin {
2269
+ name = "label-22-off";
2528
2270
  qualifiers() {
2529
2271
  return {
2530
- labels: ["1M"],
2531
- preambles: ["/"]
2272
+ labels: ["22"],
2273
+ preambles: ["OFF"]
2532
2274
  };
2533
2275
  }
2534
2276
  decode(message, options = {}) {
2535
2277
  const decodeResult = this.defaultResult();
2536
2278
  decodeResult.decoder.name = this.name;
2537
- decodeResult.formatted.description = "ETA Report";
2279
+ decodeResult.formatted.description = "Takeoff Report";
2538
2280
  decodeResult.message = message;
2539
- const results = message.text.split(/\n|\//).slice(1);
2540
- if (results) {
2541
- if (options.debug) {
2542
- console.log("Label 1M ETA: results");
2543
- console.log(results);
2281
+ if (message.text.startsWith("OFF01")) {
2282
+ const fields = message.text.substring(5).split("/");
2283
+ if (fields.length != 2) {
2284
+ decodeResult.decoded = false;
2285
+ decodeResult.decoder.decodeLevel = "none";
2286
+ return decodeResult;
2544
2287
  }
2545
- decodeResult.raw.flight_number = results[0];
2546
- ResultFormatter.departureAirport(decodeResult, results[3]);
2547
- ResultFormatter.arrivalAirport(decodeResult, results[4]);
2548
- ResultFormatter.alternateAirport(decodeResult, results[5]);
2549
- ResultFormatter.arrivalRunway(
2288
+ ResultFormatter.flightNumber(decodeResult, fields[0]);
2289
+ ResultFormatter.departureDay(
2550
2290
  decodeResult,
2551
- results[8].replace(results[4], "")
2291
+ Number(fields[1].substring(0, 2))
2552
2292
  );
2553
- const yymmdd = results[2];
2554
- ResultFormatter.eta(
2293
+ ResultFormatter.arrivalDay(
2555
2294
  decodeResult,
2556
- DateTimeUtils.convertDateTimeToEpoch(
2557
- results[7] + "00",
2558
- yymmdd.substring(4, 6) + yymmdd.substring(2, 4) + yymmdd.substring(0, 2)
2559
- ),
2560
- "epoch"
2295
+ Number(fields[1].substring(2, 4))
2561
2296
  );
2562
- }
2563
- decodeResult.decoded = true;
2564
- decodeResult.decoder.decodeLevel = "partial";
2565
- return decodeResult;
2566
- }
2567
- };
2568
-
2569
- // lib/plugins/Label_1L_3-line.ts
2570
- var Label_1L_3Line = class extends DecoderPlugin {
2571
- name = "label-1l-3-line";
2572
- qualifiers() {
2573
- return {
2574
- labels: ["1L"]
2575
- };
2576
- }
2577
- decode(message, options = {}) {
2578
- const decodeResult = this.defaultResult();
2579
- decodeResult.decoder.name = this.name;
2580
- decodeResult.formatted.description = "Position Report";
2581
- decodeResult.message = message;
2582
- const lines = message.text.split("\r\n");
2583
- if (lines.length !== 3) {
2584
- if (options.debug) {
2585
- console.log(`Decoder: Unknown 1L message: ${message.text}`);
2297
+ ResultFormatter.time_of_day(
2298
+ decodeResult,
2299
+ DateTimeUtils.convertHHMMSSToTod(fields[1].substring(4, 8))
2300
+ );
2301
+ ResultFormatter.departureAirport(
2302
+ decodeResult,
2303
+ fields[1].substring(8, 12)
2304
+ );
2305
+ ResultFormatter.arrivalAirport(decodeResult, fields[1].substring(12, 16));
2306
+ ResultFormatter.off(
2307
+ decodeResult,
2308
+ DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 22))
2309
+ );
2310
+ ResultFormatter.unknown(decodeResult, fields[1].substring(22));
2311
+ decodeResult.decoded = true;
2312
+ decodeResult.decoder.decodeLevel = "partial";
2313
+ } else if (message.text.startsWith("OFF02\r\n")) {
2314
+ const fields = message.text.substring(7).split(",");
2315
+ if (fields.length != 4) {
2316
+ decodeResult.decoded = false;
2317
+ decodeResult.decoder.decodeLevel = "none";
2318
+ return decodeResult;
2586
2319
  }
2587
- decodeResult.remaining.text = message.text;
2588
- decodeResult.decoded = false;
2589
- decodeResult.decoder.decodeLevel = "none";
2590
- return decodeResult;
2591
- }
2592
- const parts = message.text.replaceAll("\r\n", "/").split("/");
2593
- const data = /* @__PURE__ */ new Map();
2594
- data.set("", parts[0]);
2595
- for (let i = 1; i < parts.length; i++) {
2596
- const part = parts[i].split(" ");
2597
- data.set(part[0], part.slice(1).join(" "));
2598
- }
2599
- const dep = data.get("DEP");
2600
- if (dep) {
2601
- ResultFormatter.departureAirport(decodeResult, dep);
2602
- data.delete("DEP");
2603
- }
2604
- const des = data.get("DES");
2605
- if (des) {
2606
- ResultFormatter.arrivalAirport(decodeResult, des);
2607
- data.delete("DES");
2608
- }
2609
- const eta = data.get("ETA");
2610
- if (eta) {
2611
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta));
2612
- data.delete("ETA");
2613
- }
2614
- const alt = data.get("ALT");
2615
- if (alt) {
2616
- ResultFormatter.altitude(decodeResult, Number(alt));
2617
- data.delete("ALT");
2618
- }
2619
- const fn = data.get("FN");
2620
- if (fn) {
2621
- ResultFormatter.flightNumber(decodeResult, fn);
2622
- data.delete("FN");
2623
- }
2624
- const day = data.get("DAY");
2625
- const utc = data.get("UTC");
2626
- if (day && utc) {
2627
- decodeResult.raw.message_timestamp = Date.parse(day + " GMT+0000") / 1e3 + DateTimeUtils.convertHHMMSSToTod(utc);
2628
- data.delete("DAY");
2629
- data.delete("UTC");
2630
- }
2631
- const lat = data.get("LAT");
2632
- const lon = data.get("LON");
2633
- if (lat && lon) {
2634
- ResultFormatter.position(decodeResult, {
2635
- latitude: CoordinateUtils.getDirection(lat[0]) * Number(lat.substring(1)),
2636
- longitude: CoordinateUtils.getDirection(lon[0]) * Number(lon.substring(1))
2637
- });
2638
- data.delete("LAT");
2639
- data.delete("LON");
2640
- }
2641
- let remaining = "";
2642
- for (const [key, value] of data.entries()) {
2643
- if (key === "") {
2644
- remaining += value;
2645
- } else {
2646
- remaining += `/${key} ${value}`;
2320
+ ResultFormatter.departureAirport(decodeResult, fields[0]);
2321
+ ResultFormatter.arrivalAirport(decodeResult, fields[1]);
2322
+ ResultFormatter.off(
2323
+ decodeResult,
2324
+ DateTimeUtils.convertHHMMSSToTod(fields[2])
2325
+ );
2326
+ ResultFormatter.unknown(decodeResult, fields[3]);
2327
+ decodeResult.decoded = true;
2328
+ decodeResult.decoder.decodeLevel = "partial";
2329
+ } else if (message.text.startsWith("OFF02")) {
2330
+ const fields = message.text.substring(5).split("/");
2331
+ if (fields.length != 2) {
2332
+ decodeResult.decoded = false;
2333
+ decodeResult.decoder.decodeLevel = "none";
2334
+ return decodeResult;
2647
2335
  }
2648
- }
2649
- decodeResult.remaining.text = remaining;
2650
- decodeResult.decoded = true;
2651
- decodeResult.decoder.decodeLevel = "partial";
2652
- return decodeResult;
2653
- }
2654
- };
2655
-
2656
- // lib/plugins/Label_1L_070.ts
2657
- var Label_1L_070 = class extends DecoderPlugin {
2658
- name = "label-1l-070";
2659
- qualifiers() {
2660
- return {
2661
- labels: ["1L"],
2662
- preambles: ["000000070"]
2663
- };
2664
- }
2665
- decode(message, options = {}) {
2666
- const decodeResult = this.defaultResult();
2667
- decodeResult.decoder.name = this.name;
2668
- decodeResult.formatted.description = "Position Report";
2669
- decodeResult.message = message;
2670
- if (!message.text.startsWith("000000070")) {
2671
- if (options.debug) {
2672
- console.log(`Decoder: Unknown 1L message: ${message.text}`);
2336
+ ResultFormatter.flightNumber(decodeResult, fields[0]);
2337
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
2338
+ fields[1].substring(0, 14)
2339
+ );
2340
+ if (position) {
2341
+ ResultFormatter.position(decodeResult, position);
2673
2342
  }
2674
- decodeResult.remaining.text = message.text;
2675
- decodeResult.decoded = false;
2676
- decodeResult.decoder.decodeLevel = "none";
2677
- return decodeResult;
2678
- }
2679
- const parts = message.text.substring(9).split(",");
2680
- if (parts.length !== 7) {
2343
+ ResultFormatter.day(decodeResult, Number(fields[1].substring(14, 16)));
2344
+ ResultFormatter.time_of_day(
2345
+ decodeResult,
2346
+ DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 20))
2347
+ );
2348
+ ResultFormatter.departureAirport(
2349
+ decodeResult,
2350
+ fields[1].substring(20, 24)
2351
+ );
2352
+ ResultFormatter.arrivalAirport(decodeResult, fields[1].substring(24, 28));
2353
+ ResultFormatter.off(
2354
+ decodeResult,
2355
+ DateTimeUtils.convertHHMMSSToTod(fields[1].substring(28, 32))
2356
+ );
2357
+ ResultFormatter.unknown(decodeResult, fields[1].substring(32, 36));
2358
+ ResultFormatter.eta(
2359
+ decodeResult,
2360
+ DateTimeUtils.convertHHMMSSToTod(fields[1].substring(36, 40))
2361
+ );
2362
+ decodeResult.decoded = true;
2363
+ decodeResult.decoder.decodeLevel = "partial";
2364
+ } else {
2681
2365
  if (options.debug) {
2682
- console.log(`Decoder: Unknown 1L message: ${message.text}`);
2366
+ console.log(`DEBUG: ${this.name}: Unknown variation.`);
2683
2367
  }
2684
- decodeResult.remaining.text = message.text;
2685
2368
  decodeResult.decoded = false;
2686
2369
  decodeResult.decoder.decodeLevel = "none";
2687
- return decodeResult;
2688
2370
  }
2689
- ResultFormatter.departureAirport(decodeResult, parts[0]);
2690
- ResultFormatter.arrivalAirport(decodeResult, parts[1]);
2691
- ResultFormatter.time_of_day(
2692
- decodeResult,
2693
- DateTimeUtils.convertHHMMSSToTod(parts[2])
2694
- );
2695
- ResultFormatter.eta(
2696
- decodeResult,
2697
- DateTimeUtils.convertHHMMSSToTod(parts[3])
2698
- );
2699
- ResultFormatter.position(decodeResult, {
2700
- latitude: CoordinateUtils.getDirection(parts[4][0]) * Number(parts[4].substring(1)),
2701
- longitude: CoordinateUtils.getDirection(parts[5][0]) * Number(parts[5].substring(1))
2702
- });
2703
- decodeResult.remaining.text = parts[6];
2704
- decodeResult.decoded = true;
2705
- decodeResult.decoder.decodeLevel = "partial";
2706
2371
  return decodeResult;
2707
2372
  }
2708
2373
  };
2709
2374
 
2710
- // lib/plugins/Label_1L_660.ts
2711
- var Label_1L_660 = class extends DecoderPlugin {
2712
- name = "label-1l-660";
2375
+ // lib/plugins/Label_22_POS.ts
2376
+ var Label_22_POS = class extends DecoderPlugin {
2377
+ name = "label-22-pos";
2713
2378
  qualifiers() {
2714
2379
  return {
2715
- labels: ["1L"],
2716
- preambles: ["000000660"]
2380
+ labels: ["22"],
2381
+ preambles: ["N", "S"]
2717
2382
  };
2718
2383
  }
2719
2384
  decode(message, options = {}) {
@@ -2721,163 +2386,160 @@ var Label_1L_660 = class extends DecoderPlugin {
2721
2386
  decodeResult.decoder.name = this.name;
2722
2387
  decodeResult.formatted.description = "Position Report";
2723
2388
  decodeResult.message = message;
2724
- if (!message.text.startsWith("000000660")) {
2725
- if (options.debug) {
2726
- console.log(`Decoder: Unknown 1L message: ${message.text}`);
2727
- }
2728
- decodeResult.remaining.text = message.text;
2729
- decodeResult.decoded = false;
2730
- decodeResult.decoder.decodeLevel = "none";
2731
- return decodeResult;
2732
- }
2733
- const parts = message.text.substring(9).split(",");
2734
- if (parts.length !== 5) {
2389
+ const fields = message.text.split(",");
2390
+ if (fields.length !== 11) {
2735
2391
  if (options.debug) {
2736
- console.log(`Decoder: Unknown 1L message: ${message.text}`);
2392
+ console.log(
2393
+ `DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${fields.join(",")}`
2394
+ );
2737
2395
  }
2738
- decodeResult.remaining.text = message.text;
2739
2396
  decodeResult.decoded = false;
2740
2397
  decodeResult.decoder.decodeLevel = "none";
2741
2398
  return decodeResult;
2742
2399
  }
2743
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
2744
- parts[0]
2745
- );
2746
- if (position) {
2747
- ResultFormatter.position(decodeResult, position);
2748
- }
2749
- const hhmmss = parts[1].substring(0, 6);
2400
+ const latStr = fields[0].substring(1, 8);
2401
+ const lonStr = fields[0].substring(9);
2402
+ const lat = Number(latStr) / 1e4;
2403
+ const lon = Number(lonStr) / 1e4;
2404
+ ResultFormatter.position(decodeResult, {
2405
+ latitude: CoordinateUtils.getDirection(fields[0][0]) * lat,
2406
+ longitude: CoordinateUtils.getDirection(fields[0][8]) * lon
2407
+ });
2750
2408
  ResultFormatter.time_of_day(
2751
2409
  decodeResult,
2752
- DateTimeUtils.convertHHMMSSToTod(hhmmss)
2410
+ DateTimeUtils.convertHHMMSSToTod(fields[2])
2753
2411
  );
2754
- const fl = parts[1].substring(6, 9);
2755
- ResultFormatter.altitude(decodeResult, Number(fl) * 100);
2756
- const next = parts[1].substring(9);
2757
- ResultFormatter.route(decodeResult, { waypoints: [{ name: next.trim() }] });
2758
- decodeResult.remaining.text = parts.slice(2).join(",");
2412
+ ResultFormatter.altitude(decodeResult, Number(fields[3]));
2413
+ ResultFormatter.unknownArr(decodeResult, [fields[1], ...fields.slice(4)]);
2759
2414
  decodeResult.decoded = true;
2760
2415
  decodeResult.decoder.decodeLevel = "partial";
2761
2416
  return decodeResult;
2762
2417
  }
2763
2418
  };
2764
2419
 
2765
- // lib/plugins/Label_1L_Slash.ts
2766
- var Label_1L_Slash = class extends DecoderPlugin {
2767
- name = "label-1l-1-line";
2420
+ // lib/plugins/Label_2P_FM3.ts
2421
+ var Label_2P_FM3 = class extends DecoderPlugin {
2422
+ name = "label-2p-fm3";
2768
2423
  qualifiers() {
2769
2424
  return {
2770
- labels: ["1L"],
2771
- preambles: ["+", "-"]
2425
+ labels: ["2P"]
2772
2426
  };
2773
2427
  }
2774
2428
  decode(message, options = {}) {
2775
- const decodeResult = this.defaultResult();
2429
+ let decodeResult = this.defaultResult();
2776
2430
  decodeResult.decoder.name = this.name;
2777
- decodeResult.formatted.description = "Position Report";
2431
+ decodeResult.formatted.description = "Flight Report";
2778
2432
  decodeResult.message = message;
2779
- const parts = message.text.split("/");
2780
- if (parts.length !== 7) {
2433
+ const parts = message.text.split(",");
2434
+ if (parts.length === 7) {
2435
+ const header = parts[0].split("FM3 ");
2436
+ if (header.length == 0) {
2437
+ ResultFormatter.unknown(decodeResult, message.text);
2438
+ decodeResult.decoded = false;
2439
+ decodeResult.decoder.decodeLevel = "none";
2440
+ return decodeResult;
2441
+ }
2442
+ if (header[0].length > 0) {
2443
+ ResultFormatter.unknown(decodeResult, header[0].substring(0, 4));
2444
+ ResultFormatter.flightNumber(decodeResult, header[0].substring(4));
2445
+ }
2446
+ if (header[1].length === 4) {
2447
+ ResultFormatter.time_of_day(
2448
+ decodeResult,
2449
+ DateTimeUtils.convertHHMMSSToTod(header[1])
2450
+ );
2451
+ } else {
2452
+ ResultFormatter.time_of_day(
2453
+ decodeResult,
2454
+ DateTimeUtils.convertHHMMSSToTod(header[1])
2455
+ );
2456
+ }
2457
+ ResultFormatter.eta(
2458
+ decodeResult,
2459
+ DateTimeUtils.convertHHMMSSToTod(parts[1])
2460
+ );
2461
+ const lat = parts[2].replaceAll(" ", "");
2462
+ const lon = parts[3].replaceAll(" ", "");
2463
+ if (lat[0] === "N" || lat[0] === "S") {
2464
+ ResultFormatter.position(decodeResult, {
2465
+ latitude: CoordinateUtils.getDirection(lat[0]) * Number(lat.substring(1)),
2466
+ longitude: CoordinateUtils.getDirection(lon[0]) * Number(lon.substring(1))
2467
+ });
2468
+ } else {
2469
+ ResultFormatter.position(decodeResult, {
2470
+ latitude: Number(lat),
2471
+ longitude: Number(lon)
2472
+ });
2473
+ }
2474
+ ResultFormatter.altitude(decodeResult, Number(parts[4]));
2475
+ ResultFormatter.unknown(decodeResult, parts[5]);
2476
+ ResultFormatter.unknown(decodeResult, parts[6]);
2477
+ decodeResult.decoded = true;
2478
+ decodeResult.decoder.decodeLevel = "partial";
2479
+ } else {
2781
2480
  if (options.debug) {
2782
- console.log(`Decoder: Unknown 1L message: ${message.text}`);
2481
+ console.log(`Decoder: Unknown H1 message: ${message.text}`);
2783
2482
  }
2784
- decodeResult.remaining.text = message.text;
2483
+ ResultFormatter.unknown(decodeResult, message.text);
2785
2484
  decodeResult.decoded = false;
2786
2485
  decodeResult.decoder.decodeLevel = "none";
2787
- return decodeResult;
2788
- }
2789
- const data = /* @__PURE__ */ new Map();
2790
- data.set("LAT", parts[0].replaceAll(" ", ""));
2791
- data.set("LON", parts[1].replaceAll(" ", ""));
2792
- for (let i = 2; i < parts.length; i++) {
2793
- const part = parts[i].split(" ");
2794
- data.set(part[0], part.slice(1).join(" "));
2795
- }
2796
- const position = {
2797
- latitude: Number(data.get("LAT")),
2798
- longitude: Number(data.get("LON"))
2799
- };
2800
- data.delete("LAT");
2801
- data.delete("LON");
2802
- ResultFormatter.position(decodeResult, position);
2803
- const utc = data.get("UTC");
2804
- if (utc) {
2805
- ResultFormatter.time_of_day(
2806
- decodeResult,
2807
- DateTimeUtils.convertHHMMSSToTod(utc)
2808
- );
2809
- data.delete("UTC");
2810
- }
2811
- const alt = data.get("ALT");
2812
- if (alt) {
2813
- ResultFormatter.altitude(decodeResult, Number(alt));
2814
- data.delete("ALT");
2815
- }
2816
- const fob = data.get("FOB");
2817
- if (fob) {
2818
- ResultFormatter.currentFuel(decodeResult, Number(fob));
2819
- data.delete("FOB");
2820
- }
2821
- const eta = data.get("ETA");
2822
- if (eta) {
2823
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta));
2824
- data.delete("ETA");
2825
- }
2826
- let remaining = "";
2827
- for (const [key, value] of data.entries()) {
2828
- remaining += `/${key} ${value}`;
2829
2486
  }
2830
- decodeResult.remaining.text = remaining;
2831
- decodeResult.decoded = true;
2832
- decodeResult.decoder.decodeLevel = "partial";
2833
2487
  return decodeResult;
2834
2488
  }
2835
2489
  };
2836
2490
 
2837
- // lib/plugins/Label_20_POS.ts
2838
- var Label_20_POS = class extends DecoderPlugin {
2839
- name = "label-20-pos";
2491
+ // lib/plugins/Label_2P_FM4.ts
2492
+ var Label_2P_FM4 = class extends DecoderPlugin {
2493
+ name = "label-2p-fm4";
2840
2494
  qualifiers() {
2841
2495
  return {
2842
- labels: ["20"],
2843
- preambles: ["POS"]
2496
+ labels: ["2P"]
2844
2497
  };
2845
2498
  }
2846
2499
  decode(message, options = {}) {
2847
- const decodeResult = this.defaultResult();
2500
+ let decodeResult = this.defaultResult();
2848
2501
  decodeResult.decoder.name = this.name;
2849
- decodeResult.formatted.description = "Position Report";
2502
+ decodeResult.formatted.description = "Flight Report";
2850
2503
  decodeResult.message = message;
2851
- decodeResult.raw.preamble = message.text.substring(0, 3);
2852
- const content = message.text.substring(3);
2853
- const fields = content.split(",");
2854
- if (fields.length == 11) {
2855
- if (options.debug) {
2856
- console.log(`DEBUG: ${this.name}: Variation 1 detected`);
2504
+ const parts = message.text.split(",");
2505
+ if (parts.length === 10) {
2506
+ const header = parts[0].split("FM4");
2507
+ if (header.length == 0) {
2508
+ ResultFormatter.unknown(decodeResult, message.text);
2509
+ decodeResult.decoded = false;
2510
+ decodeResult.decoder.decodeLevel = "none";
2511
+ return decodeResult;
2857
2512
  }
2858
- const rawCoords = fields[0];
2859
- ResultFormatter.position(
2513
+ if (header[0].length > 0) {
2514
+ ResultFormatter.unknown(decodeResult, header[0].substring(0, 4));
2515
+ ResultFormatter.flightNumber(decodeResult, header[0].substring(4));
2516
+ }
2517
+ ResultFormatter.departureAirport(decodeResult, header[1]);
2518
+ ResultFormatter.arrivalAirport(decodeResult, parts[1]);
2519
+ ResultFormatter.day(decodeResult, Number(parts[2].substring(0, 2)));
2520
+ ResultFormatter.time_of_day(
2860
2521
  decodeResult,
2861
- CoordinateUtils.decodeStringCoordinates(rawCoords)
2522
+ DateTimeUtils.convertHHMMSSToTod(parts[2].substring(2))
2862
2523
  );
2524
+ ResultFormatter.eta(
2525
+ decodeResult,
2526
+ DateTimeUtils.convertHHMMSSToTod(parts[3])
2527
+ );
2528
+ ResultFormatter.position(decodeResult, {
2529
+ latitude: Number(parts[4].replaceAll(" ", "")),
2530
+ longitude: Number(parts[5].replaceAll(" ", ""))
2531
+ });
2532
+ ResultFormatter.altitude(decodeResult, Number(parts[6]));
2533
+ ResultFormatter.heading(decodeResult, Number(parts[7]));
2534
+ ResultFormatter.unknown(decodeResult, parts[8]);
2535
+ ResultFormatter.unknown(decodeResult, parts[9]);
2863
2536
  decodeResult.decoded = true;
2864
- decodeResult.decoder.decodeLevel = "full";
2865
- } else if (fields.length == 5) {
2866
- if (options.debug) {
2867
- console.log(`DEBUG: ${this.name}: Variation 2 detected`);
2868
- }
2869
- const position = CoordinateUtils.decodeStringCoordinates(fields[0]);
2870
- if (position) {
2871
- ResultFormatter.position(decodeResult, position);
2872
- }
2873
- decodeResult.decoded = true;
2874
- decodeResult.decoder.decodeLevel = "full";
2537
+ decodeResult.decoder.decodeLevel = "partial";
2875
2538
  } else {
2876
2539
  if (options.debug) {
2877
- console.log(
2878
- `DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`
2879
- );
2540
+ console.log(`Decoder: Unknown H1 message: ${message.text}`);
2880
2541
  }
2542
+ ResultFormatter.unknown(decodeResult, message.text);
2881
2543
  decodeResult.decoded = false;
2882
2544
  decodeResult.decoder.decodeLevel = "none";
2883
2545
  }
@@ -2885,168 +2547,105 @@ var Label_20_POS = class extends DecoderPlugin {
2885
2547
  }
2886
2548
  };
2887
2549
 
2888
- // lib/plugins/Label_21_POS.ts
2889
- var Label_21_POS = class extends DecoderPlugin {
2890
- name = "label-21-pos";
2550
+ // lib/plugins/Label_2P_FM5.ts
2551
+ var Label_2P_FM5 = class extends DecoderPlugin {
2552
+ name = "label-2p-fm5";
2891
2553
  qualifiers() {
2892
2554
  return {
2893
- labels: ["21"],
2894
- preambles: ["POS"]
2555
+ labels: ["2P"]
2895
2556
  };
2896
2557
  }
2897
2558
  decode(message, options = {}) {
2898
- const decodeResult = this.defaultResult();
2559
+ let decodeResult = this.defaultResult();
2899
2560
  decodeResult.decoder.name = this.name;
2900
- decodeResult.formatted.description = "Position Report";
2561
+ decodeResult.formatted.description = "Flight Report";
2901
2562
  decodeResult.message = message;
2902
- decodeResult.raw.preamble = message.text.substring(0, 3);
2903
- const content = message.text.substring(3);
2904
- const fields = content.split(",");
2905
- if (fields.length == 9) {
2906
- processPosition(decodeResult, fields[0].trim());
2563
+ const parts = message.text.split(",");
2564
+ if (parts.length === 12) {
2565
+ const header = parts[0].split("FM5 ");
2566
+ if (header.length == 0) {
2567
+ ResultFormatter.unknown(decodeResult, message.text);
2568
+ decodeResult.decoded = false;
2569
+ decodeResult.decoder.decodeLevel = "none";
2570
+ return decodeResult;
2571
+ }
2572
+ ResultFormatter.departureAirport(decodeResult, header[1]);
2573
+ ResultFormatter.arrivalAirport(decodeResult, parts[1]);
2907
2574
  ResultFormatter.time_of_day(
2908
2575
  decodeResult,
2909
- DateTimeUtils.convertHHMMSSToTod(fields[2])
2576
+ DateTimeUtils.convertHHMMSSToTod(parts[2])
2910
2577
  );
2911
- ResultFormatter.altitude(decodeResult, Number(fields[3]));
2912
- ResultFormatter.temperature(decodeResult, fields[6].replace(/ /g, ""));
2913
2578
  ResultFormatter.eta(
2914
2579
  decodeResult,
2915
- DateTimeUtils.convertHHMMSSToTod(fields[7])
2580
+ DateTimeUtils.convertHHMMSSToTod(parts[3])
2916
2581
  );
2917
- ResultFormatter.arrivalAirport(decodeResult, fields[8]);
2918
- ResultFormatter.unknownArr(decodeResult, [
2919
- fields[1],
2920
- fields[4],
2921
- fields[5]
2922
- ]);
2582
+ ResultFormatter.position(decodeResult, {
2583
+ latitude: Number(parts[4].replaceAll(" ", "")),
2584
+ longitude: Number(parts[5].replaceAll(" ", ""))
2585
+ });
2586
+ ResultFormatter.altitude(decodeResult, Number(parts[6]));
2587
+ ResultFormatter.unknown(decodeResult, parts[7]);
2588
+ ResultFormatter.unknown(decodeResult, parts[8]);
2589
+ ResultFormatter.unknown(decodeResult, parts[9]);
2590
+ ResultFormatter.flightNumber(decodeResult, parts[10].trim());
2591
+ ResultFormatter.unknown(decodeResult, parts[11]);
2923
2592
  decodeResult.decoded = true;
2924
2593
  decodeResult.decoder.decodeLevel = "partial";
2925
2594
  } else {
2926
2595
  if (options.debug) {
2927
- console.log(
2928
- `DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`
2929
- );
2596
+ console.log(`Decoder: Unknown H1 message: ${message.text}`);
2930
2597
  }
2598
+ ResultFormatter.unknown(decodeResult, message.text);
2931
2599
  decodeResult.decoded = false;
2932
2600
  decodeResult.decoder.decodeLevel = "none";
2933
2601
  }
2934
2602
  return decodeResult;
2935
2603
  }
2936
2604
  };
2937
- function processPosition(decodeResult, value) {
2938
- if (value.length !== 16 && value[0] !== "N" && value[0] !== "S" && value[8] !== "W" && value[8] !== "E") {
2939
- return;
2940
- }
2941
- const latDir = value[0] === "N" ? 1 : -1;
2942
- const lonDir = value[8] === "E" ? 1 : -1;
2943
- const position = {
2944
- latitude: latDir * Number(value.substring(1, 7)),
2945
- longitude: lonDir * Number(value.substring(9, 15))
2946
- };
2947
- ResultFormatter.position(decodeResult, position);
2948
- }
2949
2605
 
2950
- // lib/plugins/Label_22_OFF.ts
2951
- var Label_22_OFF = class extends DecoderPlugin {
2952
- name = "label-22-off";
2606
+ // lib/plugins/Label_24_Slash.ts
2607
+ var Label_24_Slash = class extends DecoderPlugin {
2608
+ name = "label-24-slash";
2953
2609
  qualifiers() {
2954
2610
  return {
2955
- labels: ["22"],
2956
- preambles: ["OFF"]
2611
+ labels: ["24"],
2612
+ preambles: ["/"]
2957
2613
  };
2958
2614
  }
2959
2615
  decode(message, options = {}) {
2960
2616
  const decodeResult = this.defaultResult();
2961
2617
  decodeResult.decoder.name = this.name;
2962
- decodeResult.formatted.description = "Takeoff Report";
2618
+ decodeResult.formatted.description = "Position Report";
2963
2619
  decodeResult.message = message;
2964
- if (message.text.startsWith("OFF01")) {
2965
- const fields = message.text.substring(5).split("/");
2966
- if (fields.length != 2) {
2967
- decodeResult.decoded = false;
2968
- decodeResult.decoder.decodeLevel = "none";
2969
- return decodeResult;
2970
- }
2971
- ResultFormatter.flightNumber(decodeResult, fields[0]);
2972
- ResultFormatter.departureDay(
2973
- decodeResult,
2974
- Number(fields[1].substring(0, 2))
2975
- );
2976
- ResultFormatter.arrivalDay(
2977
- decodeResult,
2978
- Number(fields[1].substring(2, 4))
2979
- );
2980
- ResultFormatter.time_of_day(
2981
- decodeResult,
2982
- DateTimeUtils.convertHHMMSSToTod(fields[1].substring(4, 8))
2983
- );
2984
- ResultFormatter.departureAirport(
2985
- decodeResult,
2986
- fields[1].substring(8, 12)
2987
- );
2988
- ResultFormatter.arrivalAirport(decodeResult, fields[1].substring(12, 16));
2989
- ResultFormatter.off(
2990
- decodeResult,
2991
- DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 22))
2992
- );
2993
- ResultFormatter.unknown(decodeResult, fields[1].substring(22));
2994
- decodeResult.decoded = true;
2995
- decodeResult.decoder.decodeLevel = "partial";
2996
- } else if (message.text.startsWith("OFF02\r\n")) {
2997
- const fields = message.text.substring(7).split(",");
2998
- if (fields.length != 4) {
2999
- decodeResult.decoded = false;
3000
- decodeResult.decoder.decodeLevel = "none";
3001
- return decodeResult;
3002
- }
3003
- ResultFormatter.departureAirport(decodeResult, fields[0]);
3004
- ResultFormatter.arrivalAirport(decodeResult, fields[1]);
3005
- ResultFormatter.off(
3006
- decodeResult,
3007
- DateTimeUtils.convertHHMMSSToTod(fields[2])
3008
- );
3009
- ResultFormatter.unknown(decodeResult, fields[3]);
3010
- decodeResult.decoded = true;
3011
- decodeResult.decoder.decodeLevel = "partial";
3012
- } else if (message.text.startsWith("OFF02")) {
3013
- const fields = message.text.substring(5).split("/");
3014
- if (fields.length != 2) {
3015
- decodeResult.decoded = false;
3016
- decodeResult.decoder.decodeLevel = "none";
3017
- return decodeResult;
3018
- }
3019
- ResultFormatter.flightNumber(decodeResult, fields[0]);
3020
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
3021
- fields[1].substring(0, 14)
3022
- );
3023
- if (position) {
3024
- ResultFormatter.position(decodeResult, position);
3025
- }
3026
- ResultFormatter.day(decodeResult, Number(fields[1].substring(14, 16)));
3027
- ResultFormatter.time_of_day(
3028
- decodeResult,
3029
- DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 20))
3030
- );
3031
- ResultFormatter.departureAirport(
3032
- decodeResult,
3033
- fields[1].substring(20, 24)
3034
- );
3035
- ResultFormatter.arrivalAirport(decodeResult, fields[1].substring(24, 28));
3036
- ResultFormatter.off(
3037
- decodeResult,
3038
- DateTimeUtils.convertHHMMSSToTod(fields[1].substring(28, 32))
2620
+ const fields = message.text.split("/");
2621
+ if (fields.length == 10 && fields[0] == "" && fields[9] == "") {
2622
+ const ddmmyy = fields[1].substring(2, 4) + fields[1].substring(4, 6) + fields[1].substring(0, 2);
2623
+ const hhmmss = fields[2] + "00";
2624
+ decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(
2625
+ hhmmss,
2626
+ ddmmyy
3039
2627
  );
3040
- ResultFormatter.unknown(decodeResult, fields[1].substring(32, 36));
2628
+ ResultFormatter.flightNumber(decodeResult, fields[3]);
2629
+ ResultFormatter.altitude(decodeResult, Number(fields[4]));
2630
+ const lat = fields[5];
2631
+ const lon = fields[6];
2632
+ const position = {
2633
+ latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1)),
2634
+ longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1))
2635
+ };
2636
+ ResultFormatter.position(decodeResult, position);
3041
2637
  ResultFormatter.eta(
3042
2638
  decodeResult,
3043
- DateTimeUtils.convertHHMMSSToTod(fields[1].substring(36, 40))
2639
+ DateTimeUtils.convertHHMMSSToTod(fields[8])
3044
2640
  );
2641
+ ResultFormatter.unknown(decodeResult, fields[7]);
3045
2642
  decodeResult.decoded = true;
3046
2643
  decodeResult.decoder.decodeLevel = "partial";
3047
2644
  } else {
3048
2645
  if (options.debug) {
3049
- console.log(`DEBUG: ${this.name}: Unknown variation.`);
2646
+ console.log(
2647
+ `DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}. Message: ${message.text}`
2648
+ );
3050
2649
  }
3051
2650
  decodeResult.decoded = false;
3052
2651
  decodeResult.decoder.decodeLevel = "none";
@@ -3055,409 +2654,201 @@ var Label_22_OFF = class extends DecoderPlugin {
3055
2654
  }
3056
2655
  };
3057
2656
 
3058
- // lib/plugins/Label_22_POS.ts
3059
- var Label_22_POS = class extends DecoderPlugin {
3060
- name = "label-22-pos";
2657
+ // lib/plugins/Label_30_Slash_EA.ts
2658
+ var Label_30_Slash_EA = class extends DecoderPlugin {
2659
+ name = "label-30-slash-ea";
3061
2660
  qualifiers() {
3062
2661
  return {
3063
- labels: ["22"],
3064
- preambles: ["N", "S"]
2662
+ labels: ["30"],
2663
+ preambles: ["/EA"]
3065
2664
  };
3066
2665
  }
3067
2666
  decode(message, options = {}) {
3068
2667
  const decodeResult = this.defaultResult();
3069
2668
  decodeResult.decoder.name = this.name;
3070
- decodeResult.formatted.description = "Position Report";
2669
+ decodeResult.formatted.description = "ETA Report";
3071
2670
  decodeResult.message = message;
3072
- const fields = message.text.split(",");
3073
- if (fields.length !== 11) {
2671
+ const results = message.text.split(/\n|\//).slice(1);
2672
+ if (results) {
3074
2673
  if (options.debug) {
3075
- console.log(
3076
- `DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${fields.join(",")}`
3077
- );
2674
+ console.log("Label 30 EA: results");
2675
+ console.log(results);
3078
2676
  }
3079
- decodeResult.decoded = false;
3080
- decodeResult.decoder.decodeLevel = "none";
3081
- return decodeResult;
3082
2677
  }
3083
- const latStr = fields[0].substring(1, 8);
3084
- const lonStr = fields[0].substring(9);
3085
- const lat = Number(latStr) / 1e4;
3086
- const lon = Number(lonStr) / 1e4;
3087
- ResultFormatter.position(decodeResult, {
3088
- latitude: CoordinateUtils.getDirection(fields[0][0]) * lat,
3089
- longitude: CoordinateUtils.getDirection(fields[0][8]) * lon
3090
- });
3091
- ResultFormatter.time_of_day(
2678
+ ResultFormatter.eta(
3092
2679
  decodeResult,
3093
- DateTimeUtils.convertHHMMSSToTod(fields[2])
2680
+ DateTimeUtils.convertHHMMSSToTod(results[0].substr(2, 4))
3094
2681
  );
3095
- ResultFormatter.altitude(decodeResult, Number(fields[3]));
3096
- ResultFormatter.unknownArr(decodeResult, [fields[1], ...fields.slice(4)]);
2682
+ if (results[1].substring(0, 2) === "DS") {
2683
+ ResultFormatter.arrivalAirport(decodeResult, results[1].substring(2, 6));
2684
+ ResultFormatter.unknown(decodeResult, "/".concat(results[2]));
2685
+ } else {
2686
+ ResultFormatter.unknown(
2687
+ decodeResult,
2688
+ "/".concat(results[1], "/", results[2])
2689
+ );
2690
+ }
3097
2691
  decodeResult.decoded = true;
3098
2692
  decodeResult.decoder.decodeLevel = "partial";
3099
2693
  return decodeResult;
3100
2694
  }
3101
2695
  };
3102
2696
 
3103
- // lib/plugins/Label_2P_FM3.ts
3104
- var Label_2P_FM3 = class extends DecoderPlugin {
3105
- name = "label-2p-fm3";
2697
+ // lib/plugins/Label_44_ETA.ts
2698
+ var Label_44_ETA = class extends DecoderPlugin {
2699
+ name = "label-44-eta";
3106
2700
  qualifiers() {
3107
2701
  return {
3108
- labels: ["2P"]
2702
+ labels: ["44"],
2703
+ preambles: ["00ETA01", "00ETA02", "00ETA03", "ETA01", "ETA02", "ETA03"]
3109
2704
  };
3110
2705
  }
3111
2706
  decode(message, options = {}) {
3112
- let decodeResult = this.defaultResult();
2707
+ const decodeResult = this.defaultResult();
3113
2708
  decodeResult.decoder.name = this.name;
3114
- decodeResult.formatted.description = "Flight Report";
2709
+ decodeResult.formatted.description = "ETA Report";
3115
2710
  decodeResult.message = message;
3116
- const parts = message.text.split(",");
3117
- if (parts.length === 7) {
3118
- const header = parts[0].split("FM3 ");
3119
- if (header.length == 0) {
3120
- ResultFormatter.unknown(decodeResult, message.text);
3121
- decodeResult.decoded = false;
3122
- decodeResult.decoder.decodeLevel = "none";
3123
- return decodeResult;
3124
- }
3125
- if (header[0].length > 0) {
3126
- ResultFormatter.unknown(decodeResult, header[0].substring(0, 4));
3127
- ResultFormatter.flightNumber(decodeResult, header[0].substring(4));
3128
- }
3129
- if (header[1].length === 4) {
3130
- ResultFormatter.time_of_day(
3131
- decodeResult,
3132
- DateTimeUtils.convertHHMMSSToTod(header[1])
3133
- );
3134
- } else {
3135
- ResultFormatter.time_of_day(
3136
- decodeResult,
3137
- DateTimeUtils.convertHHMMSSToTod(header[1])
3138
- );
2711
+ const data = message.text.split(",");
2712
+ if (data.length >= 9) {
2713
+ if (options.debug) {
2714
+ console.log("Label 44 ETA Report: groups");
2715
+ console.log(data);
3139
2716
  }
2717
+ ResultFormatter.position(
2718
+ decodeResult,
2719
+ CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[1])
2720
+ );
2721
+ ResultFormatter.altitude(decodeResult, 100 * Number(data[2]));
2722
+ ResultFormatter.departureAirport(decodeResult, data[3]);
2723
+ ResultFormatter.arrivalAirport(decodeResult, data[4]);
2724
+ ResultFormatter.month(decodeResult, Number(data[5].substring(0, 2)));
2725
+ ResultFormatter.day(decodeResult, Number(data[5].substring(2, 4)));
2726
+ ResultFormatter.time_of_day(
2727
+ decodeResult,
2728
+ DateTimeUtils.convertHHMMSSToTod(data[6])
2729
+ );
3140
2730
  ResultFormatter.eta(
3141
2731
  decodeResult,
3142
- DateTimeUtils.convertHHMMSSToTod(parts[1])
2732
+ DateTimeUtils.convertHHMMSSToTod(data[7])
3143
2733
  );
3144
- const lat = parts[2].replaceAll(" ", "");
3145
- const lon = parts[3].replaceAll(" ", "");
3146
- if (lat[0] === "N" || lat[0] === "S") {
3147
- ResultFormatter.position(decodeResult, {
3148
- latitude: CoordinateUtils.getDirection(lat[0]) * Number(lat.substring(1)),
3149
- longitude: CoordinateUtils.getDirection(lon[0]) * Number(lon.substring(1))
3150
- });
3151
- } else {
3152
- ResultFormatter.position(decodeResult, {
3153
- latitude: Number(lat),
3154
- longitude: Number(lon)
3155
- });
2734
+ const fuel = Number(data[8]);
2735
+ if (!isNaN(fuel)) {
2736
+ ResultFormatter.remainingFuel(decodeResult, Number(fuel));
2737
+ }
2738
+ if (data.length > 9) {
2739
+ ResultFormatter.unknownArr(decodeResult, data.slice(9));
3156
2740
  }
3157
- ResultFormatter.altitude(decodeResult, Number(parts[4]));
3158
- ResultFormatter.unknown(decodeResult, parts[5]);
3159
- ResultFormatter.unknown(decodeResult, parts[6]);
3160
- decodeResult.decoded = true;
3161
- decodeResult.decoder.decodeLevel = "partial";
3162
2741
  } else {
3163
2742
  if (options.debug) {
3164
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
2743
+ console.log(`Decoder: Unknown 44 message: ${message.text}`);
3165
2744
  }
3166
2745
  ResultFormatter.unknown(decodeResult, message.text);
3167
2746
  decodeResult.decoded = false;
3168
2747
  decodeResult.decoder.decodeLevel = "none";
2748
+ return decodeResult;
3169
2749
  }
2750
+ decodeResult.decoded = true;
2751
+ decodeResult.decoder.decodeLevel = "full";
3170
2752
  return decodeResult;
3171
2753
  }
3172
2754
  };
3173
2755
 
3174
- // lib/plugins/Label_2P_FM4.ts
3175
- var Label_2P_FM4 = class extends DecoderPlugin {
3176
- name = "label-2p-fm4";
2756
+ // lib/plugins/Label_44_IN.ts
2757
+ var Label_44_IN = class extends DecoderPlugin {
2758
+ name = "label-44-in";
3177
2759
  qualifiers() {
3178
2760
  return {
3179
- labels: ["2P"]
2761
+ labels: ["44"],
2762
+ preambles: ["00IN01", "00IN02", "00IN03", "IN01", "IN02", "IN03"]
3180
2763
  };
3181
2764
  }
3182
2765
  decode(message, options = {}) {
3183
- let decodeResult = this.defaultResult();
2766
+ const decodeResult = this.defaultResult();
3184
2767
  decodeResult.decoder.name = this.name;
3185
- decodeResult.formatted.description = "Flight Report";
2768
+ decodeResult.formatted.description = "In Air Report";
3186
2769
  decodeResult.message = message;
3187
- const parts = message.text.split(",");
3188
- if (parts.length === 10) {
3189
- const header = parts[0].split("FM4");
3190
- if (header.length == 0) {
3191
- ResultFormatter.unknown(decodeResult, message.text);
3192
- decodeResult.decoded = false;
3193
- decodeResult.decoder.decodeLevel = "none";
3194
- return decodeResult;
3195
- }
3196
- if (header[0].length > 0) {
3197
- ResultFormatter.unknown(decodeResult, header[0].substring(0, 4));
3198
- ResultFormatter.flightNumber(decodeResult, header[0].substring(4));
2770
+ const data = message.text.split(",");
2771
+ if (data.length >= 7) {
2772
+ if (options.debug) {
2773
+ console.log("Label 44 In Air Report: groups");
2774
+ console.log(data);
3199
2775
  }
3200
- ResultFormatter.departureAirport(decodeResult, header[1]);
3201
- ResultFormatter.arrivalAirport(decodeResult, parts[1]);
3202
- ResultFormatter.day(decodeResult, Number(parts[2].substring(0, 2)));
3203
- ResultFormatter.time_of_day(
2776
+ ResultFormatter.position(
3204
2777
  decodeResult,
3205
- DateTimeUtils.convertHHMMSSToTod(parts[2].substring(2))
2778
+ CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[1])
3206
2779
  );
3207
- ResultFormatter.eta(
2780
+ ResultFormatter.departureAirport(decodeResult, data[2]);
2781
+ ResultFormatter.arrivalAirport(decodeResult, data[3]);
2782
+ ResultFormatter.month(decodeResult, Number(data[4].substring(0, 2)));
2783
+ ResultFormatter.day(decodeResult, Number(data[4].substring(2, 4)));
2784
+ ResultFormatter.in(
3208
2785
  decodeResult,
3209
- DateTimeUtils.convertHHMMSSToTod(parts[3])
2786
+ DateTimeUtils.convertHHMMSSToTod(data[5])
3210
2787
  );
3211
- ResultFormatter.position(decodeResult, {
3212
- latitude: Number(parts[4].replaceAll(" ", "")),
3213
- longitude: Number(parts[5].replaceAll(" ", ""))
3214
- });
3215
- ResultFormatter.altitude(decodeResult, Number(parts[6]));
3216
- ResultFormatter.heading(decodeResult, Number(parts[7]));
3217
- ResultFormatter.unknown(decodeResult, parts[8]);
3218
- ResultFormatter.unknown(decodeResult, parts[9]);
3219
- decodeResult.decoded = true;
3220
- decodeResult.decoder.decodeLevel = "partial";
3221
- } else {
3222
- if (options.debug) {
3223
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
3224
- }
3225
- ResultFormatter.unknown(decodeResult, message.text);
3226
- decodeResult.decoded = false;
3227
- decodeResult.decoder.decodeLevel = "none";
3228
- }
3229
- return decodeResult;
3230
- }
3231
- };
3232
-
3233
- // lib/plugins/Label_2P_FM5.ts
3234
- var Label_2P_FM5 = class extends DecoderPlugin {
3235
- name = "label-2p-fm5";
3236
- qualifiers() {
3237
- return {
3238
- labels: ["2P"]
3239
- };
3240
- }
3241
- decode(message, options = {}) {
3242
- let decodeResult = this.defaultResult();
3243
- decodeResult.decoder.name = this.name;
3244
- decodeResult.formatted.description = "Flight Report";
3245
- decodeResult.message = message;
3246
- const parts = message.text.split(",");
3247
- if (parts.length === 12) {
3248
- const header = parts[0].split("FM5 ");
3249
- if (header.length == 0) {
3250
- ResultFormatter.unknown(decodeResult, message.text);
3251
- decodeResult.decoded = false;
3252
- decodeResult.decoder.decodeLevel = "none";
3253
- return decodeResult;
2788
+ const fuel = Number(data[6]);
2789
+ if (!isNaN(fuel)) {
2790
+ ResultFormatter.remainingFuel(decodeResult, Number(fuel));
3254
2791
  }
3255
- ResultFormatter.departureAirport(decodeResult, header[1]);
3256
- ResultFormatter.arrivalAirport(decodeResult, parts[1]);
3257
- ResultFormatter.time_of_day(
3258
- decodeResult,
3259
- DateTimeUtils.convertHHMMSSToTod(parts[2])
3260
- );
3261
- ResultFormatter.eta(
3262
- decodeResult,
3263
- DateTimeUtils.convertHHMMSSToTod(parts[3])
3264
- );
3265
- ResultFormatter.position(decodeResult, {
3266
- latitude: Number(parts[4].replaceAll(" ", "")),
3267
- longitude: Number(parts[5].replaceAll(" ", ""))
3268
- });
3269
- ResultFormatter.altitude(decodeResult, Number(parts[6]));
3270
- ResultFormatter.unknown(decodeResult, parts[7]);
3271
- ResultFormatter.unknown(decodeResult, parts[8]);
3272
- ResultFormatter.unknown(decodeResult, parts[9]);
3273
- ResultFormatter.flightNumber(decodeResult, parts[10].trim());
3274
- ResultFormatter.unknown(decodeResult, parts[11]);
3275
- decodeResult.decoded = true;
3276
- decodeResult.decoder.decodeLevel = "partial";
3277
- } else {
3278
- if (options.debug) {
3279
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
2792
+ if (data.length > 7) {
2793
+ ResultFormatter.unknownArr(decodeResult, data.slice(7));
3280
2794
  }
3281
- ResultFormatter.unknown(decodeResult, message.text);
3282
- decodeResult.decoded = false;
3283
- decodeResult.decoder.decodeLevel = "none";
3284
- }
3285
- return decodeResult;
3286
- }
3287
- };
3288
-
3289
- // lib/plugins/Label_2P_POS.ts
3290
- var Label_2P_POS = class extends DecoderPlugin {
3291
- name = "label-2p-pos";
3292
- qualifiers() {
3293
- return {
3294
- labels: ["2P"]
3295
- };
3296
- }
3297
- decode(message, options = {}) {
3298
- let decodeResult = this.defaultResult();
3299
- decodeResult.decoder.name = this.name;
3300
- decodeResult.message = message;
3301
- const msg = message.text.replace(/\n|\r/g, "");
3302
- const parts = msg.split("/");
3303
- let decoded = false;
3304
- if (parts[0].length > 3) {
3305
- decoded = H1Helper.decodeH1Message(
3306
- decodeResult,
3307
- msg.slice(parts[0].length - 3)
3308
- );
3309
- decodeResult.remaining.text = parts[0].slice(0, 3) + "/" + decodeResult.remaining.text;
3310
2795
  } else {
3311
- decoded = H1Helper.decodeH1Message(decodeResult, msg);
3312
- }
3313
- decodeResult.decoded = decoded;
3314
- decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
3315
- if (decodeResult.formatted.items.length === 0) {
3316
2796
  if (options.debug) {
3317
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
2797
+ console.log(`Decoder: Unknown 44 message: ${message.text}`);
3318
2798
  }
3319
2799
  ResultFormatter.unknown(decodeResult, message.text);
3320
2800
  decodeResult.decoded = false;
3321
2801
  decodeResult.decoder.decodeLevel = "none";
3322
- }
3323
- return decodeResult;
3324
- }
3325
- };
3326
-
3327
- // lib/plugins/Label_24_Slash.ts
3328
- var Label_24_Slash = class extends DecoderPlugin {
3329
- name = "label-24-slash";
3330
- qualifiers() {
3331
- return {
3332
- labels: ["24"],
3333
- preambles: ["/"]
3334
- };
3335
- }
3336
- decode(message, options = {}) {
3337
- const decodeResult = this.defaultResult();
3338
- decodeResult.decoder.name = this.name;
3339
- decodeResult.formatted.description = "Position Report";
3340
- decodeResult.message = message;
3341
- const fields = message.text.split("/");
3342
- if (fields.length == 10 && fields[0] == "" && fields[9] == "") {
3343
- const ddmmyy = fields[1].substring(2, 4) + fields[1].substring(4, 6) + fields[1].substring(0, 2);
3344
- const hhmmss = fields[2] + "00";
3345
- decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(
3346
- hhmmss,
3347
- ddmmyy
3348
- );
3349
- ResultFormatter.flightNumber(decodeResult, fields[3]);
3350
- ResultFormatter.altitude(decodeResult, Number(fields[4]));
3351
- const lat = fields[5];
3352
- const lon = fields[6];
3353
- const position = {
3354
- latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1)),
3355
- longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1))
3356
- };
3357
- ResultFormatter.position(decodeResult, position);
3358
- ResultFormatter.eta(
3359
- decodeResult,
3360
- DateTimeUtils.convertHHMMSSToTod(fields[8])
3361
- );
3362
- ResultFormatter.unknown(decodeResult, fields[7]);
3363
- decodeResult.decoded = true;
3364
- decodeResult.decoder.decodeLevel = "partial";
3365
- } else {
3366
- if (options.debug) {
3367
- console.log(
3368
- `DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}. Message: ${message.text}`
3369
- );
3370
- }
3371
- decodeResult.decoded = false;
3372
- decodeResult.decoder.decodeLevel = "none";
3373
- }
3374
- return decodeResult;
3375
- }
3376
- };
3377
-
3378
- // lib/plugins/Label_30_Slash_EA.ts
3379
- var Label_30_Slash_EA = class extends DecoderPlugin {
3380
- name = "label-30-slash-ea";
3381
- qualifiers() {
3382
- return {
3383
- labels: ["30"],
3384
- preambles: ["/EA"]
3385
- };
3386
- }
3387
- decode(message, options = {}) {
3388
- const decodeResult = this.defaultResult();
3389
- decodeResult.decoder.name = this.name;
3390
- decodeResult.formatted.description = "ETA Report";
3391
- decodeResult.message = message;
3392
- const results = message.text.split(/\n|\//).slice(1);
3393
- if (results) {
3394
- if (options.debug) {
3395
- console.log("Label 30 EA: results");
3396
- console.log(results);
3397
- }
3398
- }
3399
- ResultFormatter.eta(
3400
- decodeResult,
3401
- DateTimeUtils.convertHHMMSSToTod(results[0].substr(2, 4))
3402
- );
3403
- if (results[1].substring(0, 2) === "DS") {
3404
- ResultFormatter.arrivalAirport(decodeResult, results[1].substring(2, 6));
3405
- ResultFormatter.unknown(decodeResult, "/".concat(results[2]));
3406
- } else {
3407
- ResultFormatter.unknown(
3408
- decodeResult,
3409
- "/".concat(results[1], "/", results[2])
3410
- );
2802
+ return decodeResult;
3411
2803
  }
3412
2804
  decodeResult.decoded = true;
3413
- decodeResult.decoder.decodeLevel = "partial";
2805
+ decodeResult.decoder.decodeLevel = "full";
3414
2806
  return decodeResult;
3415
2807
  }
3416
2808
  };
3417
2809
 
3418
- // lib/plugins/Label_44_ETA.ts
3419
- var Label_44_ETA = class extends DecoderPlugin {
3420
- name = "label-44-eta";
2810
+ // lib/plugins/Label_44_OFF.ts
2811
+ var Label_44_OFF = class extends DecoderPlugin {
2812
+ name = "label-44-off";
3421
2813
  qualifiers() {
3422
2814
  return {
3423
2815
  labels: ["44"],
3424
- preambles: ["00ETA01", "00ETA02", "00ETA03", "ETA01", "ETA02", "ETA03"]
2816
+ preambles: ["00OFF01", "00OFF02", "00OFF03", "OFF01", "OFF02", "OFF03"]
3425
2817
  };
3426
2818
  }
3427
2819
  decode(message, options = {}) {
3428
2820
  const decodeResult = this.defaultResult();
3429
2821
  decodeResult.decoder.name = this.name;
3430
- decodeResult.formatted.description = "ETA Report";
2822
+ decodeResult.formatted.description = "Off Runway Report";
3431
2823
  decodeResult.message = message;
3432
2824
  const data = message.text.split(",");
3433
- if (data.length >= 9) {
2825
+ if (data.length >= 8) {
3434
2826
  if (options.debug) {
3435
- console.log("Label 44 ETA Report: groups");
2827
+ console.log("Label 44 Off Runway Report: groups");
3436
2828
  console.log(data);
3437
2829
  }
3438
2830
  ResultFormatter.position(
3439
2831
  decodeResult,
3440
2832
  CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[1])
3441
2833
  );
3442
- ResultFormatter.altitude(decodeResult, 100 * Number(data[2]));
3443
- ResultFormatter.departureAirport(decodeResult, data[3]);
3444
- ResultFormatter.arrivalAirport(decodeResult, data[4]);
3445
- ResultFormatter.month(decodeResult, Number(data[5].substring(0, 2)));
3446
- ResultFormatter.day(decodeResult, Number(data[5].substring(2, 4)));
3447
- ResultFormatter.time_of_day(
2834
+ ResultFormatter.departureAirport(decodeResult, data[2]);
2835
+ ResultFormatter.arrivalAirport(decodeResult, data[3]);
2836
+ ResultFormatter.month(decodeResult, Number(data[4].substring(0, 2)));
2837
+ ResultFormatter.day(decodeResult, Number(data[4].substring(2, 4)));
2838
+ ResultFormatter.off(
3448
2839
  decodeResult,
3449
- DateTimeUtils.convertHHMMSSToTod(data[6])
2840
+ DateTimeUtils.convertHHMMSSToTod(data[5])
3450
2841
  );
3451
2842
  ResultFormatter.eta(
3452
2843
  decodeResult,
3453
- DateTimeUtils.convertHHMMSSToTod(data[7])
2844
+ DateTimeUtils.convertHHMMSSToTod(data[6])
3454
2845
  );
3455
- const fuel = Number(data[8]);
2846
+ const fuel = Number(data[7]);
3456
2847
  if (!isNaN(fuel)) {
3457
2848
  ResultFormatter.remainingFuel(decodeResult, Number(fuel));
3458
2849
  }
3459
- if (data.length > 9) {
3460
- ResultFormatter.unknownArr(decodeResult, data.slice(9));
2850
+ if (data.length > 8) {
2851
+ ResultFormatter.unknownArr(decodeResult, data.slice(8));
3461
2852
  }
3462
2853
  } else {
3463
2854
  if (options.debug) {
@@ -3474,24 +2865,24 @@ var Label_44_ETA = class extends DecoderPlugin {
3474
2865
  }
3475
2866
  };
3476
2867
 
3477
- // lib/plugins/Label_44_IN.ts
3478
- var Label_44_IN = class extends DecoderPlugin {
3479
- name = "label-44-in";
2868
+ // lib/plugins/Label_44_ON.ts
2869
+ var Label_44_ON = class extends DecoderPlugin {
2870
+ name = "label-44-on";
3480
2871
  qualifiers() {
3481
2872
  return {
3482
2873
  labels: ["44"],
3483
- preambles: ["00IN01", "00IN02", "00IN03", "IN01", "IN02", "IN03"]
2874
+ preambles: ["00ON01", "00ON02", "00ON03", "ON01", "ON02", "ON03"]
3484
2875
  };
3485
2876
  }
3486
2877
  decode(message, options = {}) {
3487
2878
  const decodeResult = this.defaultResult();
3488
2879
  decodeResult.decoder.name = this.name;
3489
- decodeResult.formatted.description = "In Air Report";
2880
+ decodeResult.formatted.description = "On Runway Report";
3490
2881
  decodeResult.message = message;
3491
2882
  const data = message.text.split(",");
3492
2883
  if (data.length >= 7) {
3493
2884
  if (options.debug) {
3494
- console.log("Label 44 In Air Report: groups");
2885
+ console.log("Label 44 On Runway Report: groups");
3495
2886
  console.log(data);
3496
2887
  }
3497
2888
  ResultFormatter.position(
@@ -3502,7 +2893,7 @@ var Label_44_IN = class extends DecoderPlugin {
3502
2893
  ResultFormatter.arrivalAirport(decodeResult, data[3]);
3503
2894
  ResultFormatter.month(decodeResult, Number(data[4].substring(0, 2)));
3504
2895
  ResultFormatter.day(decodeResult, Number(data[4].substring(2, 4)));
3505
- ResultFormatter.in(
2896
+ ResultFormatter.on(
3506
2897
  decodeResult,
3507
2898
  DateTimeUtils.convertHHMMSSToTod(data[5])
3508
2899
  );
@@ -3528,125 +2919,13 @@ var Label_44_IN = class extends DecoderPlugin {
3528
2919
  }
3529
2920
  };
3530
2921
 
3531
- // lib/plugins/Label_44_OFF.ts
3532
- var Label_44_OFF = class extends DecoderPlugin {
3533
- name = "label-44-off";
2922
+ // lib/plugins/Label_44_POS.ts
2923
+ var Label_44_POS = class extends DecoderPlugin {
2924
+ name = "label-44-pos";
3534
2925
  qualifiers() {
3535
2926
  return {
3536
2927
  labels: ["44"],
3537
- preambles: ["00OFF01", "00OFF02", "00OFF03", "OFF01", "OFF02", "OFF03"]
3538
- };
3539
- }
3540
- decode(message, options = {}) {
3541
- const decodeResult = this.defaultResult();
3542
- decodeResult.decoder.name = this.name;
3543
- decodeResult.formatted.description = "Off Runway Report";
3544
- decodeResult.message = message;
3545
- const data = message.text.split(",");
3546
- if (data.length >= 8) {
3547
- if (options.debug) {
3548
- console.log("Label 44 Off Runway Report: groups");
3549
- console.log(data);
3550
- }
3551
- ResultFormatter.position(
3552
- decodeResult,
3553
- CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[1])
3554
- );
3555
- ResultFormatter.departureAirport(decodeResult, data[2]);
3556
- ResultFormatter.arrivalAirport(decodeResult, data[3]);
3557
- ResultFormatter.month(decodeResult, Number(data[4].substring(0, 2)));
3558
- ResultFormatter.day(decodeResult, Number(data[4].substring(2, 4)));
3559
- ResultFormatter.off(
3560
- decodeResult,
3561
- DateTimeUtils.convertHHMMSSToTod(data[5])
3562
- );
3563
- ResultFormatter.eta(
3564
- decodeResult,
3565
- DateTimeUtils.convertHHMMSSToTod(data[6])
3566
- );
3567
- const fuel = Number(data[7]);
3568
- if (!isNaN(fuel)) {
3569
- ResultFormatter.remainingFuel(decodeResult, Number(fuel));
3570
- }
3571
- if (data.length > 8) {
3572
- ResultFormatter.unknownArr(decodeResult, data.slice(8));
3573
- }
3574
- } else {
3575
- if (options.debug) {
3576
- console.log(`Decoder: Unknown 44 message: ${message.text}`);
3577
- }
3578
- ResultFormatter.unknown(decodeResult, message.text);
3579
- decodeResult.decoded = false;
3580
- decodeResult.decoder.decodeLevel = "none";
3581
- return decodeResult;
3582
- }
3583
- decodeResult.decoded = true;
3584
- decodeResult.decoder.decodeLevel = "full";
3585
- return decodeResult;
3586
- }
3587
- };
3588
-
3589
- // lib/plugins/Label_44_ON.ts
3590
- var Label_44_ON = class extends DecoderPlugin {
3591
- name = "label-44-on";
3592
- qualifiers() {
3593
- return {
3594
- labels: ["44"],
3595
- preambles: ["00ON01", "00ON02", "00ON03", "ON01", "ON02", "ON03"]
3596
- };
3597
- }
3598
- decode(message, options = {}) {
3599
- const decodeResult = this.defaultResult();
3600
- decodeResult.decoder.name = this.name;
3601
- decodeResult.formatted.description = "On Runway Report";
3602
- decodeResult.message = message;
3603
- const data = message.text.split(",");
3604
- if (data.length >= 7) {
3605
- if (options.debug) {
3606
- console.log("Label 44 On Runway Report: groups");
3607
- console.log(data);
3608
- }
3609
- ResultFormatter.position(
3610
- decodeResult,
3611
- CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[1])
3612
- );
3613
- ResultFormatter.departureAirport(decodeResult, data[2]);
3614
- ResultFormatter.arrivalAirport(decodeResult, data[3]);
3615
- ResultFormatter.month(decodeResult, Number(data[4].substring(0, 2)));
3616
- ResultFormatter.day(decodeResult, Number(data[4].substring(2, 4)));
3617
- ResultFormatter.on(
3618
- decodeResult,
3619
- DateTimeUtils.convertHHMMSSToTod(data[5])
3620
- );
3621
- const fuel = Number(data[6]);
3622
- if (!isNaN(fuel)) {
3623
- ResultFormatter.remainingFuel(decodeResult, Number(fuel));
3624
- }
3625
- if (data.length > 7) {
3626
- ResultFormatter.unknownArr(decodeResult, data.slice(7));
3627
- }
3628
- } else {
3629
- if (options.debug) {
3630
- console.log(`Decoder: Unknown 44 message: ${message.text}`);
3631
- }
3632
- ResultFormatter.unknown(decodeResult, message.text);
3633
- decodeResult.decoded = false;
3634
- decodeResult.decoder.decodeLevel = "none";
3635
- return decodeResult;
3636
- }
3637
- decodeResult.decoded = true;
3638
- decodeResult.decoder.decodeLevel = "full";
3639
- return decodeResult;
3640
- }
3641
- };
3642
-
3643
- // lib/plugins/Label_44_POS.ts
3644
- var Label_44_POS = class extends DecoderPlugin {
3645
- name = "label-44-pos";
3646
- qualifiers() {
3647
- return {
3648
- labels: ["44"],
3649
- preambles: ["00POS01", "00POS02", "00POS03", "POS01", "POS02", "POS03"]
2928
+ preambles: ["00POS01", "00POS02", "00POS03", "POS01", "POS02", "POS03"]
3650
2929
  };
3651
2930
  }
3652
2931
  decode(message, options = {}) {
@@ -3700,60 +2979,236 @@ var Label_44_POS = class extends DecoderPlugin {
3700
2979
  }
3701
2980
  };
3702
2981
 
3703
- // lib/plugins/Label_44_Slash.ts
3704
- var Label_44_Slash = class extends DecoderPlugin {
3705
- name = "label-44-slash";
3706
- qualifiers() {
3707
- return {
3708
- labels: ["44"],
3709
- preambles: [" /FB"]
3710
- };
3711
- }
3712
- decode(message, options = {}) {
3713
- const decodeResult = this.defaultResult();
3714
- decodeResult.decoder.name = this.name;
3715
- decodeResult.formatted.description = "Flight Briefing";
3716
- decodeResult.message = message;
3717
- const fields = message.text.split("/");
3718
- if (fields.length !== 4) {
3719
- if (options.debug) {
3720
- console.log(`Decoder: Unknown 44 message: ${message.text}`);
2982
+ // lib/utils/flight_plan_utils.ts
2983
+ var FlightPlanUtils = class _FlightPlanUtils {
2984
+ /**
2985
+ * Processes flight plan data
2986
+ *
2987
+ * Expected format is [header, fpei, val1, ... fpeiN, valN]
2988
+ *
2989
+ * @see https://atlaske-content.garmin.com/filestorage//email/outbound/attachments/GTN_Flight_Plan_and_User_Waypoint_transfer_Time1712844670119.pdf
2990
+ * @param decodeResult - results
2991
+ * @param data - original message split by ':'
2992
+ * @returns whether all fields were processed or not
2993
+ */
2994
+ static processFlightPlan(decodeResult, data) {
2995
+ let allKnownFields = _FlightPlanUtils.parseHeader(decodeResult, data[0]);
2996
+ for (let i = 1; i < data.length; i += 2) {
2997
+ const fpei = data[i];
2998
+ const value = data[i + 1];
2999
+ switch (fpei) {
3000
+ case "A":
3001
+ _FlightPlanUtils.addProcedure(decodeResult, value, "arrival");
3002
+ break;
3003
+ case "AA":
3004
+ addArrivalAirport(decodeResult, value);
3005
+ break;
3006
+ case "AP":
3007
+ _FlightPlanUtils.addProcedure(decodeResult, value, "approach");
3008
+ break;
3009
+ case "CR":
3010
+ addCompanyRoute(decodeResult, value);
3011
+ break;
3012
+ case "D":
3013
+ _FlightPlanUtils.addProcedure(decodeResult, value, "departure");
3014
+ break;
3015
+ case "DA":
3016
+ addDepartureAirport(decodeResult, value);
3017
+ break;
3018
+ case "F":
3019
+ addRoute(decodeResult, value);
3020
+ break;
3021
+ case "FP":
3022
+ ResultFormatter.flightPlan(decodeResult, value.trim());
3023
+ break;
3024
+ case "R":
3025
+ addRunway(decodeResult, value);
3026
+ break;
3027
+ // case 'WS': // something about routes, has altitude, so current parsing won't work
3028
+ // break;
3029
+ default:
3030
+ if (allKnownFields) {
3031
+ decodeResult.remaining.text = "";
3032
+ allKnownFields = false;
3033
+ }
3034
+ decodeResult.remaining.text += `:${fpei}:${value}`;
3035
+ decodeResult.decoder.decodeLevel = "partial";
3721
3036
  }
3722
- ResultFormatter.unknown(decodeResult, message.text);
3723
- decodeResult.decoded = false;
3724
- decodeResult.decoder.decodeLevel = "none";
3725
- return decodeResult;
3726
3037
  }
3727
- ResultFormatter.unknownArr(decodeResult, fields.slice(0, 2), "/");
3728
- const data = fields[3].split(",");
3729
- if (data.length >= 6) {
3730
- if (options.debug) {
3731
- console.log("Label 44 Slash: groups");
3732
- console.log(data);
3733
- }
3734
- ResultFormatter.position(decodeResult, {
3735
- latitude: (data[0].charAt(0) === "S" ? -1 : 1) * parseFloat(data[0].slice(1).trim()),
3736
- longitude: (data[1].charAt(0) === "W" ? -1 : 1) * parseFloat(data[1].slice(1).trim())
3038
+ return allKnownFields;
3039
+ }
3040
+ static parseHeader(decodeResult, header) {
3041
+ let allKnownFields = true;
3042
+ if (header.startsWith("RF")) {
3043
+ decodeResult.formatted.items.push({
3044
+ type: "status",
3045
+ code: "ROUTE_STATUS",
3046
+ label: "Route Status",
3047
+ value: "Route Filed"
3737
3048
  });
3738
- ResultFormatter.flightNumber(decodeResult, data[2]);
3739
- ResultFormatter.unknown(decodeResult, data[3]);
3740
- ResultFormatter.arrivalAirport(decodeResult, data[4]);
3741
- ResultFormatter.eta(
3742
- decodeResult,
3743
- DateTimeUtils.convertHHMMSSToTod(data[5])
3744
- );
3745
- if (data.length === 18) {
3746
- ResultFormatter.unknownArr(decodeResult, data.slice(6, 8), ",");
3747
- ResultFormatter.remainingFuel(decodeResult, parseFloat(data[8]));
3748
- ResultFormatter.unknownArr(decodeResult, data.slice(9, 11), ",");
3749
- ResultFormatter.arrivalRunway(decodeResult, data[11]);
3750
- FlightPlanUtils.addProcedure(decodeResult, data[12], "arrival");
3751
- ResultFormatter.unknownArr(decodeResult, data.slice(13, 18), ",");
3049
+ decodeResult.raw.route_status = "RF";
3050
+ if (header.length > 2) {
3051
+ addRoute(decodeResult, header.substring(2));
3752
3052
  }
3053
+ } else if (header.startsWith("RP")) {
3054
+ decodeResult.raw.route_status = "RP";
3055
+ decodeResult.formatted.items.push({
3056
+ type: "status",
3057
+ code: "ROUTE_STATUS",
3058
+ label: "Route Status",
3059
+ value: "Route Planned"
3060
+ });
3061
+ decodeResult.raw.route_status = header;
3062
+ } else if (header.startsWith("RI")) {
3063
+ decodeResult.raw.route_status = "RI";
3064
+ decodeResult.formatted.items.push({
3065
+ type: "status",
3066
+ code: "ROUTE_STATUS",
3067
+ label: "Route Status",
3068
+ value: "Route Inactive"
3069
+ });
3070
+ } else if (header.startsWith("RM")) {
3071
+ decodeResult.raw.route_status = "RM";
3072
+ decodeResult.formatted.items.push({
3073
+ type: "status",
3074
+ code: "ROUTE_STATUS",
3075
+ label: "Route Status",
3076
+ value: "Route Mapped"
3077
+ });
3078
+ } else if (header.startsWith("RS")) {
3079
+ decodeResult.raw.route_status = "RS";
3080
+ decodeResult.formatted.items.push({
3081
+ type: "status",
3082
+ code: "ROUTE_STATUS",
3083
+ label: "Route Status",
3084
+ value: "Route Saved"
3085
+ });
3753
3086
  } else {
3754
- if (options.debug) {
3755
- console.log(`Decoder: Unknown 44 message: ${message.text}`);
3756
- }
3087
+ decodeResult.remaining.text += header;
3088
+ allKnownFields = false;
3089
+ }
3090
+ return allKnownFields;
3091
+ }
3092
+ static addProcedure(decodeResult, value, type) {
3093
+ if (decodeResult.raw.procedures === void 0) {
3094
+ decodeResult.raw.procedures = [];
3095
+ }
3096
+ const data = value.split(".");
3097
+ let waypoints;
3098
+ if (data.length > 1) {
3099
+ waypoints = data.slice(1).map((leg) => RouteUtils.getWaypoint(leg));
3100
+ }
3101
+ const route = { name: data[0], waypoints };
3102
+ decodeResult.raw.procedures.push({ type, route });
3103
+ const procedureName = type.substring(0, 1).toUpperCase() + type.slice(1);
3104
+ decodeResult.formatted.items.push({
3105
+ type: "procedure",
3106
+ code: "proc",
3107
+ label: `${procedureName} Procedure`,
3108
+ value: RouteUtils.routeToString(route)
3109
+ });
3110
+ }
3111
+ };
3112
+ function addArrivalAirport(decodeResult, value) {
3113
+ ResultFormatter.arrivalAirport(decodeResult, value);
3114
+ }
3115
+ function addDepartureAirport(decodeResult, value) {
3116
+ ResultFormatter.departureAirport(decodeResult, value);
3117
+ }
3118
+ function addRunway(decodeResult, value) {
3119
+ if (value.length === 8) {
3120
+ ResultFormatter.arrivalRunway(decodeResult, value.substring(4, 7));
3121
+ }
3122
+ ResultFormatter.departureRunway(decodeResult, value.substring(0, 3));
3123
+ }
3124
+ function addRoute(decodeResult, value) {
3125
+ const route = value.split(".");
3126
+ ResultFormatter.route(decodeResult, {
3127
+ waypoints: route.map((leg) => RouteUtils.getWaypoint(leg))
3128
+ });
3129
+ }
3130
+ function addCompanyRoute(decodeResult, value) {
3131
+ const segments = value.split(".");
3132
+ const parens_idx = segments[0].indexOf("(");
3133
+ let name;
3134
+ let runway;
3135
+ if (parens_idx === -1) {
3136
+ name = segments[0];
3137
+ } else {
3138
+ name = segments[0].slice(0, parens_idx);
3139
+ runway = segments[0].slice(parens_idx + 1, segments[0].indexOf(")"));
3140
+ }
3141
+ let waypoints;
3142
+ if (segments.length > 1) {
3143
+ waypoints = segments.slice(1).map((leg) => RouteUtils.getWaypoint(leg));
3144
+ }
3145
+ decodeResult.raw.company_route = {
3146
+ name,
3147
+ runway,
3148
+ waypoints
3149
+ };
3150
+ decodeResult.formatted.items.push({
3151
+ type: "company_route",
3152
+ code: "CR",
3153
+ label: "Company Route",
3154
+ value: RouteUtils.routeToString(decodeResult.raw.company_route)
3155
+ });
3156
+ }
3157
+
3158
+ // lib/plugins/Label_44_Slash.ts
3159
+ var Label_44_Slash = class extends DecoderPlugin {
3160
+ name = "label-44-slash";
3161
+ qualifiers() {
3162
+ return {
3163
+ labels: ["44"],
3164
+ preambles: [" /FB"]
3165
+ };
3166
+ }
3167
+ decode(message, options = {}) {
3168
+ const decodeResult = this.defaultResult();
3169
+ decodeResult.decoder.name = this.name;
3170
+ decodeResult.formatted.description = "Flight Briefing";
3171
+ decodeResult.message = message;
3172
+ const fields = message.text.split("/");
3173
+ if (fields.length !== 4) {
3174
+ if (options.debug) {
3175
+ console.log(`Decoder: Unknown 44 message: ${message.text}`);
3176
+ }
3177
+ ResultFormatter.unknown(decodeResult, message.text);
3178
+ decodeResult.decoded = false;
3179
+ decodeResult.decoder.decodeLevel = "none";
3180
+ return decodeResult;
3181
+ }
3182
+ ResultFormatter.unknownArr(decodeResult, fields.slice(0, 2), "/");
3183
+ const data = fields[3].split(",");
3184
+ if (data.length >= 6) {
3185
+ if (options.debug) {
3186
+ console.log("Label 44 Slash: groups");
3187
+ console.log(data);
3188
+ }
3189
+ ResultFormatter.position(decodeResult, {
3190
+ latitude: (data[0].charAt(0) === "S" ? -1 : 1) * parseFloat(data[0].slice(1).trim()),
3191
+ longitude: (data[1].charAt(0) === "W" ? -1 : 1) * parseFloat(data[1].slice(1).trim())
3192
+ });
3193
+ ResultFormatter.flightNumber(decodeResult, data[2]);
3194
+ ResultFormatter.unknown(decodeResult, data[3]);
3195
+ ResultFormatter.arrivalAirport(decodeResult, data[4]);
3196
+ ResultFormatter.eta(
3197
+ decodeResult,
3198
+ DateTimeUtils.convertHHMMSSToTod(data[5])
3199
+ );
3200
+ if (data.length === 18) {
3201
+ ResultFormatter.unknownArr(decodeResult, data.slice(6, 8), ",");
3202
+ ResultFormatter.remainingFuel(decodeResult, parseFloat(data[8]));
3203
+ ResultFormatter.unknownArr(decodeResult, data.slice(9, 11), ",");
3204
+ ResultFormatter.arrivalRunway(decodeResult, data[11]);
3205
+ FlightPlanUtils.addProcedure(decodeResult, data[12], "arrival");
3206
+ ResultFormatter.unknownArr(decodeResult, data.slice(13, 18), ",");
3207
+ }
3208
+ } else {
3209
+ if (options.debug) {
3210
+ console.log(`Decoder: Unknown 44 message: ${message.text}`);
3211
+ }
3757
3212
  ResultFormatter.unknown(decodeResult, message.text);
3758
3213
  decodeResult.decoded = false;
3759
3214
  decodeResult.decoder.decodeLevel = "none";
@@ -3912,7 +3367,7 @@ var Label_4A_DIS = class extends DecoderPlugin {
3912
3367
  DateTimeUtils.convertHHMMSSToTod(fields[1].substring(2) + "00")
3913
3368
  );
3914
3369
  ResultFormatter.callsign(decodeResult, fields[2]);
3915
- ResultFormatter.freetext(decodeResult, fields.slice(3).join(""));
3370
+ ResultFormatter.text(decodeResult, fields.slice(3).join(""));
3916
3371
  if (decodeResult.decoded) {
3917
3372
  if (!decodeResult.remaining.text)
3918
3373
  decodeResult.decoder.decodeLevel = "full";
@@ -3997,38 +3452,6 @@ var Label_4A_Slash_01 = class extends DecoderPlugin {
3997
3452
  }
3998
3453
  };
3999
3454
 
4000
- // lib/plugins/Label_4J_POS.ts
4001
- var Label_4J_POS = class extends DecoderPlugin {
4002
- name = "label-4j-pos";
4003
- qualifiers() {
4004
- return {
4005
- labels: ["4J"],
4006
- preambles: ["POS/"]
4007
- };
4008
- }
4009
- // copied from Label_H1.ts since i don't really want to have to have
4010
- // something named like that decode more than 1 type
4011
- // if we figure out a good name, i'll combine them
4012
- decode(message, options = {}) {
4013
- let decodeResult = this.defaultResult();
4014
- decodeResult.decoder.name = this.name;
4015
- decodeResult.message = message;
4016
- const msg = message.text.replace(/\n|\r/g, "");
4017
- const decoded = H1Helper.decodeH1Message(decodeResult, msg);
4018
- decodeResult.decoded = decoded;
4019
- decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
4020
- if (decodeResult.formatted.items.length === 0) {
4021
- if (options.debug) {
4022
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
4023
- }
4024
- ResultFormatter.unknown(decodeResult, message.text);
4025
- decodeResult.decoded = false;
4026
- decodeResult.decoder.decodeLevel = "none";
4027
- }
4028
- return decodeResult;
4029
- }
4030
- };
4031
-
4032
3455
  // lib/plugins/Label_4N.ts
4033
3456
  var Label_4N = class extends DecoderPlugin {
4034
3457
  name = "label-4n";
@@ -4389,6 +3812,9 @@ var Label_80 = class extends DecoderPlugin {
4389
3812
  }
4390
3813
  parseCsvFormat(text, results) {
4391
3814
  const csvParts = text.split(",");
3815
+ if (csvParts.length !== 9) {
3816
+ return;
3817
+ }
4392
3818
  const header = csvParts[0].trim().split(/\s+/);
4393
3819
  ResultFormatter.unknown(results, header[0], " ");
4394
3820
  ResultFormatter.unknown(results, header[1], " ");
@@ -4470,101 +3896,645 @@ var Label_83 = class extends DecoderPlugin {
4470
3896
  ResultFormatter.unknown(decodeResult, text);
4471
3897
  }
4472
3898
  }
4473
- if (decodeResult.decoded) {
4474
- if (!decodeResult.remaining.text)
4475
- decodeResult.decoder.decodeLevel = "full";
4476
- else decodeResult.decoder.decodeLevel = "partial";
4477
- } else {
4478
- decodeResult.decoder.decodeLevel = "none";
3899
+ if (decodeResult.decoded) {
3900
+ if (!decodeResult.remaining.text)
3901
+ decodeResult.decoder.decodeLevel = "full";
3902
+ else decodeResult.decoder.decodeLevel = "partial";
3903
+ } else {
3904
+ decodeResult.decoder.decodeLevel = "none";
3905
+ }
3906
+ return decodeResult;
3907
+ }
3908
+ };
3909
+
3910
+ // lib/plugins/Label_8E.ts
3911
+ var Label_8E = class extends DecoderPlugin {
3912
+ name = "label-8e";
3913
+ qualifiers() {
3914
+ return {
3915
+ labels: ["8E"]
3916
+ };
3917
+ }
3918
+ decode(message, options = {}) {
3919
+ const decodeResult = this.defaultResult();
3920
+ decodeResult.decoder.name = this.name;
3921
+ decodeResult.formatted.description = "ETA Report";
3922
+ decodeResult.message = message;
3923
+ const regex = /^(?<arrival_icao>\w{4}),(?<arrival_eta>\d{4})$/;
3924
+ const results = message.text.match(regex);
3925
+ if (results?.groups) {
3926
+ if (options.debug) {
3927
+ console.log("Label 8E ETA: groups");
3928
+ console.log(results.groups);
3929
+ }
3930
+ ResultFormatter.eta(
3931
+ decodeResult,
3932
+ DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta)
3933
+ );
3934
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
3935
+ }
3936
+ decodeResult.decoded = true;
3937
+ decodeResult.decoder.decodeLevel = "full";
3938
+ return decodeResult;
3939
+ }
3940
+ };
3941
+
3942
+ // lib/plugins/Label_B6.ts
3943
+ var Label_B6_Forwardslash = class extends DecoderPlugin {
3944
+ name = "label-b6-forwardslash";
3945
+ qualifiers() {
3946
+ return {
3947
+ labels: ["B6"],
3948
+ preambles: ["/"]
3949
+ };
3950
+ }
3951
+ decode(message, options = {}) {
3952
+ const decodeResult = this.defaultResult();
3953
+ decodeResult.decoder.name = this.name;
3954
+ decodeResult.formatted.description = "CPDLC Message";
3955
+ decodeResult.message = message;
3956
+ if (options.debug) {
3957
+ console.log("CPDLC: " + message);
3958
+ }
3959
+ return decodeResult;
3960
+ }
3961
+ };
3962
+
3963
+ // lib/plugins/Label_ColonComma.ts
3964
+ var Label_ColonComma = class extends DecoderPlugin {
3965
+ name = "label-colon-comma";
3966
+ qualifiers() {
3967
+ return {
3968
+ labels: [":;"]
3969
+ };
3970
+ }
3971
+ decode(message, options = {}) {
3972
+ const decodeResult = this.defaultResult();
3973
+ decodeResult.decoder.name = this.name;
3974
+ decodeResult.raw.frequency = Number(message.text) / 1e3;
3975
+ decodeResult.formatted.description = "Aircraft Transceiver Frequency Change";
3976
+ decodeResult.formatted.items.push({
3977
+ type: "frequency",
3978
+ label: "Frequency",
3979
+ value: `${decodeResult.raw.frequency} MHz`,
3980
+ code: "FREQ"
3981
+ });
3982
+ decodeResult.decoded = true;
3983
+ decodeResult.decoder.decodeLevel = "full";
3984
+ return decodeResult;
3985
+ }
3986
+ };
3987
+
3988
+ // lib/utils/arinc_702_helper.ts
3989
+ var Arinc702Helper = class _Arinc702Helper {
3990
+ /**
3991
+ * Decodes an ARINC 702 message
3992
+ *
3993
+ * Steps:
3994
+ * 1. Check against known checksum algorithms to determine if message is valid
3995
+ * 2. Parse the Imbedded Message Identifier (IMI) to determine the type of message
3996
+ * 3. Iterate through the Information Elements (IEI) and decode known fields, while storing unknown fields for further analysis
3997
+ *
3998
+ * @param decodeResult - object to store decoded results in
3999
+ * @param message - message to decode
4000
+ * @returns boolean indicating if the message was successfully decoded
4001
+ */
4002
+ static decodeH1Message(decodeResult, message) {
4003
+ decodeResult.remaining.text = "";
4004
+ const checksum = parseInt(message.slice(-4), 16);
4005
+ const data = message.slice(0, message.length - 4);
4006
+ let checksumAlgorithmUsed = "";
4007
+ if (crc16IbmSdlcRev(data) === checksum) {
4008
+ checksumAlgorithmUsed = "IBM-SDLC reversed";
4009
+ } else if (crc16Genibus(data) === checksum) {
4010
+ checksumAlgorithmUsed = "GENIBUS";
4011
+ } else {
4012
+ decodeResult.decoded = false;
4013
+ decodeResult.decoder.decodeLevel = "none";
4014
+ return false;
4015
+ }
4016
+ const fields = data.split("/");
4017
+ const canDecode = parseMessageType(decodeResult, fields[0]);
4018
+ if (!canDecode) {
4019
+ decodeResult.decoded = false;
4020
+ decodeResult.decoder.decodeLevel = "none";
4021
+ return false;
4022
+ }
4023
+ for (let i = 1; i < fields.length; ++i) {
4024
+ const iei = fields[i].substring(0, 2);
4025
+ const data2 = fields[i].substring(2);
4026
+ switch (iei) {
4027
+ case "AF":
4028
+ processAirField(decodeResult, data2.split(","));
4029
+ break;
4030
+ case "AK":
4031
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
4032
+ break;
4033
+ case "CG":
4034
+ processCenterOfGravity(decodeResult, data2.split(","));
4035
+ break;
4036
+ case "DC":
4037
+ processDateCode(decodeResult, data2.split(","));
4038
+ break;
4039
+ case "DI":
4040
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
4041
+ break;
4042
+ case "DT":
4043
+ processDT(decodeResult, data2.split(","));
4044
+ break;
4045
+ case "DQ":
4046
+ ResultFormatter.desiredAltitude(
4047
+ decodeResult,
4048
+ parseInt(data2, 10) * 100
4049
+ );
4050
+ break;
4051
+ case "ET":
4052
+ processETA(data2, decodeResult, fields, i);
4053
+ break;
4054
+ case "FB":
4055
+ ResultFormatter.currentFuel(decodeResult, parseInt(data2, 10));
4056
+ break;
4057
+ case "FN":
4058
+ decodeResult.raw.flight_number = data2;
4059
+ break;
4060
+ case "FX":
4061
+ ResultFormatter.text(decodeResult, data2);
4062
+ break;
4063
+ case "GA":
4064
+ ResultFormatter.groundAddress(decodeResult, data2);
4065
+ break;
4066
+ case "ID":
4067
+ processIdentification(decodeResult, data2.split(","));
4068
+ break;
4069
+ case "LR":
4070
+ processLandingReport(decodeResult, data2.split(","));
4071
+ break;
4072
+ case "MR":
4073
+ processMessageReference(decodeResult, data2.split(","));
4074
+ break;
4075
+ case "PR":
4076
+ processPerformanceData(decodeResult, data2.split(","));
4077
+ break;
4078
+ //case 'PR':
4079
+ // TODO: decode /PR fields
4080
+ // ResultFormatter.unknown(decodeResult, fields[i], '/');
4081
+ // break;
4082
+ case "PS":
4083
+ _Arinc702Helper.processPS(decodeResult, data2.split(","));
4084
+ break;
4085
+ case "RF":
4086
+ case "RI":
4087
+ case "RM":
4088
+ case "RP":
4089
+ case "RS":
4090
+ FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
4091
+ break;
4092
+ case "RN":
4093
+ ResultFormatter.routeNumber(decodeResult, data2);
4094
+ break;
4095
+ case "RW":
4096
+ processRunway(decodeResult, data2.split(":"));
4097
+ break;
4098
+ case "SN":
4099
+ decodeResult.raw.serial_number = data2;
4100
+ break;
4101
+ case "SP":
4102
+ ResultFormatter.startPoint(decodeResult, data2);
4103
+ break;
4104
+ case "TD":
4105
+ processTimeOfDeparture(decodeResult, data2.split(","));
4106
+ break;
4107
+ case "TS":
4108
+ _Arinc702Helper.processTimeStamp(decodeResult, data2.split(","));
4109
+ break;
4110
+ case "VR":
4111
+ ResultFormatter.version(decodeResult, parseInt(data2, 10) / 10);
4112
+ break;
4113
+ case "WD":
4114
+ processWindData(decodeResult, data2);
4115
+ break;
4116
+ case "WQ":
4117
+ processWeatherQuery(decodeResult, data2.split(":"));
4118
+ break;
4119
+ default:
4120
+ console.log(`Unknown IEI ${iei} in H1 message, data: ${data2}`);
4121
+ console.log(`Remaing text: ${decodeResult.remaining.text}`);
4122
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
4123
+ }
4124
+ }
4125
+ ResultFormatter.checksumAlgorithm(decodeResult, checksumAlgorithmUsed);
4126
+ ResultFormatter.checksum(decodeResult, checksum);
4127
+ return true;
4128
+ }
4129
+ static processPS(decodeResult, data) {
4130
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
4131
+ data[0]
4132
+ );
4133
+ if (position) {
4134
+ ResultFormatter.position(decodeResult, position);
4135
+ }
4136
+ if (data.length === 9) {
4137
+ processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
4138
+ ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
4139
+ ResultFormatter.temperature(decodeResult, data[6]);
4140
+ ResultFormatter.unknown(decodeResult, data[7]);
4141
+ ResultFormatter.unknown(decodeResult, data[8]);
4142
+ }
4143
+ if (data.length === 14) {
4144
+ ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
4145
+ processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
4146
+ ResultFormatter.temperature(decodeResult, data[7]);
4147
+ ResultFormatter.unknownArr(decodeResult, data.slice(8));
4148
+ }
4149
+ }
4150
+ static processPosition(decodeResult, data) {
4151
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
4152
+ data[0]
4153
+ );
4154
+ if (position) {
4155
+ ResultFormatter.position(decodeResult, position);
4156
+ }
4157
+ if (data.length >= 10) {
4158
+ ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
4159
+ processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
4160
+ ResultFormatter.temperature(decodeResult, data[7]);
4161
+ ResultFormatter.unknown(decodeResult, data[8]);
4162
+ ResultFormatter.unknown(decodeResult, data[9]);
4163
+ }
4164
+ if (data.length >= 14) {
4165
+ ResultFormatter.unknownArr(decodeResult, data.slice(10));
4166
+ }
4167
+ }
4168
+ static processTimeStamp(decodeResult, data) {
4169
+ if (data.length > 2) {
4170
+ const positionData = data.slice(1);
4171
+ positionData[0] = positionData[0].substring(6);
4172
+ this.processPosition(decodeResult, positionData);
4173
+ }
4174
+ let time = DateTimeUtils.convertDateTimeToEpoch(
4175
+ data[0],
4176
+ data[1].substring(0, 6)
4177
+ );
4178
+ if (Number.isNaN(time)) {
4179
+ const date = data[1].substring(2, 4) + data[1].substring(0, 2) + data[1].substring(4, 6);
4180
+ time = DateTimeUtils.convertDateTimeToEpoch(data[0], date);
4181
+ }
4182
+ decodeResult.raw.message_timestamp = time;
4183
+ }
4184
+ };
4185
+ function processETA(data, decodeResult, fields, i) {
4186
+ if (data.length === 5) {
4187
+ ResultFormatter.day(decodeResult, Number(data.substring(0, 1)));
4188
+ ResultFormatter.eta(
4189
+ decodeResult,
4190
+ DateTimeUtils.convertHHMMSSToTod(data.substring(1))
4191
+ );
4192
+ } else if (data.length === 6) {
4193
+ ResultFormatter.day(decodeResult, Number(data.substring(0, 2)));
4194
+ ResultFormatter.eta(
4195
+ decodeResult,
4196
+ DateTimeUtils.convertHHMMSSToTod(data.substring(2))
4197
+ );
4198
+ } else {
4199
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
4200
+ }
4201
+ }
4202
+ function processAirField(decodeResult, data) {
4203
+ if (data.length === 2) {
4204
+ ResultFormatter.departureAirport(decodeResult, data[0]);
4205
+ ResultFormatter.arrivalAirport(decodeResult, data[1]);
4206
+ } else {
4207
+ ResultFormatter.unknown(decodeResult, data.join(","), "AF/");
4208
+ }
4209
+ }
4210
+ function processTimeOfDeparture(decodeResult, data) {
4211
+ if (data.length === 2) {
4212
+ decodeResult.raw.planned_departure_time = data[0];
4213
+ decodeResult.formatted.items.push({
4214
+ type: "ptd",
4215
+ code: "ptd",
4216
+ label: "Planned Departure Time",
4217
+ value: `YYYY-MM-${data[0].substring(0, 2)}T${data[0].substring(2, 4)}:${data[0].substring(4)}:00Z`
4218
+ });
4219
+ decodeResult.raw.estimated_departure_time = data[1];
4220
+ decodeResult.formatted.items.push({
4221
+ type: "etd",
4222
+ code: "etd",
4223
+ label: "Estimated Departure Time",
4224
+ value: `${data[1].substring(0, 2)}:${data[1].substring(2)}`
4225
+ });
4226
+ } else {
4227
+ ResultFormatter.unknown(decodeResult, data.join(","), "/TD");
4228
+ }
4229
+ }
4230
+ function processIdentification(decodeResult, data) {
4231
+ ResultFormatter.tail(decodeResult, data[0]);
4232
+ if (data.length > 1) {
4233
+ ResultFormatter.flightNumber(decodeResult, data[1]);
4234
+ }
4235
+ if (data.length > 2) {
4236
+ decodeResult.raw.mission_number = data[2];
4237
+ }
4238
+ }
4239
+ function processDT(decodeResult, data) {
4240
+ if (data.length === 9) {
4241
+ ResultFormatter.unknown(decodeResult, data[0]);
4242
+ if (!decodeResult.raw.arrival_icao) {
4243
+ ResultFormatter.arrivalAirport(decodeResult, data[1]);
4244
+ }
4245
+ ResultFormatter.arrivalRunway(decodeResult, data[2]);
4246
+ ResultFormatter.currentFuel(decodeResult, parseInt(data[3], 10));
4247
+ ResultFormatter.eta(
4248
+ decodeResult,
4249
+ DateTimeUtils.convertHHMMSSToTod(data[4])
4250
+ );
4251
+ ResultFormatter.unknown(decodeResult, data[5]);
4252
+ ResultFormatter.position(
4253
+ decodeResult,
4254
+ CoordinateUtils.decodeStringCoordinates(data[6])
4255
+ );
4256
+ ResultFormatter.unknown(decodeResult, data[7]);
4257
+ ResultFormatter.unknown(decodeResult, data[8]);
4258
+ return;
4259
+ }
4260
+ if (data.length === 4 || data.length === 5) {
4261
+ if (!decodeResult.raw.arrival_icao) {
4262
+ ResultFormatter.arrivalAirport(decodeResult, data[0]);
4263
+ }
4264
+ ResultFormatter.arrivalRunway(decodeResult, data[1]);
4265
+ ResultFormatter.currentFuel(decodeResult, parseInt(data[2], 10));
4266
+ ResultFormatter.eta(
4267
+ decodeResult,
4268
+ DateTimeUtils.convertHHMMSSToTod(data[3])
4269
+ );
4270
+ if (data.length > 4) {
4271
+ ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
4272
+ }
4273
+ return;
4274
+ }
4275
+ ResultFormatter.unknownArr(decodeResult, data, ",");
4276
+ }
4277
+ function processLandingReport(decodeResult, data) {
4278
+ if (data.length === 19) {
4279
+ ResultFormatter.unknown(decodeResult, data[1]);
4280
+ ResultFormatter.flightNumber(decodeResult, data[2]);
4281
+ ResultFormatter.departureAirport(decodeResult, data[3]);
4282
+ ResultFormatter.arrivalAirport(decodeResult, data[4]);
4283
+ ResultFormatter.arrivalRunway(decodeResult, data[5]);
4284
+ ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
4285
+ } else {
4286
+ ResultFormatter.unknown(decodeResult, data.join(","));
4287
+ }
4288
+ }
4289
+ function processCenterOfGravity(decodeResult, data) {
4290
+ if (data.length === 1) {
4291
+ if (data[0] !== void 0 && data[0] !== "") {
4292
+ ResultFormatter.cg(decodeResult, parseInt(data[0], 10) / 10);
4293
+ }
4294
+ } else if (data.length === 3) {
4295
+ if (data[0] !== void 0 && data[0] !== "") {
4296
+ ResultFormatter.cg(decodeResult, parseInt(data[0], 10) / 10, "center");
4297
+ }
4298
+ if (data[1] !== void 0 && data[1] !== "") {
4299
+ ResultFormatter.cg(decodeResult, parseInt(data[1], 10) / 10, "lower");
4300
+ }
4301
+ if (data[2] !== void 0 && data[2] !== "") {
4302
+ ResultFormatter.cg(decodeResult, parseInt(data[2], 10) / 10, "upper");
4303
+ }
4304
+ } else {
4305
+ ResultFormatter.unknown(decodeResult, data.join(","));
4306
+ }
4307
+ }
4308
+ function parseMessageType(decodeResult, messagePart) {
4309
+ const messageParts = messagePart.split(",");
4310
+ const messageType = messageParts[0];
4311
+ if (messageType.startsWith("POS")) {
4312
+ Arinc702Helper.processPosition(
4313
+ decodeResult,
4314
+ messagePart.substring(3).split(",")
4315
+ );
4316
+ return processIMI(decodeResult, "POS");
4317
+ } else if (messageType.length === 6) {
4318
+ const part1 = processIMI(decodeResult, messageType.substring(0, 3));
4319
+ const description = decodeResult.formatted.description;
4320
+ const part2 = processIMI(decodeResult, messageType.substring(3, 6));
4321
+ decodeResult.formatted.description = description + " for " + decodeResult.formatted.description;
4322
+ if (messageParts.length > 1) {
4323
+ ResultFormatter.unknown(
4324
+ decodeResult,
4325
+ messageParts.slice(1).join(","),
4326
+ "/"
4327
+ );
4328
+ }
4329
+ return part1 && part2;
4330
+ }
4331
+ if (messageParts.length > 1) {
4332
+ ResultFormatter.unknown(decodeResult, messageParts.slice(1).join(","), "/");
4333
+ }
4334
+ return processIMI(decodeResult, messageType);
4335
+ }
4336
+ function processIMI(decodeResult, type) {
4337
+ if (type === "FPN") {
4338
+ decodeResult.formatted.description = "Flight Plan";
4339
+ } else if (type === "FTX") {
4340
+ decodeResult.formatted.description = "Free Text";
4341
+ } else if (type === "INI") {
4342
+ decodeResult.formatted.description = "Initial Report";
4343
+ } else if (type === "INR") {
4344
+ decodeResult.formatted.description = "In-Range Report";
4345
+ } else if (type === "LDI") {
4346
+ decodeResult.formatted.description = "Load Distribution Information";
4347
+ } else if (type === "PER") {
4348
+ decodeResult.formatted.description = "Performance Report";
4349
+ } else if (type === "POS") {
4350
+ decodeResult.formatted.description = "Position Report";
4351
+ } else if (type === "PRG") {
4352
+ decodeResult.formatted.description = "Progress Report";
4353
+ } else if (type === "PWI") {
4354
+ decodeResult.formatted.description = "Pilot Weather Information";
4355
+ } else if (type === "WXR") {
4356
+ decodeResult.formatted.description = "Weather Report";
4357
+ } else if (type === "REJ") {
4358
+ decodeResult.formatted.description = "Reject";
4359
+ } else if (type === "REQ") {
4360
+ decodeResult.formatted.description = "Request";
4361
+ } else if (type === "RES") {
4362
+ decodeResult.formatted.description = "Response";
4363
+ } else if (type === "SUM") {
4364
+ decodeResult.formatted.description = "Summary Report";
4365
+ } else {
4366
+ decodeResult.formatted.description = "Unknown H1 Message";
4367
+ return false;
4368
+ }
4369
+ return true;
4370
+ }
4371
+ function processPerformanceData(decodeResult, data) {
4372
+ if (data.length < 3) {
4373
+ ResultFormatter.unknownArr(decodeResult, data, ",");
4374
+ return;
4375
+ }
4376
+ if (data[2] !== void 0 && data[2] !== "") {
4377
+ const alt = Number(data[2]) * 100;
4378
+ if (!isNaN(alt) && alt > 0) {
4379
+ ResultFormatter.altitude(decodeResult, alt);
4380
+ }
4381
+ }
4382
+ if (data.length > 8 && data[8] !== void 0 && data[8] !== "") {
4383
+ ResultFormatter.temperature(decodeResult, data[8]);
4384
+ }
4385
+ const remaining = [];
4386
+ for (let i = 0; i < data.length; i++) {
4387
+ if (i === 2 && data[i] !== "" && !isNaN(Number(data[i])) && Number(data[i]) * 100 > 0) {
4388
+ continue;
4479
4389
  }
4480
- return decodeResult;
4390
+ if (i === 8 && data[i] !== "" && (data[i].startsWith("M") || data[i].startsWith("P") || !isNaN(Number(data[i])))) {
4391
+ continue;
4392
+ }
4393
+ remaining.push(data[i]);
4481
4394
  }
4482
- };
4483
-
4484
- // lib/plugins/Label_8E.ts
4485
- var Label_8E = class extends DecoderPlugin {
4486
- name = "label-8e";
4487
- qualifiers() {
4488
- return {
4489
- labels: ["8E"]
4490
- };
4395
+ if (remaining.length > 0 && remaining.some((r) => r !== "")) {
4396
+ ResultFormatter.unknown(decodeResult, remaining.join(","), "/PR");
4491
4397
  }
4492
- decode(message, options = {}) {
4493
- const decodeResult = this.defaultResult();
4494
- decodeResult.decoder.name = this.name;
4495
- decodeResult.formatted.description = "ETA Report";
4496
- decodeResult.message = message;
4497
- const regex = /^(?<arrival_icao>\w{4}),(?<arrival_eta>\d{4})$/;
4498
- const results = message.text.match(regex);
4499
- if (results?.groups) {
4500
- if (options.debug) {
4501
- console.log("Label 8E ETA: groups");
4502
- console.log(results.groups);
4398
+ }
4399
+ function processDateCode(decodeResult, data) {
4400
+ if (data.length === 1) {
4401
+ } else if (data.length === 2) {
4402
+ const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
4403
+ const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
4404
+ decodeResult.raw.message_timestamp = time;
4405
+ }
4406
+ }
4407
+ function processWeatherQuery(decodeResult, data) {
4408
+ if (data.length !== 2) {
4409
+ ResultFormatter.unknown(decodeResult, data.join(":"), "WQ/");
4410
+ return;
4411
+ }
4412
+ const alts = data[0].split(".");
4413
+ const route = data[1].split(".");
4414
+ ResultFormatter.requestedAltitudes(
4415
+ decodeResult,
4416
+ alts.map((a) => parseInt(a, 10) * 100)
4417
+ );
4418
+ const waypoints = route.map((wp) => {
4419
+ return { name: wp };
4420
+ });
4421
+ ResultFormatter.route(decodeResult, { waypoints });
4422
+ }
4423
+ function processRoute(decodeResult, last, time, next, eta, then, date) {
4424
+ const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
4425
+ const nextTime = date ? DateTimeUtils.convertDateTimeToEpoch(eta, date) : DateTimeUtils.convertHHMMSSToTod(eta);
4426
+ const timeFormat = date ? "epoch" : "tod";
4427
+ const lastWaypoint = RouteUtils.getWaypoint(last);
4428
+ lastWaypoint.time = lastTime;
4429
+ lastWaypoint.timeFormat = timeFormat;
4430
+ const nextWaypoint = RouteUtils.getWaypoint(next);
4431
+ nextWaypoint.time = nextTime;
4432
+ nextWaypoint.timeFormat = timeFormat;
4433
+ const thenWaypoint = RouteUtils.getWaypoint(then || "?");
4434
+ const waypoints = [lastWaypoint, nextWaypoint, thenWaypoint];
4435
+ ResultFormatter.route(decodeResult, { waypoints });
4436
+ }
4437
+ function processWindData(decodeResult, message) {
4438
+ const wind = [];
4439
+ const flightLevel = Number(message.slice(0, 3));
4440
+ const fields = message.slice(4).split(".");
4441
+ fields.forEach((field) => {
4442
+ if (field.length < 4) {
4443
+ return;
4444
+ }
4445
+ const data = field.split(",");
4446
+ const waypoint = { name: data[0] };
4447
+ const windData = data[1];
4448
+ const windDirection = parseInt(windData.slice(0, 3), 10);
4449
+ const windSpeed = parseInt(windData.slice(3), 10);
4450
+ if (data.length === 3) {
4451
+ const tempData = data[2];
4452
+ const tempFlightLevel = Number(tempData.slice(0, 3));
4453
+ const tempString = tempData.slice(3);
4454
+ const tempDegrees = Number(tempString.substring(1)) * (tempString.charAt(0) === "M" ? -1 : 1);
4455
+ wind.push({
4456
+ waypoint,
4457
+ flightLevel,
4458
+ windDirection,
4459
+ windSpeed,
4460
+ temperature: {
4461
+ flightLevel: tempFlightLevel,
4462
+ degreesC: tempDegrees
4463
+ }
4464
+ });
4465
+ } else {
4466
+ wind.push({
4467
+ waypoint,
4468
+ flightLevel,
4469
+ windDirection,
4470
+ windSpeed
4471
+ });
4472
+ }
4473
+ });
4474
+ ResultFormatter.windData(decodeResult, wind);
4475
+ }
4476
+ function processRunway(decodeResult, data) {
4477
+ const parts = data[0].split(".");
4478
+ const more = parts[0].split(",");
4479
+ ResultFormatter.departureRunway(decodeResult, more[0]);
4480
+ ResultFormatter.unknownArr(decodeResult, more.slice(1), ",");
4481
+ ResultFormatter.unknownArr(decodeResult, parts.slice(1), ".");
4482
+ ResultFormatter.departureAirport(decodeResult, data[1].split(",")[0]);
4483
+ ResultFormatter.unknownArr(decodeResult, data[1].split(",").slice(1), ",");
4484
+ }
4485
+ function crc16IbmSdlcRev(data) {
4486
+ let crc = 65535;
4487
+ const bytes = Buffer.from(data, "ascii");
4488
+ for (const byte of bytes) {
4489
+ crc ^= byte;
4490
+ for (let i = 0; i < 8; i++) {
4491
+ if ((crc & 1) !== 0) {
4492
+ crc = crc >>> 1 ^ 33800;
4493
+ } else {
4494
+ crc = crc >>> 1;
4503
4495
  }
4504
- ResultFormatter.eta(
4505
- decodeResult,
4506
- DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta)
4507
- );
4508
- ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
4509
4496
  }
4510
- decodeResult.decoded = true;
4511
- decodeResult.decoder.decodeLevel = "full";
4512
- return decodeResult;
4513
- }
4514
- };
4515
-
4516
- // lib/plugins/Label_B6.ts
4517
- var Label_B6_Forwardslash = class extends DecoderPlugin {
4518
- name = "label-b6-forwardslash";
4519
- qualifiers() {
4520
- return {
4521
- labels: ["B6"],
4522
- preambles: ["/"]
4523
- };
4524
4497
  }
4525
- decode(message, options = {}) {
4526
- const decodeResult = this.defaultResult();
4527
- decodeResult.decoder.name = this.name;
4528
- decodeResult.formatted.description = "CPDLC Message";
4529
- decodeResult.message = message;
4530
- if (options.debug) {
4531
- console.log("CPDLC: " + message);
4498
+ crc = (crc ^ 65535) & 65535;
4499
+ const nibble1 = crc >> 12 & 15;
4500
+ const nibble2 = crc >> 8 & 15;
4501
+ const nibble3 = crc >> 4 & 15;
4502
+ const nibble4 = crc & 15;
4503
+ return nibble4 << 12 | nibble3 << 8 | nibble2 << 4 | nibble1;
4504
+ }
4505
+ function crc16Genibus(data) {
4506
+ let crc = 65535;
4507
+ const polynomial = 4129;
4508
+ const bytes = Buffer.from(data, "ascii");
4509
+ for (const byte of bytes) {
4510
+ crc ^= byte << 8;
4511
+ for (let i = 0; i < 8; i++) {
4512
+ if ((crc & 32768) !== 0) {
4513
+ crc = (crc << 1 ^ polynomial) & 65535;
4514
+ } else {
4515
+ crc = crc << 1 & 65535;
4516
+ }
4532
4517
  }
4533
- return decodeResult;
4534
4518
  }
4535
- };
4536
-
4537
- // lib/plugins/Label_ColonComma.ts
4538
- var Label_ColonComma = class extends DecoderPlugin {
4539
- name = "label-colon-comma";
4540
- qualifiers() {
4541
- return {
4542
- labels: [":;"]
4543
- };
4519
+ return (crc ^ 65535) & 65535;
4520
+ }
4521
+ function processMessageReference(decodeResult, data) {
4522
+ if (data.length !== 2) {
4523
+ ResultFormatter.unknown(decodeResult, data.join(","), "/MR");
4524
+ return;
4544
4525
  }
4545
- decode(message, options = {}) {
4546
- const decodeResult = this.defaultResult();
4547
- decodeResult.decoder.name = this.name;
4548
- decodeResult.raw.frequency = Number(message.text) / 1e3;
4549
- decodeResult.formatted.description = "Aircraft Transceiver Frequency Change";
4550
- decodeResult.formatted.items.push({
4551
- type: "frequency",
4552
- label: "Frequency",
4553
- value: `${decodeResult.raw.frequency} MHz`,
4554
- code: "FREQ"
4555
- });
4556
- decodeResult.decoded = true;
4557
- decodeResult.decoder.decodeLevel = "full";
4558
- return decodeResult;
4526
+ ResultFormatter.sequenceNumber(decodeResult, parseInt(data[0], 10));
4527
+ if (data[1] !== "") {
4528
+ ResultFormatter.sequenceResponse(decodeResult, parseInt(data[1], 10));
4559
4529
  }
4560
- };
4530
+ }
4561
4531
 
4562
- // lib/plugins/Label_H1.ts
4563
- var Label_H1 = class extends DecoderPlugin {
4564
- name = "label-h1";
4532
+ // lib/plugins/ARINC_702.ts
4533
+ var Arinc702 = class extends DecoderPlugin {
4534
+ name = "arinc-702";
4565
4535
  qualifiers() {
4566
4536
  return {
4567
- labels: ["H1"]
4537
+ labels: ["*"]
4568
4538
  };
4569
4539
  }
4570
4540
  decode(message, options = {}) {
@@ -4572,33 +4542,58 @@ var Label_H1 = class extends DecoderPlugin {
4572
4542
  decodeResult.decoder.name = this.name;
4573
4543
  decodeResult.message = message;
4574
4544
  const msg = message.text.replace(/\n|\r/g, "");
4575
- const parts = msg.split("#");
4576
4545
  let decoded = false;
4546
+ decoded = Arinc702Helper.decodeH1Message(decodeResult, msg);
4547
+ if (decoded) {
4548
+ return this.processDecodeResult(decodeResult, decoded, options, message);
4549
+ }
4577
4550
  if (msg.startsWith("/")) {
4578
4551
  const headerData = msg.split(".");
4579
- const decoded2 = H1Helper.decodeH1Message(
4552
+ decoded = Arinc702Helper.decodeH1Message(
4580
4553
  decodeResult,
4581
4554
  headerData.slice(1).join(".")
4582
4555
  );
4583
- if (decoded2) {
4556
+ if (decoded) {
4584
4557
  decodeResult.remaining.text = headerData[0] + "." + decodeResult.remaining.text;
4585
- decodeResult.decoded = decoded2;
4586
- decodeResult.decoder.decodeLevel = "partial";
4558
+ return this.processDecodeResult(
4559
+ decodeResult,
4560
+ decoded,
4561
+ options,
4562
+ message
4563
+ );
4587
4564
  }
4588
- return decodeResult;
4589
- } else if (parts.length === 1) {
4590
- decoded = H1Helper.decodeH1Message(decodeResult, msg);
4591
- } else if (parts.length == 2) {
4592
- const offset = parts[0] === "- " || isNaN(parseInt(parts[1][1])) ? 3 : 4;
4593
- decoded = H1Helper.decodeH1Message(
4565
+ }
4566
+ const hashParts = msg.split("#");
4567
+ if (hashParts.length == 2) {
4568
+ const offset = hashParts[0] === "- " || isNaN(parseInt(hashParts[1][1])) ? 3 : 4;
4569
+ decoded = Arinc702Helper.decodeH1Message(
4594
4570
  decodeResult,
4595
- msg.slice(parts[0].length + offset)
4571
+ msg.slice(hashParts[0].length + offset)
4596
4572
  );
4597
- if (decoded && parts[0].length > 0) {
4598
- ResultFormatter.flightNumber(decodeResult, parts[0].substring(4));
4599
- decodeResult.remaining.text = parts[0].substring(0, 4) + "#" + parts[1].substring(0, offset - 1) + "/" + decodeResult.remaining.text;
4573
+ if (decoded && hashParts[0].length > 0) {
4574
+ ResultFormatter.flightNumber(decodeResult, hashParts[0].substring(4));
4575
+ decodeResult.remaining.text = hashParts[0].substring(0, 4) + "#" + hashParts[1].substring(0, offset - 1) + "/" + decodeResult.remaining.text;
4576
+ }
4577
+ if (decoded) {
4578
+ return this.processDecodeResult(
4579
+ decodeResult,
4580
+ decoded,
4581
+ options,
4582
+ message
4583
+ );
4600
4584
  }
4601
4585
  }
4586
+ const slashParts = msg.split("/");
4587
+ if (slashParts[0].length > 3) {
4588
+ decoded = Arinc702Helper.decodeH1Message(
4589
+ decodeResult,
4590
+ msg.slice(slashParts[0].length - 3)
4591
+ );
4592
+ decodeResult.remaining.text = slashParts[0].slice(0, 3) + "/" + decodeResult.remaining.text;
4593
+ }
4594
+ return this.processDecodeResult(decodeResult, decoded, options, message);
4595
+ }
4596
+ processDecodeResult(decodeResult, decoded, options, message) {
4602
4597
  decodeResult.decoded = decoded;
4603
4598
  decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
4604
4599
  if (decodeResult.formatted.items.length === 0) {
@@ -6217,6 +6212,7 @@ var MessageDecoder = class {
6217
6212
  this.plugins = [];
6218
6213
  this.debug = false;
6219
6214
  this.registerPlugin(new CBand(this));
6215
+ this.registerPlugin(new Arinc702(this));
6220
6216
  this.registerPlugin(new Label_ColonComma(this));
6221
6217
  this.registerPlugin(new Label_5Z_Slash(this));
6222
6218
  this.registerPlugin(new Label_10_LDR(this));
@@ -6231,7 +6227,6 @@ var MessageDecoder = class {
6231
6227
  this.registerPlugin(new Label_16_N_Space(this));
6232
6228
  this.registerPlugin(new Label_16_POSA1(this));
6233
6229
  this.registerPlugin(new Label_16_TOD(this));
6234
- this.registerPlugin(new Label_1J_2J_FTX(this));
6235
6230
  this.registerPlugin(new Label_1L_3Line(this));
6236
6231
  this.registerPlugin(new Label_1L_070(this));
6237
6232
  this.registerPlugin(new Label_1L_660(this));
@@ -6244,7 +6239,6 @@ var MessageDecoder = class {
6244
6239
  this.registerPlugin(new Label_2P_FM3(this));
6245
6240
  this.registerPlugin(new Label_2P_FM4(this));
6246
6241
  this.registerPlugin(new Label_2P_FM5(this));
6247
- this.registerPlugin(new Label_2P_POS(this));
6248
6242
  this.registerPlugin(new Label_30_Slash_EA(this));
6249
6243
  this.registerPlugin(new Label_44_ETA(this));
6250
6244
  this.registerPlugin(new Label_44_IN(this));
@@ -6257,7 +6251,6 @@ var MessageDecoder = class {
6257
6251
  this.registerPlugin(new Label_4A_DIS(this));
6258
6252
  this.registerPlugin(new Label_4A_DOOR(this));
6259
6253
  this.registerPlugin(new Label_4A_Slash_01(this));
6260
- this.registerPlugin(new Label_4J_POS(this));
6261
6254
  this.registerPlugin(new Label_4N(this));
6262
6255
  this.registerPlugin(new Label_4T_AGFSR(this));
6263
6256
  this.registerPlugin(new Label_4T_ETA(this));
@@ -6267,7 +6260,6 @@ var MessageDecoder = class {
6267
6260
  this.registerPlugin(new Label_H1_OHMA(this));
6268
6261
  this.registerPlugin(new Label_H1_Paren(this));
6269
6262
  this.registerPlugin(new Label_H1_WRN(this));
6270
- this.registerPlugin(new Label_H1(this));
6271
6263
  this.registerPlugin(new Label_H1_StarPOS(this));
6272
6264
  this.registerPlugin(new Label_HX(this));
6273
6265
  this.registerPlugin(new Label_58(this));