@airframes/acars-decoder 1.8.10 → 1.8.11

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
@@ -1830,698 +1830,6 @@ var Label_16_TOD = class extends DecoderPlugin {
1830
1830
  }
1831
1831
  };
1832
1832
 
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;
1889
- }
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));
1902
- }
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));
1950
- }
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
- });
1960
- }
1961
- };
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
-
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 {
2019
- decodeResult.decoded = false;
2020
- decodeResult.decoder.decodeLevel = "none";
2021
- return false;
2022
- }
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;
2029
- }
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);
2133
- }
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]);
2140
- }
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));
2146
- }
2147
- }
2148
- static processPosition(decodeResult, data) {
2149
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
2150
- data[0]
2151
- );
2152
- if (position) {
2153
- ResultFormatter.position(decodeResult, position);
2154
- }
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]);
2161
- }
2162
- if (data.length >= 14) {
2163
- ResultFormatter.unknownArr(decodeResult, data.slice(10));
2164
- }
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);
2171
- }
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);
2179
- }
2180
- decodeResult.raw.message_timestamp = time;
2181
- }
2182
- };
2183
- function processETA(data, decodeResult, fields, i) {
2184
- if (data.length === 5) {
2185
- ResultFormatter.day(decodeResult, Number(data.substring(0, 1)));
2186
- ResultFormatter.eta(
2187
- decodeResult,
2188
- DateTimeUtils.convertHHMMSSToTod(data.substring(1))
2189
- );
2190
- } else if (data.length === 6) {
2191
- ResultFormatter.day(decodeResult, Number(data.substring(0, 2)));
2192
- ResultFormatter.eta(
2193
- decodeResult,
2194
- DateTimeUtils.convertHHMMSSToTod(data.substring(2))
2195
- );
2196
- } else {
2197
- ResultFormatter.unknown(decodeResult, fields[i], "/");
2198
- }
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/");
2206
- }
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]);
2242
- }
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])
2253
- );
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]);
2261
- }
2262
- ResultFormatter.arrivalRunway(decodeResult, data[1]);
2263
- ResultFormatter.currentFuel(decodeResult, parseInt(data[2], 10));
2264
- ResultFormatter.eta(
2265
- decodeResult,
2266
- DateTimeUtils.convertHHMMSSToTod(data[3])
2267
- );
2268
- if (data.length > 4) {
2269
- ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
2270
- }
2271
- return;
2272
- }
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(","));
2285
- }
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);
2291
- }
2292
- } else if (data.length === 3) {
2293
- if (data[0] !== void 0 && data[0] !== "") {
2294
- ResultFormatter.cg(decodeResult, parseInt(data[0], 10) / 10, "center");
2295
- }
2296
- if (data[1] !== void 0 && data[1] !== "") {
2297
- ResultFormatter.cg(decodeResult, parseInt(data[1], 10) / 10, "lower");
2298
- }
2299
- if (data[2] !== void 0 && data[2] !== "") {
2300
- ResultFormatter.cg(decodeResult, parseInt(data[2], 10) / 10, "upper");
2301
- }
2302
- } else {
2303
- ResultFormatter.unknown(decodeResult, data.join(","));
2304
- }
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(
2319
- decodeResult,
2320
- messageParts.slice(1).join(","),
2321
- "/"
2322
- );
2323
- }
2324
- return part1 && part2;
2325
- }
2326
- if (messageParts.length > 1) {
2327
- ResultFormatter.unknown(decodeResult, messageParts.slice(1).join(","), "/");
2328
- }
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
- }
2486
-
2487
- // lib/plugins/Label_1J_2J_FTX.ts
2488
- var Label_1J_2J_FTX = class extends DecoderPlugin {
2489
- name = "label-1j-2j-ftx";
2490
- qualifiers() {
2491
- return {
2492
- labels: ["1J", "2J"]
2493
- };
2494
- }
2495
- decode(message, options = {}) {
2496
- let decodeResult = this.defaultResult();
2497
- decodeResult.decoder.name = this.name;
2498
- 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(
2504
- decodeResult,
2505
- msg.slice(parts[0].length - 3)
2506
- );
2507
- decodeResult.remaining.text = parts[0].slice(0, 3) + "/" + decodeResult.remaining.text;
2508
- } 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
- if (options.debug) {
2515
- console.log(`Decoder: Unknown 1J/2J message: ${message.text}`);
2516
- }
2517
- ResultFormatter.unknown(decodeResult, message.text);
2518
- decodeResult.decoded = false;
2519
- decodeResult.decoder.decodeLevel = "none";
2520
- }
2521
- return decodeResult;
2522
- }
2523
- };
2524
-
2525
1833
  // lib/plugins/Label_1M_Slash.ts
2526
1834
  var Label_1M_Slash = class extends DecoderPlugin {
2527
1835
  name = "label-1m-slash";
@@ -3286,44 +2594,6 @@ var Label_2P_FM5 = class extends DecoderPlugin {
3286
2594
  }
3287
2595
  };
3288
2596
 
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
- } 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
- if (options.debug) {
3317
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
3318
- }
3319
- ResultFormatter.unknown(decodeResult, message.text);
3320
- decodeResult.decoded = false;
3321
- decodeResult.decoder.decodeLevel = "none";
3322
- }
3323
- return decodeResult;
3324
- }
3325
- };
3326
-
3327
2597
  // lib/plugins/Label_24_Slash.ts
3328
2598
  var Label_24_Slash = class extends DecoderPlugin {
3329
2599
  name = "label-24-slash";
@@ -3698,7 +2968,182 @@ var Label_44_POS = class extends DecoderPlugin {
3698
2968
  decodeResult.decoder.decodeLevel = "full";
3699
2969
  return decodeResult;
3700
2970
  }
3701
- };
2971
+ };
2972
+
2973
+ // lib/utils/flight_plan_utils.ts
2974
+ var FlightPlanUtils = class _FlightPlanUtils {
2975
+ /**
2976
+ * Processes flight plan data
2977
+ *
2978
+ * Expected format is [header, key1, val1, ... keyN, valN]
2979
+ *
2980
+ * @param decodeResult - results
2981
+ * @param data - original message split by ':'
2982
+ * @returns whether all fields were processed or not
2983
+ */
2984
+ static processFlightPlan(decodeResult, data) {
2985
+ let allKnownFields = _FlightPlanUtils.parseHeader(decodeResult, data[0]);
2986
+ for (let i = 1; i < data.length; i += 2) {
2987
+ const key = data[i];
2988
+ const value = data[i + 1];
2989
+ switch (key) {
2990
+ case "A":
2991
+ _FlightPlanUtils.addProcedure(decodeResult, value, "arrival");
2992
+ break;
2993
+ case "AA":
2994
+ addArrivalAirport(decodeResult, value);
2995
+ break;
2996
+ case "AP":
2997
+ _FlightPlanUtils.addProcedure(decodeResult, value, "approach");
2998
+ break;
2999
+ case "CR":
3000
+ addCompanyRoute(decodeResult, value);
3001
+ break;
3002
+ case "D":
3003
+ _FlightPlanUtils.addProcedure(decodeResult, value, "departure");
3004
+ break;
3005
+ case "DA":
3006
+ addDepartureAirport(decodeResult, value);
3007
+ break;
3008
+ case "F":
3009
+ addRoute(decodeResult, value);
3010
+ break;
3011
+ case "FP":
3012
+ ResultFormatter.flightPlan(decodeResult, value.trim());
3013
+ break;
3014
+ case "R":
3015
+ addRunway(decodeResult, value);
3016
+ break;
3017
+ // case 'WS': // something about routes, has altitude, so current parsing won't work
3018
+ // break;
3019
+ default:
3020
+ if (allKnownFields) {
3021
+ decodeResult.remaining.text = "";
3022
+ allKnownFields = false;
3023
+ }
3024
+ decodeResult.remaining.text += `:${key}:${value}`;
3025
+ decodeResult.decoder.decodeLevel = "partial";
3026
+ }
3027
+ }
3028
+ return allKnownFields;
3029
+ }
3030
+ static parseHeader(decodeResult, header) {
3031
+ let allKnownFields = true;
3032
+ if (header.startsWith("RF")) {
3033
+ decodeResult.formatted.items.push({
3034
+ type: "status",
3035
+ code: "ROUTE_STATUS",
3036
+ label: "Route Status",
3037
+ value: "Route Filed"
3038
+ });
3039
+ decodeResult.raw.route_status = "RF";
3040
+ if (header.length > 2) {
3041
+ addRoute(decodeResult, header.substring(2));
3042
+ }
3043
+ } else if (header.startsWith("RP")) {
3044
+ decodeResult.raw.route_status = "RP";
3045
+ decodeResult.formatted.items.push({
3046
+ type: "status",
3047
+ code: "ROUTE_STATUS",
3048
+ label: "Route Status",
3049
+ value: "Route Planned"
3050
+ });
3051
+ decodeResult.raw.route_status = header;
3052
+ } else if (header.startsWith("RI")) {
3053
+ decodeResult.raw.route_status = "RI";
3054
+ decodeResult.formatted.items.push({
3055
+ type: "status",
3056
+ code: "ROUTE_STATUS",
3057
+ label: "Route Status",
3058
+ value: "Route Inactive"
3059
+ });
3060
+ } else if (header.startsWith("RM")) {
3061
+ decodeResult.raw.route_status = "RM";
3062
+ decodeResult.formatted.items.push({
3063
+ type: "status",
3064
+ code: "ROUTE_STATUS",
3065
+ label: "Route Status",
3066
+ value: "Route Mapped"
3067
+ });
3068
+ } else if (header.startsWith("RS")) {
3069
+ decodeResult.raw.route_status = "RS";
3070
+ decodeResult.formatted.items.push({
3071
+ type: "status",
3072
+ code: "ROUTE_STATUS",
3073
+ label: "Route Status",
3074
+ value: "Route Saved"
3075
+ });
3076
+ } else {
3077
+ decodeResult.remaining.text += header;
3078
+ allKnownFields = false;
3079
+ }
3080
+ return allKnownFields;
3081
+ }
3082
+ static addProcedure(decodeResult, value, type) {
3083
+ if (decodeResult.raw.procedures === void 0) {
3084
+ decodeResult.raw.procedures = [];
3085
+ }
3086
+ const data = value.split(".");
3087
+ let waypoints;
3088
+ if (data.length > 1) {
3089
+ waypoints = data.slice(1).map((leg) => RouteUtils.getWaypoint(leg));
3090
+ }
3091
+ const route = { name: data[0], waypoints };
3092
+ decodeResult.raw.procedures.push({ type, route });
3093
+ const procedureName = type.substring(0, 1).toUpperCase() + type.slice(1);
3094
+ decodeResult.formatted.items.push({
3095
+ type: "procedure",
3096
+ code: "proc",
3097
+ label: `${procedureName} Procedure`,
3098
+ value: RouteUtils.routeToString(route)
3099
+ });
3100
+ }
3101
+ };
3102
+ function addArrivalAirport(decodeResult, value) {
3103
+ ResultFormatter.arrivalAirport(decodeResult, value);
3104
+ }
3105
+ function addDepartureAirport(decodeResult, value) {
3106
+ ResultFormatter.departureAirport(decodeResult, value);
3107
+ }
3108
+ function addRunway(decodeResult, value) {
3109
+ if (value.length === 8) {
3110
+ ResultFormatter.arrivalRunway(decodeResult, value.substring(4, 7));
3111
+ }
3112
+ ResultFormatter.departureRunway(decodeResult, value.substring(0, 3));
3113
+ }
3114
+ function addRoute(decodeResult, value) {
3115
+ const route = value.split(".");
3116
+ ResultFormatter.route(decodeResult, {
3117
+ waypoints: route.map((leg) => RouteUtils.getWaypoint(leg))
3118
+ });
3119
+ }
3120
+ function addCompanyRoute(decodeResult, value) {
3121
+ const segments = value.split(".");
3122
+ const parens_idx = segments[0].indexOf("(");
3123
+ let name;
3124
+ let runway;
3125
+ if (parens_idx === -1) {
3126
+ name = segments[0];
3127
+ } else {
3128
+ name = segments[0].slice(0, parens_idx);
3129
+ runway = segments[0].slice(parens_idx + 1, segments[0].indexOf(")"));
3130
+ }
3131
+ let waypoints;
3132
+ if (segments.length > 1) {
3133
+ waypoints = segments.slice(1).map((leg) => RouteUtils.getWaypoint(leg));
3134
+ }
3135
+ decodeResult.raw.company_route = {
3136
+ name,
3137
+ runway,
3138
+ waypoints
3139
+ };
3140
+ decodeResult.formatted.items.push({
3141
+ type: "company_route",
3142
+ code: "CR",
3143
+ label: "Company Route",
3144
+ value: RouteUtils.routeToString(decodeResult.raw.company_route)
3145
+ });
3146
+ }
3702
3147
 
3703
3148
  // lib/plugins/Label_44_Slash.ts
3704
3149
  var Label_44_Slash = class extends DecoderPlugin {
@@ -3891,150 +3336,503 @@ var Label_4A_01 = class extends DecoderPlugin {
3891
3336
  }
3892
3337
  };
3893
3338
 
3894
- // lib/plugins/Label_4A_DIS.ts
3895
- var Label_4A_DIS = class extends DecoderPlugin {
3896
- name = "label-4a-dis";
3339
+ // lib/plugins/Label_4A_DIS.ts
3340
+ var Label_4A_DIS = class extends DecoderPlugin {
3341
+ name = "label-4a-dis";
3342
+ qualifiers() {
3343
+ return {
3344
+ labels: ["4A"],
3345
+ preambles: ["DIS"]
3346
+ };
3347
+ }
3348
+ decode(message, options = {}) {
3349
+ const decodeResult = this.defaultResult();
3350
+ decodeResult.decoder.name = this.name;
3351
+ decodeResult.message = message;
3352
+ decodeResult.formatted.description = "Latest New Format";
3353
+ decodeResult.decoded = true;
3354
+ const fields = message.text.split(",");
3355
+ ResultFormatter.time_of_day(
3356
+ decodeResult,
3357
+ DateTimeUtils.convertHHMMSSToTod(fields[1].substring(2) + "00")
3358
+ );
3359
+ ResultFormatter.callsign(decodeResult, fields[2]);
3360
+ ResultFormatter.freetext(decodeResult, fields.slice(3).join(""));
3361
+ if (decodeResult.decoded) {
3362
+ if (!decodeResult.remaining.text)
3363
+ decodeResult.decoder.decodeLevel = "full";
3364
+ else decodeResult.decoder.decodeLevel = "partial";
3365
+ } else {
3366
+ decodeResult.decoder.decodeLevel = "none";
3367
+ }
3368
+ return decodeResult;
3369
+ }
3370
+ };
3371
+
3372
+ // lib/plugins/Label_4A_DOOR.ts
3373
+ var Label_4A_DOOR = class extends DecoderPlugin {
3374
+ name = "label-4a-door";
3375
+ qualifiers() {
3376
+ return {
3377
+ labels: ["4A"],
3378
+ preambles: ["DOOR"]
3379
+ };
3380
+ }
3381
+ decode(message, options = {}) {
3382
+ const decodeResult = this.defaultResult();
3383
+ decodeResult.decoder.name = this.name;
3384
+ decodeResult.message = message;
3385
+ decodeResult.formatted.description = "Latest New Format";
3386
+ decodeResult.decoded = true;
3387
+ const fields = message.text.split(" ");
3388
+ if (fields.length === 3) {
3389
+ ResultFormatter.door_event(
3390
+ decodeResult,
3391
+ fields[0].split("/")[1],
3392
+ fields[1]
3393
+ );
3394
+ ResultFormatter.time_of_day(
3395
+ decodeResult,
3396
+ DateTimeUtils.convertHHMMSSToTod(fields[2] + "00")
3397
+ );
3398
+ } else {
3399
+ decodeResult.decoded = false;
3400
+ ResultFormatter.unknown(decodeResult, message.text);
3401
+ }
3402
+ if (decodeResult.decoded) {
3403
+ if (!decodeResult.remaining.text)
3404
+ decodeResult.decoder.decodeLevel = "full";
3405
+ else decodeResult.decoder.decodeLevel = "partial";
3406
+ } else {
3407
+ decodeResult.decoder.decodeLevel = "none";
3408
+ }
3409
+ return decodeResult;
3410
+ }
3411
+ };
3412
+
3413
+ // lib/plugins/Label_4A_Slash_01.ts
3414
+ var Label_4A_Slash_01 = class extends DecoderPlugin {
3415
+ name = "label-4a-slash-01";
3416
+ qualifiers() {
3417
+ return {
3418
+ labels: ["4A"],
3419
+ preambles: ["/01"]
3420
+ };
3421
+ }
3422
+ decode(message, options = {}) {
3423
+ const decodeResult = this.defaultResult();
3424
+ decodeResult.decoder.name = this.name;
3425
+ decodeResult.message = message;
3426
+ decodeResult.formatted.description = "Latest New Format";
3427
+ decodeResult.decoded = true;
3428
+ if (message.text.length === 5 && message.text.substring(0, 4) === "/01-") {
3429
+ ResultFormatter.unknown(decodeResult, message.text.substring(4));
3430
+ } else {
3431
+ decodeResult.decoded = false;
3432
+ ResultFormatter.unknown(decodeResult, message.text);
3433
+ }
3434
+ if (decodeResult.decoded) {
3435
+ if (!decodeResult.remaining.text)
3436
+ decodeResult.decoder.decodeLevel = "full";
3437
+ else decodeResult.decoder.decodeLevel = "partial";
3438
+ } else {
3439
+ decodeResult.decoder.decodeLevel = "none";
3440
+ }
3441
+ return decodeResult;
3442
+ }
3443
+ };
3444
+
3445
+ // lib/plugins/Label_4N.ts
3446
+ var Label_4N = class extends DecoderPlugin {
3447
+ name = "label-4n";
3448
+ qualifiers() {
3449
+ return {
3450
+ labels: ["4N"]
3451
+ };
3452
+ }
3453
+ decode(message, options = {}) {
3454
+ const decodeResult = this.defaultResult();
3455
+ decodeResult.decoder.name = this.name;
3456
+ decodeResult.message = message;
3457
+ decodeResult.formatted.description = "Airline Defined";
3458
+ decodeResult.decoded = true;
3459
+ const text = message.text;
3460
+ const fields = text.split(",");
3461
+ if (text.length === 51) {
3462
+ decodeResult.raw.day = text.substring(0, 2);
3463
+ ResultFormatter.departureAirport(decodeResult, text.substring(8, 11));
3464
+ ResultFormatter.arrivalAirport(decodeResult, text.substring(13, 16));
3465
+ ResultFormatter.position(
3466
+ decodeResult,
3467
+ CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
3468
+ text.substring(30, 45).replace(/^(.)0/, "$1")
3469
+ )
3470
+ );
3471
+ ResultFormatter.altitude(
3472
+ decodeResult,
3473
+ Number(text.substring(48, 51)) * 100
3474
+ );
3475
+ ResultFormatter.unknownArr(
3476
+ decodeResult,
3477
+ [text.substring(2, 4), text.substring(19, 29)],
3478
+ " "
3479
+ );
3480
+ } else if (fields.length === 33) {
3481
+ decodeResult.raw.date = fields[3];
3482
+ if (fields[1] === "B") {
3483
+ ResultFormatter.position(decodeResult, {
3484
+ latitude: Number(fields[4]),
3485
+ longitude: Number(fields[5])
3486
+ });
3487
+ ResultFormatter.altitude(decodeResult, Number(fields[6]));
3488
+ }
3489
+ ResultFormatter.departureAirport(decodeResult, fields[8]);
3490
+ ResultFormatter.arrivalAirport(decodeResult, fields[9]);
3491
+ ResultFormatter.alternateAirport(decodeResult, fields[10]);
3492
+ ResultFormatter.arrivalRunway(decodeResult, fields[11].split("/")[0]);
3493
+ if (fields[12].length > 1) {
3494
+ ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
3495
+ }
3496
+ ResultFormatter.checksum(decodeResult, parseInt(fields[32], 16));
3497
+ ResultFormatter.unknownArr(
3498
+ decodeResult,
3499
+ [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter(
3500
+ (f) => f != ""
3501
+ )
3502
+ );
3503
+ } else {
3504
+ decodeResult.decoded = false;
3505
+ ResultFormatter.unknown(decodeResult, text);
3506
+ }
3507
+ if (decodeResult.decoded) {
3508
+ if (!decodeResult.remaining.text)
3509
+ decodeResult.decoder.decodeLevel = "full";
3510
+ else decodeResult.decoder.decodeLevel = "partial";
3511
+ } else {
3512
+ decodeResult.decoder.decodeLevel = "none";
3513
+ }
3514
+ return decodeResult;
3515
+ }
3516
+ };
3517
+
3518
+ // lib/plugins/Label_4T_AGFSR.ts
3519
+ var Label_4T_AGFSR = class extends DecoderPlugin {
3520
+ name = "label-4t-agfsr";
3521
+ qualifiers() {
3522
+ return {
3523
+ labels: ["4T"],
3524
+ preambles: ["AGFSR"]
3525
+ };
3526
+ }
3527
+ decode(message, options = {}) {
3528
+ const decodeResult = this.defaultResult();
3529
+ decodeResult.decoder.name = this.name;
3530
+ decodeResult.formatted.description = "Position Report";
3531
+ decodeResult.message = message;
3532
+ const data = message.text.substring(5).split("/");
3533
+ if (!message.text.startsWith("AGFSR") || data.length !== 20) {
3534
+ if (options.debug) {
3535
+ console.log(`Decoder: Unknown 4T message: ${message.text}`);
3536
+ }
3537
+ ResultFormatter.unknown(decodeResult, message.text);
3538
+ decodeResult.decoded = false;
3539
+ decodeResult.decoder.decodeLevel = "none";
3540
+ return decodeResult;
3541
+ }
3542
+ ResultFormatter.flightNumber(decodeResult, data[0].trim());
3543
+ ResultFormatter.departureDay(decodeResult, Number(data[1]));
3544
+ ResultFormatter.arrivalDay(decodeResult, Number(data[2]));
3545
+ ResultFormatter.departureAirport(
3546
+ decodeResult,
3547
+ data[3].substring(0, 3),
3548
+ "IATA"
3549
+ );
3550
+ ResultFormatter.arrivalAirport(decodeResult, data[3].substring(3), "IATA");
3551
+ ResultFormatter.time_of_day(
3552
+ decodeResult,
3553
+ DateTimeUtils.convertHHMMSSToTod(data[4].substring(0, 4))
3554
+ );
3555
+ ResultFormatter.unknown(decodeResult, data[5], "/");
3556
+ const lat = data[6].substring(0, 7);
3557
+ const lon = data[6].substring(7, 15);
3558
+ ResultFormatter.position(decodeResult, {
3559
+ latitude: CoordinateUtils.getDirection(lat[6]) * Number(lat.substring(0, 2)) + Number(lat.substring(2, 6)) / 60,
3560
+ longitude: CoordinateUtils.getDirection(lon[7]) * Number(lon.substring(0, 3)) + Number(lon.substring(3, 7)) / 60
3561
+ });
3562
+ ResultFormatter.altitude(decodeResult, 100 * Number(data[7]));
3563
+ ResultFormatter.unknownArr(decodeResult, data.slice(8), "/");
3564
+ decodeResult.decoded = true;
3565
+ decodeResult.decoder.decodeLevel = "partial";
3566
+ return decodeResult;
3567
+ }
3568
+ };
3569
+
3570
+ // lib/plugins/Label_58.ts
3571
+ var Label_58 = class extends DecoderPlugin {
3572
+ name = "label-58";
3897
3573
  qualifiers() {
3898
3574
  return {
3899
- labels: ["4A"],
3900
- preambles: ["DIS"]
3575
+ labels: ["58"]
3901
3576
  };
3902
3577
  }
3903
3578
  decode(message, options = {}) {
3904
3579
  const decodeResult = this.defaultResult();
3905
3580
  decodeResult.decoder.name = this.name;
3581
+ decodeResult.formatted.description = "Position Report";
3906
3582
  decodeResult.message = message;
3907
- decodeResult.formatted.description = "Latest New Format";
3908
- decodeResult.decoded = true;
3909
- const fields = message.text.split(",");
3910
- ResultFormatter.time_of_day(
3911
- decodeResult,
3912
- DateTimeUtils.convertHHMMSSToTod(fields[1].substring(2) + "00")
3913
- );
3914
- ResultFormatter.callsign(decodeResult, fields[2]);
3915
- ResultFormatter.freetext(decodeResult, fields.slice(3).join(""));
3916
- if (decodeResult.decoded) {
3917
- if (!decodeResult.remaining.text)
3918
- decodeResult.decoder.decodeLevel = "full";
3919
- else decodeResult.decoder.decodeLevel = "partial";
3583
+ const data = message.text.split("/");
3584
+ if (data.length === 8) {
3585
+ ResultFormatter.flightNumber(decodeResult, data[0]);
3586
+ ResultFormatter.day(decodeResult, Number(data[1]));
3587
+ ResultFormatter.time_of_day(
3588
+ decodeResult,
3589
+ DateTimeUtils.convertHHMMSSToTod(data[2])
3590
+ );
3591
+ const lat = data[3];
3592
+ const lon = data[4];
3593
+ ResultFormatter.position(decodeResult, {
3594
+ latitude: CoordinateUtils.getDirection(lat[0]) * Number(lat.substring(1)),
3595
+ longitude: CoordinateUtils.getDirection(lon[0]) * Number(lon.substring(1))
3596
+ });
3597
+ ResultFormatter.altitude(decodeResult, Number(data[5]));
3598
+ ResultFormatter.unknown(decodeResult, data[6], "/");
3599
+ ResultFormatter.unknown(decodeResult, data[7], "/");
3920
3600
  } else {
3601
+ if (options.debug) {
3602
+ console.log(`Decoder: Unknown 58 message: ${message.text}`);
3603
+ }
3604
+ ResultFormatter.unknown(decodeResult, message.text);
3605
+ decodeResult.decoded = false;
3921
3606
  decodeResult.decoder.decodeLevel = "none";
3607
+ return decodeResult;
3922
3608
  }
3609
+ decodeResult.decoded = true;
3610
+ decodeResult.decoder.decodeLevel = "partial";
3923
3611
  return decodeResult;
3924
3612
  }
3925
3613
  };
3926
3614
 
3927
- // lib/plugins/Label_4A_DOOR.ts
3928
- var Label_4A_DOOR = class extends DecoderPlugin {
3929
- name = "label-4a-door";
3615
+ // lib/plugins/Label_4T_ETA.ts
3616
+ var Label_4T_ETA = class extends DecoderPlugin {
3617
+ name = "label-4t-eta";
3930
3618
  qualifiers() {
3931
3619
  return {
3932
- labels: ["4A"],
3933
- preambles: ["DOOR"]
3620
+ labels: ["4T"],
3621
+ preambles: ["ETA"]
3934
3622
  };
3935
3623
  }
3936
3624
  decode(message, options = {}) {
3937
3625
  const decodeResult = this.defaultResult();
3938
3626
  decodeResult.decoder.name = this.name;
3627
+ decodeResult.formatted.description = "ETA Report";
3939
3628
  decodeResult.message = message;
3940
- decodeResult.formatted.description = "Latest New Format";
3941
- decodeResult.decoded = true;
3942
- const fields = message.text.split(" ");
3943
- if (fields.length === 3) {
3944
- ResultFormatter.door_event(
3945
- decodeResult,
3946
- fields[0].split("/")[1],
3947
- fields[1]
3948
- );
3949
- ResultFormatter.time_of_day(
3950
- decodeResult,
3951
- DateTimeUtils.convertHHMMSSToTod(fields[2] + "00")
3952
- );
3953
- } else {
3954
- decodeResult.decoded = false;
3629
+ const data = message.text.substring(3).split("/");
3630
+ if (!message.text.startsWith("ETA") || data.length !== 3) {
3631
+ if (options.debug) {
3632
+ console.log(`Decoder: Unknown 4T message: ${message.text}`);
3633
+ }
3955
3634
  ResultFormatter.unknown(decodeResult, message.text);
3956
- }
3957
- if (decodeResult.decoded) {
3958
- if (!decodeResult.remaining.text)
3959
- decodeResult.decoder.decodeLevel = "full";
3960
- else decodeResult.decoder.decodeLevel = "partial";
3961
- } else {
3635
+ decodeResult.decoded = false;
3962
3636
  decodeResult.decoder.decodeLevel = "none";
3637
+ return decodeResult;
3963
3638
  }
3639
+ ResultFormatter.flightNumber(decodeResult, data[0].trim());
3640
+ ResultFormatter.departureDay(decodeResult, Number(data[1]));
3641
+ const etaData = data[2].split(" ");
3642
+ ResultFormatter.arrivalDay(decodeResult, Number(etaData[0]));
3643
+ ResultFormatter.arrivalAirport(decodeResult, etaData[1], "IATA");
3644
+ ResultFormatter.eta(
3645
+ decodeResult,
3646
+ DateTimeUtils.convertHHMMSSToTod(etaData[2].substring(0, 4))
3647
+ );
3648
+ decodeResult.decoded = true;
3649
+ decodeResult.decoder.decodeLevel = "full";
3964
3650
  return decodeResult;
3965
3651
  }
3966
3652
  };
3967
3653
 
3968
- // lib/plugins/Label_4A_Slash_01.ts
3969
- var Label_4A_Slash_01 = class extends DecoderPlugin {
3970
- name = "label-4a-slash-01";
3654
+ // lib/plugins/Label_80.ts
3655
+ var Label_80 = class extends DecoderPlugin {
3656
+ name = "label-80";
3971
3657
  qualifiers() {
3972
3658
  return {
3973
- labels: ["4A"],
3974
- preambles: ["/01"]
3659
+ labels: ["80"],
3660
+ preambles: []
3975
3661
  };
3976
3662
  }
3977
3663
  decode(message, options = {}) {
3978
3664
  const decodeResult = this.defaultResult();
3979
3665
  decodeResult.decoder.name = this.name;
3980
- decodeResult.message = message;
3981
- decodeResult.formatted.description = "Latest New Format";
3982
- decodeResult.decoded = true;
3983
- if (message.text.length === 5 && message.text.substring(0, 4) === "/01-") {
3984
- ResultFormatter.unknown(decodeResult, message.text.substring(4));
3666
+ decodeResult.formatted.description = "Airline Defined Position Report";
3667
+ const lines = message.text.split(/\r?\n/);
3668
+ if (lines.length === 1 && lines[0].includes(",")) {
3669
+ this.parseCsvFormat(lines[0], decodeResult);
3985
3670
  } else {
3986
- decodeResult.decoded = false;
3987
- ResultFormatter.unknown(decodeResult, message.text);
3671
+ const header = lines[0].trim();
3672
+ const headerParts = header.split(",");
3673
+ for (let i = 0; i < headerParts.length - 1; i++) {
3674
+ const moreFields = headerParts[i].split("/");
3675
+ for (const more of moreFields) {
3676
+ this.parseTags(more.trim(), decodeResult);
3677
+ }
3678
+ }
3679
+ this.parseHeader(
3680
+ headerParts[headerParts.length - 1].trim(),
3681
+ decodeResult
3682
+ );
3683
+ for (let i = 1; i < lines.length; i++) {
3684
+ const line = lines[i];
3685
+ const parts = line.split("/");
3686
+ for (const part of parts) {
3687
+ this.parseTags(part.trim(), decodeResult);
3688
+ }
3689
+ }
3988
3690
  }
3989
- if (decodeResult.decoded) {
3990
- if (!decodeResult.remaining.text)
3991
- decodeResult.decoder.decodeLevel = "full";
3992
- else decodeResult.decoder.decodeLevel = "partial";
3993
- } else {
3994
- decodeResult.decoder.decodeLevel = "none";
3691
+ if (decodeResult.formatted.items.length > 0) {
3692
+ decodeResult.decoded = true;
3693
+ decodeResult.decoder.decodeLevel = decodeResult.remaining.text === void 0 ? "full" : "partial";
3995
3694
  }
3996
3695
  return decodeResult;
3997
3696
  }
3998
- };
3999
-
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
- };
3697
+ parseHeader(header, results) {
3698
+ const fields = header.split("/");
3699
+ if (fields.length < 3) {
3700
+ ResultFormatter.unknown(results, header, "/");
3701
+ return;
3702
+ }
3703
+ const msgInfo = fields[0].split(/\s+/);
3704
+ if (msgInfo.length === 3) {
3705
+ ResultFormatter.unknownArr(results, msgInfo.slice(0, 2), " ");
3706
+ ResultFormatter.flightNumber(results, msgInfo[2]);
3707
+ } else {
3708
+ ResultFormatter.unknown(results, header, "/");
3709
+ return;
3710
+ }
3711
+ const otherInfo1 = fields[1].split(/\s+/);
3712
+ if (otherInfo1.length === 2) {
3713
+ ResultFormatter.day(results, parseInt(otherInfo1[0], 10));
3714
+ ResultFormatter.departureAirport(results, otherInfo1[1]);
3715
+ } else {
3716
+ ResultFormatter.unknownArr(results, otherInfo1, " ");
3717
+ }
3718
+ const otherInfo2 = fields[2].split(/\s+/);
3719
+ if (otherInfo2.length === 2) {
3720
+ ResultFormatter.arrivalAirport(results, otherInfo2[0]);
3721
+ ResultFormatter.tail(results, otherInfo2[1].replace(".", ""));
3722
+ } else {
3723
+ ResultFormatter.unknownArr(results, otherInfo2, " ");
3724
+ }
3725
+ if (fields.length > 3) {
3726
+ ResultFormatter.unknownArr(results, fields.slice(3), "/");
3727
+ }
3728
+ }
3729
+ parseTags(part, results) {
3730
+ const kvPair = part.split(/\s+/);
3731
+ if (kvPair.length < 2) {
3732
+ ResultFormatter.unknown(results, part, "/");
3733
+ return;
3734
+ }
3735
+ const tag = kvPair[0];
3736
+ const val = kvPair.slice(1).join(" ");
3737
+ switch (tag) {
3738
+ case "POS":
3739
+ const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
3740
+ const posResult = val.match(posRegex);
3741
+ const lat = Number(posResult?.groups?.lat) * (posResult?.groups?.latd === "S" ? -1 : 1);
3742
+ const lon = Number(posResult?.groups?.lng) * (posResult?.groups?.lngd === "W" ? -1 : 1);
3743
+ const position = {
3744
+ latitude: Number.isInteger(lat) ? lat / 1e3 : lat / 100,
3745
+ longitude: Number.isInteger(lon) ? lon / 1e3 : lon / 100
3746
+ };
3747
+ ResultFormatter.position(results, position);
3748
+ break;
3749
+ case "ALT":
3750
+ ResultFormatter.altitude(results, parseInt(val.replace("+", ""), 10));
3751
+ break;
3752
+ case "FL":
3753
+ ResultFormatter.altitude(results, parseInt(val, 10) * 100);
3754
+ break;
3755
+ case "MCH":
3756
+ ResultFormatter.mach(results, parseInt(val, 10) / 1e3);
3757
+ break;
3758
+ case "SPD":
3759
+ ResultFormatter.groundspeed(results, parseInt(val, 10));
3760
+ break;
3761
+ case "TAS":
3762
+ ResultFormatter.airspeed(results, parseInt(val, 10));
3763
+ break;
3764
+ case "SAT":
3765
+ ResultFormatter.temperature(results, val);
3766
+ break;
3767
+ case "FB":
3768
+ break;
3769
+ case "FOB":
3770
+ ResultFormatter.currentFuel(
3771
+ results,
3772
+ parseInt(val.replace(/\D/g, ""), 10)
3773
+ );
3774
+ break;
3775
+ case "UTC":
3776
+ ResultFormatter.time_of_day(
3777
+ results,
3778
+ DateTimeUtils.convertHHMMSSToTod(val)
3779
+ );
3780
+ break;
3781
+ case "ETA":
3782
+ const hhmm = val.split(".")[0].replace(":", "");
3783
+ ResultFormatter.eta(results, DateTimeUtils.convertHHMMSSToTod(hhmm));
3784
+ break;
3785
+ case "HDG":
3786
+ ResultFormatter.heading(results, parseInt(val, 10));
3787
+ break;
3788
+ case "NWYP":
3789
+ results.raw.next_waypoint = val;
3790
+ break;
3791
+ case "SWN":
3792
+ ResultFormatter.unknown(results, part, "/");
3793
+ break;
3794
+ case "DWN":
3795
+ ResultFormatter.unknown(results, part, "/");
3796
+ break;
3797
+ case "AD":
3798
+ break;
3799
+ default:
3800
+ ResultFormatter.unknown(results, part, "/");
3801
+ }
4008
3802
  }
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";
3803
+ parseCsvFormat(text, results) {
3804
+ const csvParts = text.split(",");
3805
+ if (csvParts.length !== 9) {
3806
+ return;
4027
3807
  }
4028
- return decodeResult;
3808
+ const header = csvParts[0].trim().split(/\s+/);
3809
+ ResultFormatter.unknown(results, header[0], " ");
3810
+ ResultFormatter.unknown(results, header[1], " ");
3811
+ ResultFormatter.position(
3812
+ results,
3813
+ CoordinateUtils.decodeStringCoordinates(header[2])
3814
+ );
3815
+ ResultFormatter.unknown(results, csvParts[1]);
3816
+ ResultFormatter.time_of_day(
3817
+ results,
3818
+ DateTimeUtils.convertHHMMSSToTod(csvParts[2])
3819
+ );
3820
+ ResultFormatter.unknownArr(results, csvParts.slice(4, 6), ",");
3821
+ ResultFormatter.temperature(
3822
+ results,
3823
+ ((csvParts[6].charAt(0) === "M" ? -1 : 1) * parseInt(csvParts[6].slice(1), 10)).toString()
3824
+ );
3825
+ ResultFormatter.airspeed(results, parseInt(csvParts[7], 10));
3826
+ ResultFormatter.currentFuel(results, parseInt(csvParts[8], 10));
4029
3827
  }
4030
3828
  };
4031
3829
 
4032
- // lib/plugins/Label_4N.ts
4033
- var Label_4N = class extends DecoderPlugin {
4034
- name = "label-4n";
3830
+ // lib/plugins/Label_83.ts
3831
+ var Label_83 = class extends DecoderPlugin {
3832
+ name = "label-83";
4035
3833
  qualifiers() {
4036
3834
  return {
4037
- labels: ["4N"]
3835
+ labels: ["83"]
4038
3836
  };
4039
3837
  }
4040
3838
  decode(message, options = {}) {
@@ -4044,52 +3842,49 @@ var Label_4N = class extends DecoderPlugin {
4044
3842
  decodeResult.formatted.description = "Airline Defined";
4045
3843
  decodeResult.decoded = true;
4046
3844
  const text = message.text;
4047
- const fields = text.split(",");
4048
- if (text.length === 51) {
4049
- decodeResult.raw.day = text.substring(0, 2);
4050
- ResultFormatter.departureAirport(decodeResult, text.substring(8, 11));
4051
- ResultFormatter.arrivalAirport(decodeResult, text.substring(13, 16));
4052
- ResultFormatter.position(
4053
- decodeResult,
4054
- CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
4055
- text.substring(30, 45).replace(/^(.)0/, "$1")
4056
- )
4057
- );
4058
- ResultFormatter.altitude(
3845
+ if (text.substring(0, 10) === "4DH3 ETAT2") {
3846
+ const fields = text.split(/\s+/);
3847
+ if (fields[2].length > 5) {
3848
+ decodeResult.raw.day = fields[2].substring(5);
3849
+ }
3850
+ ResultFormatter.unknown(decodeResult, fields[2].substring(0, 4));
3851
+ const subfields = fields[3].split("/");
3852
+ ResultFormatter.departureAirport(decodeResult, subfields[0]);
3853
+ ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
3854
+ ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
3855
+ ResultFormatter.eta(
4059
3856
  decodeResult,
4060
- Number(text.substring(48, 51)) * 100
3857
+ DateTimeUtils.convertHHMMSSToTod(fields[6] + "00")
4061
3858
  );
4062
- ResultFormatter.unknownArr(
4063
- decodeResult,
4064
- [text.substring(2, 4), text.substring(19, 29)],
4065
- " "
3859
+ } else if (text.substring(0, 5) === "001PR") {
3860
+ decodeResult.raw.day = text.substring(5, 7);
3861
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
3862
+ text.substring(13, 28).replace(/\./g, "")
4066
3863
  );
4067
- } else if (fields.length === 33) {
4068
- decodeResult.raw.date = fields[3];
4069
- if (fields[1] === "B") {
3864
+ if (position) {
3865
+ ResultFormatter.position(decodeResult, position);
3866
+ }
3867
+ ResultFormatter.altitude(decodeResult, Number(text.substring(28, 33)));
3868
+ ResultFormatter.unknown(decodeResult, text.substring(33));
3869
+ } else {
3870
+ const fields = text.replace(/\s/g, "").split(",");
3871
+ if (fields.length === 9) {
3872
+ ResultFormatter.departureAirport(decodeResult, fields[0]);
3873
+ ResultFormatter.arrivalAirport(decodeResult, fields[1]);
3874
+ decodeResult.raw.day = fields[2].substring(0, 2);
3875
+ decodeResult.raw.time = fields[2].substring(2);
4070
3876
  ResultFormatter.position(decodeResult, {
4071
- latitude: Number(fields[4]),
4072
- longitude: Number(fields[5])
3877
+ latitude: Number(fields[3].replace(/\s/g, "")),
3878
+ longitude: Number(fields[4].replace(/\s/g, ""))
4073
3879
  });
4074
- ResultFormatter.altitude(decodeResult, Number(fields[6]));
4075
- }
4076
- ResultFormatter.departureAirport(decodeResult, fields[8]);
4077
- ResultFormatter.arrivalAirport(decodeResult, fields[9]);
4078
- ResultFormatter.alternateAirport(decodeResult, fields[10]);
4079
- ResultFormatter.arrivalRunway(decodeResult, fields[11].split("/")[0]);
4080
- if (fields[12].length > 1) {
4081
- ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
3880
+ ResultFormatter.altitude(decodeResult, Number(fields[5]));
3881
+ ResultFormatter.groundspeed(decodeResult, Number(fields[6]));
3882
+ ResultFormatter.heading(decodeResult, Number(fields[7]));
3883
+ ResultFormatter.unknown(decodeResult, fields[8]);
3884
+ } else {
3885
+ decodeResult.decoded = false;
3886
+ ResultFormatter.unknown(decodeResult, text);
4082
3887
  }
4083
- ResultFormatter.checksum(decodeResult, parseInt(fields[32], 16));
4084
- ResultFormatter.unknownArr(
4085
- decodeResult,
4086
- [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter(
4087
- (f) => f != ""
4088
- )
4089
- );
4090
- } else {
4091
- decodeResult.decoded = false;
4092
- ResultFormatter.unknown(decodeResult, text);
4093
3888
  }
4094
3889
  if (decodeResult.decoded) {
4095
3890
  if (!decodeResult.remaining.text)
@@ -4102,469 +3897,569 @@ var Label_4N = class extends DecoderPlugin {
4102
3897
  }
4103
3898
  };
4104
3899
 
4105
- // lib/plugins/Label_4T_AGFSR.ts
4106
- var Label_4T_AGFSR = class extends DecoderPlugin {
4107
- name = "label-4t-agfsr";
3900
+ // lib/plugins/Label_8E.ts
3901
+ var Label_8E = class extends DecoderPlugin {
3902
+ name = "label-8e";
4108
3903
  qualifiers() {
4109
3904
  return {
4110
- labels: ["4T"],
4111
- preambles: ["AGFSR"]
3905
+ labels: ["8E"]
4112
3906
  };
4113
3907
  }
4114
3908
  decode(message, options = {}) {
4115
3909
  const decodeResult = this.defaultResult();
4116
3910
  decodeResult.decoder.name = this.name;
4117
- decodeResult.formatted.description = "Position Report";
3911
+ decodeResult.formatted.description = "ETA Report";
4118
3912
  decodeResult.message = message;
4119
- const data = message.text.substring(5).split("/");
4120
- if (!message.text.startsWith("AGFSR") || data.length !== 20) {
3913
+ const regex = /^(?<arrival_icao>\w{4}),(?<arrival_eta>\d{4})$/;
3914
+ const results = message.text.match(regex);
3915
+ if (results?.groups) {
4121
3916
  if (options.debug) {
4122
- console.log(`Decoder: Unknown 4T message: ${message.text}`);
3917
+ console.log("Label 8E ETA: groups");
3918
+ console.log(results.groups);
4123
3919
  }
4124
- ResultFormatter.unknown(decodeResult, message.text);
4125
- decodeResult.decoded = false;
4126
- decodeResult.decoder.decodeLevel = "none";
4127
- return decodeResult;
4128
- }
4129
- ResultFormatter.flightNumber(decodeResult, data[0].trim());
4130
- ResultFormatter.departureDay(decodeResult, Number(data[1]));
4131
- ResultFormatter.arrivalDay(decodeResult, Number(data[2]));
4132
- ResultFormatter.departureAirport(
4133
- decodeResult,
4134
- data[3].substring(0, 3),
4135
- "IATA"
4136
- );
4137
- ResultFormatter.arrivalAirport(decodeResult, data[3].substring(3), "IATA");
4138
- ResultFormatter.time_of_day(
4139
- decodeResult,
4140
- DateTimeUtils.convertHHMMSSToTod(data[4].substring(0, 4))
4141
- );
4142
- ResultFormatter.unknown(decodeResult, data[5], "/");
4143
- const lat = data[6].substring(0, 7);
4144
- const lon = data[6].substring(7, 15);
4145
- ResultFormatter.position(decodeResult, {
4146
- latitude: CoordinateUtils.getDirection(lat[6]) * Number(lat.substring(0, 2)) + Number(lat.substring(2, 6)) / 60,
4147
- longitude: CoordinateUtils.getDirection(lon[7]) * Number(lon.substring(0, 3)) + Number(lon.substring(3, 7)) / 60
4148
- });
4149
- ResultFormatter.altitude(decodeResult, 100 * Number(data[7]));
4150
- ResultFormatter.unknownArr(decodeResult, data.slice(8), "/");
4151
- decodeResult.decoded = true;
4152
- decodeResult.decoder.decodeLevel = "partial";
4153
- return decodeResult;
4154
- }
4155
- };
4156
-
4157
- // lib/plugins/Label_58.ts
4158
- var Label_58 = class extends DecoderPlugin {
4159
- name = "label-58";
4160
- qualifiers() {
4161
- return {
4162
- labels: ["58"]
4163
- };
4164
- }
4165
- decode(message, options = {}) {
4166
- const decodeResult = this.defaultResult();
4167
- decodeResult.decoder.name = this.name;
4168
- decodeResult.formatted.description = "Position Report";
4169
- decodeResult.message = message;
4170
- const data = message.text.split("/");
4171
- if (data.length === 8) {
4172
- ResultFormatter.flightNumber(decodeResult, data[0]);
4173
- ResultFormatter.day(decodeResult, Number(data[1]));
4174
- ResultFormatter.time_of_day(
3920
+ ResultFormatter.eta(
4175
3921
  decodeResult,
4176
- DateTimeUtils.convertHHMMSSToTod(data[2])
3922
+ DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta)
4177
3923
  );
4178
- const lat = data[3];
4179
- const lon = data[4];
4180
- ResultFormatter.position(decodeResult, {
4181
- latitude: CoordinateUtils.getDirection(lat[0]) * Number(lat.substring(1)),
4182
- longitude: CoordinateUtils.getDirection(lon[0]) * Number(lon.substring(1))
4183
- });
4184
- ResultFormatter.altitude(decodeResult, Number(data[5]));
4185
- ResultFormatter.unknown(decodeResult, data[6], "/");
4186
- ResultFormatter.unknown(decodeResult, data[7], "/");
4187
- } else {
4188
- if (options.debug) {
4189
- console.log(`Decoder: Unknown 58 message: ${message.text}`);
4190
- }
4191
- ResultFormatter.unknown(decodeResult, message.text);
4192
- decodeResult.decoded = false;
4193
- decodeResult.decoder.decodeLevel = "none";
4194
- return decodeResult;
3924
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
4195
3925
  }
4196
3926
  decodeResult.decoded = true;
4197
- decodeResult.decoder.decodeLevel = "partial";
3927
+ decodeResult.decoder.decodeLevel = "full";
4198
3928
  return decodeResult;
4199
3929
  }
4200
3930
  };
4201
3931
 
4202
- // lib/plugins/Label_4T_ETA.ts
4203
- var Label_4T_ETA = class extends DecoderPlugin {
4204
- name = "label-4t-eta";
3932
+ // lib/plugins/Label_B6.ts
3933
+ var Label_B6_Forwardslash = class extends DecoderPlugin {
3934
+ name = "label-b6-forwardslash";
4205
3935
  qualifiers() {
4206
3936
  return {
4207
- labels: ["4T"],
4208
- preambles: ["ETA"]
3937
+ labels: ["B6"],
3938
+ preambles: ["/"]
4209
3939
  };
4210
3940
  }
4211
3941
  decode(message, options = {}) {
4212
3942
  const decodeResult = this.defaultResult();
4213
3943
  decodeResult.decoder.name = this.name;
4214
- decodeResult.formatted.description = "ETA Report";
3944
+ decodeResult.formatted.description = "CPDLC Message";
4215
3945
  decodeResult.message = message;
4216
- const data = message.text.substring(3).split("/");
4217
- if (!message.text.startsWith("ETA") || data.length !== 3) {
4218
- if (options.debug) {
4219
- console.log(`Decoder: Unknown 4T message: ${message.text}`);
4220
- }
4221
- ResultFormatter.unknown(decodeResult, message.text);
4222
- decodeResult.decoded = false;
4223
- decodeResult.decoder.decodeLevel = "none";
4224
- return decodeResult;
3946
+ if (options.debug) {
3947
+ console.log("CPDLC: " + message);
4225
3948
  }
4226
- ResultFormatter.flightNumber(decodeResult, data[0].trim());
4227
- ResultFormatter.departureDay(decodeResult, Number(data[1]));
4228
- const etaData = data[2].split(" ");
4229
- ResultFormatter.arrivalDay(decodeResult, Number(etaData[0]));
4230
- ResultFormatter.arrivalAirport(decodeResult, etaData[1], "IATA");
4231
- ResultFormatter.eta(
4232
- decodeResult,
4233
- DateTimeUtils.convertHHMMSSToTod(etaData[2].substring(0, 4))
4234
- );
4235
- decodeResult.decoded = true;
4236
- decodeResult.decoder.decodeLevel = "full";
4237
3949
  return decodeResult;
4238
3950
  }
4239
3951
  };
4240
3952
 
4241
- // lib/plugins/Label_80.ts
4242
- var Label_80 = class extends DecoderPlugin {
4243
- name = "label-80";
3953
+ // lib/plugins/Label_ColonComma.ts
3954
+ var Label_ColonComma = class extends DecoderPlugin {
3955
+ name = "label-colon-comma";
4244
3956
  qualifiers() {
4245
3957
  return {
4246
- labels: ["80"],
4247
- preambles: []
3958
+ labels: [":;"]
4248
3959
  };
4249
3960
  }
4250
3961
  decode(message, options = {}) {
4251
3962
  const decodeResult = this.defaultResult();
4252
3963
  decodeResult.decoder.name = this.name;
4253
- decodeResult.formatted.description = "Airline Defined Position Report";
4254
- const lines = message.text.split(/\r?\n/);
4255
- if (lines.length === 1 && lines[0].includes(",")) {
4256
- this.parseCsvFormat(lines[0], decodeResult);
4257
- } else {
4258
- const header = lines[0].trim();
4259
- const headerParts = header.split(",");
4260
- for (let i = 0; i < headerParts.length - 1; i++) {
4261
- const moreFields = headerParts[i].split("/");
4262
- for (const more of moreFields) {
4263
- this.parseTags(more.trim(), decodeResult);
4264
- }
4265
- }
4266
- this.parseHeader(
4267
- headerParts[headerParts.length - 1].trim(),
4268
- decodeResult
4269
- );
4270
- for (let i = 1; i < lines.length; i++) {
4271
- const line = lines[i];
4272
- const parts = line.split("/");
4273
- for (const part of parts) {
4274
- this.parseTags(part.trim(), decodeResult);
4275
- }
4276
- }
4277
- }
4278
- if (decodeResult.formatted.items.length > 0) {
4279
- decodeResult.decoded = true;
4280
- decodeResult.decoder.decodeLevel = decodeResult.remaining.text === void 0 ? "full" : "partial";
4281
- }
3964
+ decodeResult.raw.frequency = Number(message.text) / 1e3;
3965
+ decodeResult.formatted.description = "Aircraft Transceiver Frequency Change";
3966
+ decodeResult.formatted.items.push({
3967
+ type: "frequency",
3968
+ label: "Frequency",
3969
+ value: `${decodeResult.raw.frequency} MHz`,
3970
+ code: "FREQ"
3971
+ });
3972
+ decodeResult.decoded = true;
3973
+ decodeResult.decoder.decodeLevel = "full";
4282
3974
  return decodeResult;
4283
3975
  }
4284
- parseHeader(header, results) {
4285
- const fields = header.split("/");
4286
- if (fields.length < 3) {
4287
- ResultFormatter.unknown(results, header, "/");
4288
- return;
4289
- }
4290
- const msgInfo = fields[0].split(/\s+/);
4291
- if (msgInfo.length === 3) {
4292
- ResultFormatter.unknownArr(results, msgInfo.slice(0, 2), " ");
4293
- ResultFormatter.flightNumber(results, msgInfo[2]);
4294
- } else {
4295
- ResultFormatter.unknown(results, header, "/");
4296
- return;
4297
- }
4298
- const otherInfo1 = fields[1].split(/\s+/);
4299
- if (otherInfo1.length === 2) {
4300
- ResultFormatter.day(results, parseInt(otherInfo1[0], 10));
4301
- ResultFormatter.departureAirport(results, otherInfo1[1]);
4302
- } else {
4303
- ResultFormatter.unknownArr(results, otherInfo1, " ");
4304
- }
4305
- const otherInfo2 = fields[2].split(/\s+/);
4306
- if (otherInfo2.length === 2) {
4307
- ResultFormatter.arrivalAirport(results, otherInfo2[0]);
4308
- ResultFormatter.tail(results, otherInfo2[1].replace(".", ""));
3976
+ };
3977
+
3978
+ // lib/utils/h1_helper.ts
3979
+ var H1Helper = class _H1Helper {
3980
+ static decodeH1Message(decodeResult, message) {
3981
+ const checksum = parseInt(message.slice(-4), 16);
3982
+ const data = message.slice(0, message.length - 4);
3983
+ let checksumAlgorithmUsed = "";
3984
+ if (crc16IbmSdlcRev(data) === checksum) {
3985
+ checksumAlgorithmUsed = "IBM-SDLC reversed";
3986
+ } else if (crc16Genibus(data) === checksum) {
3987
+ checksumAlgorithmUsed = "GENIBUS";
4309
3988
  } else {
4310
- ResultFormatter.unknownArr(results, otherInfo2, " ");
4311
- }
4312
- if (fields.length > 3) {
4313
- ResultFormatter.unknownArr(results, fields.slice(3), "/");
3989
+ decodeResult.decoded = false;
3990
+ decodeResult.decoder.decodeLevel = "none";
3991
+ return false;
4314
3992
  }
4315
- }
4316
- parseTags(part, results) {
4317
- const kvPair = part.split(/\s+/);
4318
- if (kvPair.length < 2) {
4319
- ResultFormatter.unknown(results, part, "/");
4320
- return;
3993
+ const fields = data.split("/");
3994
+ const canDecode = parseMessageType(decodeResult, fields[0]);
3995
+ if (!canDecode) {
3996
+ decodeResult.decoded = false;
3997
+ decodeResult.decoder.decodeLevel = "none";
3998
+ return false;
4321
3999
  }
4322
- const tag = kvPair[0];
4323
- const val = kvPair.slice(1).join(" ");
4324
- switch (tag) {
4325
- case "POS":
4326
- const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
4327
- const posResult = val.match(posRegex);
4328
- const lat = Number(posResult?.groups?.lat) * (posResult?.groups?.latd === "S" ? -1 : 1);
4329
- const lon = Number(posResult?.groups?.lng) * (posResult?.groups?.lngd === "W" ? -1 : 1);
4330
- const position = {
4331
- latitude: Number.isInteger(lat) ? lat / 1e3 : lat / 100,
4332
- longitude: Number.isInteger(lon) ? lon / 1e3 : lon / 100
4333
- };
4334
- ResultFormatter.position(results, position);
4335
- break;
4336
- case "ALT":
4337
- ResultFormatter.altitude(results, parseInt(val.replace("+", ""), 10));
4338
- break;
4339
- case "FL":
4340
- ResultFormatter.altitude(results, parseInt(val, 10) * 100);
4341
- break;
4342
- case "MCH":
4343
- ResultFormatter.mach(results, parseInt(val, 10) / 1e3);
4344
- break;
4345
- case "SPD":
4346
- ResultFormatter.groundspeed(results, parseInt(val, 10));
4347
- break;
4348
- case "TAS":
4349
- ResultFormatter.airspeed(results, parseInt(val, 10));
4350
- break;
4351
- case "SAT":
4352
- ResultFormatter.temperature(results, val);
4353
- break;
4354
- case "FB":
4355
- break;
4356
- case "FOB":
4357
- ResultFormatter.currentFuel(
4358
- results,
4359
- parseInt(val.replace(/\D/g, ""), 10)
4360
- );
4361
- break;
4362
- case "UTC":
4363
- ResultFormatter.time_of_day(
4364
- results,
4365
- DateTimeUtils.convertHHMMSSToTod(val)
4366
- );
4367
- break;
4368
- case "ETA":
4369
- const hhmm = val.split(".")[0].replace(":", "");
4370
- ResultFormatter.eta(results, DateTimeUtils.convertHHMMSSToTod(hhmm));
4371
- break;
4372
- case "HDG":
4373
- ResultFormatter.heading(results, parseInt(val, 10));
4374
- break;
4375
- case "NWYP":
4376
- results.raw.next_waypoint = val;
4377
- break;
4378
- case "SWN":
4379
- ResultFormatter.unknown(results, part, "/");
4380
- break;
4381
- case "DWN":
4382
- ResultFormatter.unknown(results, part, "/");
4383
- break;
4384
- case "AD":
4385
- break;
4386
- default:
4387
- ResultFormatter.unknown(results, part, "/");
4000
+ for (let i = 1; i < fields.length; ++i) {
4001
+ const key = fields[i].substring(0, 2);
4002
+ const data2 = fields[i].substring(2);
4003
+ switch (key) {
4004
+ case "AF":
4005
+ processAirField(decodeResult, data2.split(","));
4006
+ break;
4007
+ case "AK":
4008
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
4009
+ break;
4010
+ case "CG":
4011
+ processCenterOfGravity(decodeResult, data2.split(","));
4012
+ break;
4013
+ case "DC":
4014
+ processDateCode(decodeResult, data2.split(","));
4015
+ break;
4016
+ case "DI":
4017
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
4018
+ break;
4019
+ case "DT":
4020
+ processDT(decodeResult, data2.split(","));
4021
+ break;
4022
+ case "DQ":
4023
+ ResultFormatter.desiredAltitude(
4024
+ decodeResult,
4025
+ parseInt(data2, 10) * 100
4026
+ );
4027
+ break;
4028
+ case "ET":
4029
+ processETA(data2, decodeResult, fields, i);
4030
+ break;
4031
+ case "FB":
4032
+ ResultFormatter.currentFuel(decodeResult, parseInt(data2, 10));
4033
+ break;
4034
+ case "FN":
4035
+ decodeResult.raw.flight_number = data2;
4036
+ break;
4037
+ case "FX":
4038
+ ResultFormatter.freetext(decodeResult, data2);
4039
+ break;
4040
+ case "GA":
4041
+ ResultFormatter.groundAddress(decodeResult, data2);
4042
+ break;
4043
+ case "ID":
4044
+ processIdentification(decodeResult, data2.split(","));
4045
+ break;
4046
+ case "LR":
4047
+ processLandingReport(decodeResult, data2.split(","));
4048
+ break;
4049
+ case "PR":
4050
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
4051
+ break;
4052
+ case "PS":
4053
+ _H1Helper.processPS(decodeResult, data2.split(","));
4054
+ break;
4055
+ case "RF":
4056
+ case "RI":
4057
+ case "RM":
4058
+ case "RP":
4059
+ case "RS":
4060
+ FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
4061
+ break;
4062
+ case "RN":
4063
+ ResultFormatter.routeNumber(decodeResult, data2);
4064
+ break;
4065
+ case "RW":
4066
+ processRunway(decodeResult, data2.split(":"));
4067
+ break;
4068
+ case "SN":
4069
+ decodeResult.raw.serial_number = data2;
4070
+ break;
4071
+ case "SP":
4072
+ ResultFormatter.startPoint(decodeResult, data2);
4073
+ break;
4074
+ case "TD":
4075
+ processTimeOfDeparture(decodeResult, data2.split(","));
4076
+ break;
4077
+ case "TS":
4078
+ _H1Helper.processTimeStamp(decodeResult, data2.split(","));
4079
+ break;
4080
+ case "VR":
4081
+ ResultFormatter.version(decodeResult, parseInt(data2, 10) / 10);
4082
+ break;
4083
+ case "WD":
4084
+ processWindData(decodeResult, data2);
4085
+ break;
4086
+ case "WQ":
4087
+ processWeatherQuery(decodeResult, data2.split(":"));
4088
+ break;
4089
+ default:
4090
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
4091
+ }
4388
4092
  }
4093
+ ResultFormatter.checksumAlgorithm(decodeResult, checksumAlgorithmUsed);
4094
+ ResultFormatter.checksum(decodeResult, checksum);
4095
+ return true;
4389
4096
  }
4390
- parseCsvFormat(text, results) {
4391
- const csvParts = text.split(",");
4392
- const header = csvParts[0].trim().split(/\s+/);
4393
- ResultFormatter.unknown(results, header[0], " ");
4394
- ResultFormatter.unknown(results, header[1], " ");
4395
- ResultFormatter.position(
4396
- results,
4397
- CoordinateUtils.decodeStringCoordinates(header[2])
4097
+ static processPS(decodeResult, data) {
4098
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
4099
+ data[0]
4398
4100
  );
4399
- ResultFormatter.unknown(results, csvParts[1]);
4400
- ResultFormatter.time_of_day(
4401
- results,
4402
- DateTimeUtils.convertHHMMSSToTod(csvParts[2])
4101
+ if (position) {
4102
+ ResultFormatter.position(decodeResult, position);
4103
+ }
4104
+ if (data.length === 9) {
4105
+ processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
4106
+ ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
4107
+ ResultFormatter.temperature(decodeResult, data[6]);
4108
+ ResultFormatter.unknown(decodeResult, data[7]);
4109
+ ResultFormatter.unknown(decodeResult, data[8]);
4110
+ }
4111
+ if (data.length === 14) {
4112
+ ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
4113
+ processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
4114
+ ResultFormatter.temperature(decodeResult, data[7]);
4115
+ ResultFormatter.unknownArr(decodeResult, data.slice(8));
4116
+ }
4117
+ }
4118
+ static processPosition(decodeResult, data) {
4119
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
4120
+ data[0]
4403
4121
  );
4404
- ResultFormatter.unknownArr(results, csvParts.slice(4, 6), ",");
4405
- ResultFormatter.temperature(
4406
- results,
4407
- ((csvParts[6].charAt(0) === "M" ? -1 : 1) * parseInt(csvParts[6].slice(1), 10)).toString()
4122
+ if (position) {
4123
+ ResultFormatter.position(decodeResult, position);
4124
+ }
4125
+ if (data.length >= 10) {
4126
+ ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
4127
+ processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
4128
+ ResultFormatter.temperature(decodeResult, data[7]);
4129
+ ResultFormatter.unknown(decodeResult, data[8]);
4130
+ ResultFormatter.unknown(decodeResult, data[9]);
4131
+ }
4132
+ if (data.length >= 14) {
4133
+ ResultFormatter.unknownArr(decodeResult, data.slice(10));
4134
+ }
4135
+ }
4136
+ static processTimeStamp(decodeResult, data) {
4137
+ if (data.length > 2) {
4138
+ const positionData = data.slice(1);
4139
+ positionData[0] = positionData[0].substring(6);
4140
+ this.processPosition(decodeResult, positionData);
4141
+ }
4142
+ let time = DateTimeUtils.convertDateTimeToEpoch(
4143
+ data[0],
4144
+ data[1].substring(0, 6)
4408
4145
  );
4409
- ResultFormatter.airspeed(results, parseInt(csvParts[7], 10));
4410
- ResultFormatter.currentFuel(results, parseInt(csvParts[8], 10));
4146
+ if (Number.isNaN(time)) {
4147
+ const date = data[1].substring(2, 4) + data[1].substring(0, 2) + data[1].substring(4, 6);
4148
+ time = DateTimeUtils.convertDateTimeToEpoch(data[0], date);
4149
+ }
4150
+ decodeResult.raw.message_timestamp = time;
4411
4151
  }
4412
4152
  };
4413
-
4414
- // lib/plugins/Label_83.ts
4415
- var Label_83 = class extends DecoderPlugin {
4416
- name = "label-83";
4417
- qualifiers() {
4418
- return {
4419
- labels: ["83"]
4420
- };
4153
+ function processETA(data, decodeResult, fields, i) {
4154
+ if (data.length === 5) {
4155
+ ResultFormatter.day(decodeResult, Number(data.substring(0, 1)));
4156
+ ResultFormatter.eta(
4157
+ decodeResult,
4158
+ DateTimeUtils.convertHHMMSSToTod(data.substring(1))
4159
+ );
4160
+ } else if (data.length === 6) {
4161
+ ResultFormatter.day(decodeResult, Number(data.substring(0, 2)));
4162
+ ResultFormatter.eta(
4163
+ decodeResult,
4164
+ DateTimeUtils.convertHHMMSSToTod(data.substring(2))
4165
+ );
4166
+ } else {
4167
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
4421
4168
  }
4422
- decode(message, options = {}) {
4423
- const decodeResult = this.defaultResult();
4424
- decodeResult.decoder.name = this.name;
4425
- decodeResult.message = message;
4426
- decodeResult.formatted.description = "Airline Defined";
4427
- decodeResult.decoded = true;
4428
- const text = message.text;
4429
- if (text.substring(0, 10) === "4DH3 ETAT2") {
4430
- const fields = text.split(/\s+/);
4431
- if (fields[2].length > 5) {
4432
- decodeResult.raw.day = fields[2].substring(5);
4433
- }
4434
- ResultFormatter.unknown(decodeResult, fields[2].substring(0, 4));
4435
- const subfields = fields[3].split("/");
4436
- ResultFormatter.departureAirport(decodeResult, subfields[0]);
4437
- ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
4438
- ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
4439
- ResultFormatter.eta(
4440
- decodeResult,
4441
- DateTimeUtils.convertHHMMSSToTod(fields[6] + "00")
4442
- );
4443
- } else if (text.substring(0, 5) === "001PR") {
4444
- decodeResult.raw.day = text.substring(5, 7);
4445
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
4446
- text.substring(13, 28).replace(/\./g, "")
4447
- );
4448
- if (position) {
4449
- ResultFormatter.position(decodeResult, position);
4450
- }
4451
- ResultFormatter.altitude(decodeResult, Number(text.substring(28, 33)));
4452
- ResultFormatter.unknown(decodeResult, text.substring(33));
4453
- } else {
4454
- const fields = text.replace(/\s/g, "").split(",");
4455
- if (fields.length === 9) {
4456
- ResultFormatter.departureAirport(decodeResult, fields[0]);
4457
- ResultFormatter.arrivalAirport(decodeResult, fields[1]);
4458
- decodeResult.raw.day = fields[2].substring(0, 2);
4459
- decodeResult.raw.time = fields[2].substring(2);
4460
- ResultFormatter.position(decodeResult, {
4461
- latitude: Number(fields[3].replace(/\s/g, "")),
4462
- longitude: Number(fields[4].replace(/\s/g, ""))
4463
- });
4464
- ResultFormatter.altitude(decodeResult, Number(fields[5]));
4465
- ResultFormatter.groundspeed(decodeResult, Number(fields[6]));
4466
- ResultFormatter.heading(decodeResult, Number(fields[7]));
4467
- ResultFormatter.unknown(decodeResult, fields[8]);
4468
- } else {
4469
- decodeResult.decoded = false;
4470
- ResultFormatter.unknown(decodeResult, text);
4471
- }
4169
+ }
4170
+ function processAirField(decodeResult, data) {
4171
+ if (data.length === 2) {
4172
+ ResultFormatter.departureAirport(decodeResult, data[0]);
4173
+ ResultFormatter.arrivalAirport(decodeResult, data[1]);
4174
+ } else {
4175
+ ResultFormatter.unknown(decodeResult, data.join(","), "AF/");
4176
+ }
4177
+ }
4178
+ function processTimeOfDeparture(decodeResult, data) {
4179
+ if (data.length === 2) {
4180
+ decodeResult.raw.plannedDepartureTime = data[0];
4181
+ decodeResult.formatted.items.push({
4182
+ type: "ptd",
4183
+ code: "ptd",
4184
+ label: "Planned Departure Time",
4185
+ value: `YYYY-MM-${data[0].substring(0, 2)}T${data[0].substring(2, 4)}:${data[0].substring(4)}:00Z`
4186
+ });
4187
+ decodeResult.raw.plannedDepartureTime = data[1];
4188
+ decodeResult.formatted.items.push({
4189
+ type: "etd",
4190
+ code: "etd",
4191
+ label: "Estimated Departure Time",
4192
+ value: `${data[1].substring(0, 2)}:${data[1].substring(2)}`
4193
+ });
4194
+ } else {
4195
+ ResultFormatter.unknown(decodeResult, data.join(","), "/TD");
4196
+ }
4197
+ }
4198
+ function processIdentification(decodeResult, data) {
4199
+ ResultFormatter.tail(decodeResult, data[0]);
4200
+ if (data.length > 1) {
4201
+ ResultFormatter.flightNumber(decodeResult, data[1]);
4202
+ }
4203
+ if (data.length > 2) {
4204
+ decodeResult.raw.mission_number = data[2];
4205
+ }
4206
+ }
4207
+ function processDT(decodeResult, data) {
4208
+ if (data.length === 9) {
4209
+ ResultFormatter.unknown(decodeResult, data[0]);
4210
+ if (!decodeResult.raw.arrival_icao) {
4211
+ ResultFormatter.arrivalAirport(decodeResult, data[1]);
4472
4212
  }
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";
4213
+ ResultFormatter.arrivalRunway(decodeResult, data[2]);
4214
+ ResultFormatter.currentFuel(decodeResult, parseInt(data[3], 10));
4215
+ ResultFormatter.eta(
4216
+ decodeResult,
4217
+ DateTimeUtils.convertHHMMSSToTod(data[4])
4218
+ );
4219
+ ResultFormatter.unknown(decodeResult, data[5]);
4220
+ ResultFormatter.position(
4221
+ decodeResult,
4222
+ CoordinateUtils.decodeStringCoordinates(data[6])
4223
+ );
4224
+ ResultFormatter.unknown(decodeResult, data[7]);
4225
+ ResultFormatter.unknown(decodeResult, data[8]);
4226
+ return;
4227
+ }
4228
+ if (data.length === 4 || data.length === 5) {
4229
+ if (!decodeResult.raw.arrival_icao) {
4230
+ ResultFormatter.arrivalAirport(decodeResult, data[0]);
4479
4231
  }
4480
- return decodeResult;
4232
+ ResultFormatter.arrivalRunway(decodeResult, data[1]);
4233
+ ResultFormatter.currentFuel(decodeResult, parseInt(data[2], 10));
4234
+ ResultFormatter.eta(
4235
+ decodeResult,
4236
+ DateTimeUtils.convertHHMMSSToTod(data[3])
4237
+ );
4238
+ if (data.length > 4) {
4239
+ ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
4240
+ }
4241
+ return;
4481
4242
  }
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
- };
4243
+ ResultFormatter.unknownArr(decodeResult, data, ",");
4244
+ }
4245
+ function processLandingReport(decodeResult, data) {
4246
+ if (data.length === 19) {
4247
+ ResultFormatter.unknown(decodeResult, data[1]);
4248
+ ResultFormatter.flightNumber(decodeResult, data[2]);
4249
+ ResultFormatter.departureAirport(decodeResult, data[3]);
4250
+ ResultFormatter.arrivalAirport(decodeResult, data[4]);
4251
+ ResultFormatter.arrivalRunway(decodeResult, data[5]);
4252
+ ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
4253
+ } else {
4254
+ ResultFormatter.unknown(decodeResult, data.join(","));
4255
+ }
4256
+ }
4257
+ function processCenterOfGravity(decodeResult, data) {
4258
+ if (data.length === 1) {
4259
+ if (data[0] !== void 0 && data[0] !== "") {
4260
+ ResultFormatter.cg(decodeResult, parseInt(data[0], 10) / 10);
4261
+ }
4262
+ } else if (data.length === 3) {
4263
+ if (data[0] !== void 0 && data[0] !== "") {
4264
+ ResultFormatter.cg(decodeResult, parseInt(data[0], 10) / 10, "center");
4265
+ }
4266
+ if (data[1] !== void 0 && data[1] !== "") {
4267
+ ResultFormatter.cg(decodeResult, parseInt(data[1], 10) / 10, "lower");
4268
+ }
4269
+ if (data[2] !== void 0 && data[2] !== "") {
4270
+ ResultFormatter.cg(decodeResult, parseInt(data[2], 10) / 10, "upper");
4271
+ }
4272
+ } else {
4273
+ ResultFormatter.unknown(decodeResult, data.join(","));
4491
4274
  }
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);
4503
- }
4504
- ResultFormatter.eta(
4275
+ }
4276
+ function parseMessageType(decodeResult, messagePart) {
4277
+ const messageParts = messagePart.split(",");
4278
+ const messageType = messageParts[0];
4279
+ if (messageType.startsWith("POS")) {
4280
+ H1Helper.processPosition(decodeResult, messagePart.substring(3).split(","));
4281
+ return processMessageType(decodeResult, "POS");
4282
+ } else if (messageType.length === 6) {
4283
+ const part1 = processMessageType(decodeResult, messageType.substring(0, 3));
4284
+ const description = decodeResult.formatted.description;
4285
+ const part2 = processMessageType(decodeResult, messageType.substring(3, 6));
4286
+ decodeResult.formatted.description = description + " for " + decodeResult.formatted.description;
4287
+ if (messageParts.length > 1) {
4288
+ ResultFormatter.unknown(
4505
4289
  decodeResult,
4506
- DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta)
4290
+ messageParts.slice(1).join(","),
4291
+ "/"
4507
4292
  );
4508
- ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
4509
4293
  }
4510
- decodeResult.decoded = true;
4511
- decodeResult.decoder.decodeLevel = "full";
4512
- return decodeResult;
4294
+ return part1 && part2;
4513
4295
  }
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
- };
4296
+ if (messageParts.length > 1) {
4297
+ ResultFormatter.unknown(decodeResult, messageParts.slice(1).join(","), "/");
4524
4298
  }
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);
4532
- }
4533
- return decodeResult;
4299
+ return processMessageType(decodeResult, messageType);
4300
+ }
4301
+ function processMessageType(decodeResult, type) {
4302
+ if (type === "FPN") {
4303
+ decodeResult.formatted.description = "Flight Plan";
4304
+ } else if (type === "FTX") {
4305
+ decodeResult.formatted.description = "Free Text";
4306
+ } else if (type === "INI") {
4307
+ decodeResult.formatted.description = "Initial Report";
4308
+ } else if (type === "INR") {
4309
+ decodeResult.formatted.description = "In-Range Report";
4310
+ } else if (type === "LDI") {
4311
+ decodeResult.formatted.description = "Load Distribution Information";
4312
+ } else if (type === "PER") {
4313
+ decodeResult.formatted.description = "Performance Report";
4314
+ } else if (type === "POS") {
4315
+ decodeResult.formatted.description = "Position Report";
4316
+ } else if (type === "PRG") {
4317
+ decodeResult.formatted.description = "Progress Report";
4318
+ } else if (type === "PWI") {
4319
+ decodeResult.formatted.description = "Pilot Weather Information";
4320
+ } else if (type === "WXR") {
4321
+ decodeResult.formatted.description = "Weather Report";
4322
+ } else if (type === "REJ") {
4323
+ decodeResult.formatted.description = "Reject";
4324
+ } else if (type === "REQ") {
4325
+ decodeResult.formatted.description = "Request";
4326
+ } else if (type === "RES") {
4327
+ decodeResult.formatted.description = "Response";
4328
+ } else {
4329
+ decodeResult.formatted.description = "Unknown H1 Message";
4330
+ return false;
4534
4331
  }
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
- };
4332
+ return true;
4333
+ }
4334
+ function processDateCode(decodeResult, data) {
4335
+ if (data.length === 1) {
4336
+ } else if (data.length === 2) {
4337
+ const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
4338
+ const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
4339
+ decodeResult.raw.message_timestamp = time;
4544
4340
  }
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;
4341
+ }
4342
+ function processWeatherQuery(decodeResult, data) {
4343
+ if (data.length !== 2) {
4344
+ ResultFormatter.unknown(decodeResult, data.join(":"), "WQ/");
4345
+ return;
4559
4346
  }
4560
- };
4347
+ const alts = data[0].split(".");
4348
+ const route = data[1].split(".");
4349
+ ResultFormatter.requestedAltitudes(
4350
+ decodeResult,
4351
+ alts.map((a) => parseInt(a, 10) * 100)
4352
+ );
4353
+ const waypoints = route.map((wp) => {
4354
+ return { name: wp };
4355
+ });
4356
+ ResultFormatter.route(decodeResult, { waypoints });
4357
+ }
4358
+ function processRoute(decodeResult, last, time, next, eta, then, date) {
4359
+ const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
4360
+ const nextTime = date ? DateTimeUtils.convertDateTimeToEpoch(eta, date) : DateTimeUtils.convertHHMMSSToTod(eta);
4361
+ const timeFormat = date ? "epoch" : "tod";
4362
+ const lastWaypoint = RouteUtils.getWaypoint(last);
4363
+ lastWaypoint.time = lastTime;
4364
+ lastWaypoint.timeFormat = timeFormat;
4365
+ const nextWaypoint = RouteUtils.getWaypoint(next);
4366
+ nextWaypoint.time = nextTime;
4367
+ nextWaypoint.timeFormat = timeFormat;
4368
+ const thenWaypoint = RouteUtils.getWaypoint(then || "?");
4369
+ const waypoints = [lastWaypoint, nextWaypoint, thenWaypoint];
4370
+ ResultFormatter.route(decodeResult, { waypoints });
4371
+ }
4372
+ function processWindData(decodeResult, message) {
4373
+ const wind = [];
4374
+ const flightLevel = Number(message.slice(0, 3));
4375
+ const fields = message.slice(4).split(".");
4376
+ fields.forEach((field) => {
4377
+ if (field.length < 4) {
4378
+ return;
4379
+ }
4380
+ const data = field.split(",");
4381
+ const waypoint = { name: data[0] };
4382
+ const windData = data[1];
4383
+ const windDirection = parseInt(windData.slice(0, 3), 10);
4384
+ const windSpeed = parseInt(windData.slice(3), 10);
4385
+ if (data.length === 3) {
4386
+ const tempData = data[2];
4387
+ const tempFlightLevel = Number(tempData.slice(0, 3));
4388
+ const tempString = tempData.slice(3);
4389
+ const tempDegrees = Number(tempString.substring(1)) * (tempString.charAt(0) === "M" ? -1 : 1);
4390
+ wind.push({
4391
+ waypoint,
4392
+ flightLevel,
4393
+ windDirection,
4394
+ windSpeed,
4395
+ temperature: {
4396
+ flightLevel: tempFlightLevel,
4397
+ degreesC: tempDegrees
4398
+ }
4399
+ });
4400
+ } else {
4401
+ wind.push({
4402
+ waypoint,
4403
+ flightLevel,
4404
+ windDirection,
4405
+ windSpeed
4406
+ });
4407
+ }
4408
+ });
4409
+ ResultFormatter.windData(decodeResult, wind);
4410
+ }
4411
+ function processRunway(decodeResult, data) {
4412
+ const parts = data[0].split(".");
4413
+ const more = parts[0].split(",");
4414
+ ResultFormatter.departureRunway(decodeResult, more[0]);
4415
+ ResultFormatter.unknownArr(decodeResult, more.slice(1), ",");
4416
+ ResultFormatter.unknownArr(decodeResult, parts.slice(1), ".");
4417
+ ResultFormatter.departureAirport(decodeResult, data[1].split(",")[0]);
4418
+ ResultFormatter.unknownArr(decodeResult, data[1].split(",").slice(1), ",");
4419
+ }
4420
+ function crc16IbmSdlcRev(data) {
4421
+ let crc = 65535;
4422
+ const bytes = Buffer.from(data, "ascii");
4423
+ for (const byte of bytes) {
4424
+ crc ^= byte;
4425
+ for (let i = 0; i < 8; i++) {
4426
+ if ((crc & 1) !== 0) {
4427
+ crc = crc >>> 1 ^ 33800;
4428
+ } else {
4429
+ crc = crc >>> 1;
4430
+ }
4431
+ }
4432
+ }
4433
+ crc = (crc ^ 65535) & 65535;
4434
+ const nibble1 = crc >> 12 & 15;
4435
+ const nibble2 = crc >> 8 & 15;
4436
+ const nibble3 = crc >> 4 & 15;
4437
+ const nibble4 = crc & 15;
4438
+ return nibble4 << 12 | nibble3 << 8 | nibble2 << 4 | nibble1;
4439
+ }
4440
+ function crc16Genibus(data) {
4441
+ let crc = 65535;
4442
+ const polynomial = 4129;
4443
+ const bytes = Buffer.from(data, "ascii");
4444
+ for (const byte of bytes) {
4445
+ crc ^= byte << 8;
4446
+ for (let i = 0; i < 8; i++) {
4447
+ if ((crc & 32768) !== 0) {
4448
+ crc = (crc << 1 ^ polynomial) & 65535;
4449
+ } else {
4450
+ crc = crc << 1 & 65535;
4451
+ }
4452
+ }
4453
+ }
4454
+ return (crc ^ 65535) & 65535;
4455
+ }
4561
4456
 
4562
4457
  // lib/plugins/Label_H1.ts
4563
4458
  var Label_H1 = class extends DecoderPlugin {
4564
4459
  name = "label-h1";
4565
4460
  qualifiers() {
4566
4461
  return {
4567
- labels: ["H1"]
4462
+ labels: ["1J", "2J", "2P", "4J", "80", "H1"]
4568
4463
  };
4569
4464
  }
4570
4465
  decode(message, options = {}) {
@@ -4572,33 +4467,58 @@ var Label_H1 = class extends DecoderPlugin {
4572
4467
  decodeResult.decoder.name = this.name;
4573
4468
  decodeResult.message = message;
4574
4469
  const msg = message.text.replace(/\n|\r/g, "");
4575
- const parts = msg.split("#");
4576
4470
  let decoded = false;
4471
+ decoded = H1Helper.decodeH1Message(decodeResult, msg);
4472
+ if (decoded) {
4473
+ return this.processDecodeResult(decodeResult, decoded, options, message);
4474
+ }
4577
4475
  if (msg.startsWith("/")) {
4578
4476
  const headerData = msg.split(".");
4579
- const decoded2 = H1Helper.decodeH1Message(
4477
+ decoded = H1Helper.decodeH1Message(
4580
4478
  decodeResult,
4581
4479
  headerData.slice(1).join(".")
4582
4480
  );
4583
- if (decoded2) {
4481
+ if (decoded) {
4584
4482
  decodeResult.remaining.text = headerData[0] + "." + decodeResult.remaining.text;
4585
- decodeResult.decoded = decoded2;
4586
- decodeResult.decoder.decodeLevel = "partial";
4483
+ return this.processDecodeResult(
4484
+ decodeResult,
4485
+ decoded,
4486
+ options,
4487
+ message
4488
+ );
4587
4489
  }
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;
4490
+ }
4491
+ const hashParts = msg.split("#");
4492
+ if (hashParts.length == 2) {
4493
+ const offset = hashParts[0] === "- " || isNaN(parseInt(hashParts[1][1])) ? 3 : 4;
4593
4494
  decoded = H1Helper.decodeH1Message(
4594
4495
  decodeResult,
4595
- msg.slice(parts[0].length + offset)
4496
+ msg.slice(hashParts[0].length + offset)
4596
4497
  );
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;
4498
+ if (decoded && hashParts[0].length > 0) {
4499
+ ResultFormatter.flightNumber(decodeResult, hashParts[0].substring(4));
4500
+ decodeResult.remaining.text = hashParts[0].substring(0, 4) + "#" + hashParts[1].substring(0, offset - 1) + "/" + decodeResult.remaining.text;
4600
4501
  }
4502
+ if (decoded) {
4503
+ return this.processDecodeResult(
4504
+ decodeResult,
4505
+ decoded,
4506
+ options,
4507
+ message
4508
+ );
4509
+ }
4510
+ }
4511
+ const slashParts = msg.split("/");
4512
+ if (slashParts[0].length > 3) {
4513
+ decoded = H1Helper.decodeH1Message(
4514
+ decodeResult,
4515
+ msg.slice(slashParts[0].length - 3)
4516
+ );
4517
+ decodeResult.remaining.text = slashParts[0].slice(0, 3) + "/" + decodeResult.remaining.text;
4601
4518
  }
4519
+ return this.processDecodeResult(decodeResult, decoded, options, message);
4520
+ }
4521
+ processDecodeResult(decodeResult, decoded, options, message) {
4602
4522
  decodeResult.decoded = decoded;
4603
4523
  decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
4604
4524
  if (decodeResult.formatted.items.length === 0) {
@@ -6231,7 +6151,6 @@ var MessageDecoder = class {
6231
6151
  this.registerPlugin(new Label_16_N_Space(this));
6232
6152
  this.registerPlugin(new Label_16_POSA1(this));
6233
6153
  this.registerPlugin(new Label_16_TOD(this));
6234
- this.registerPlugin(new Label_1J_2J_FTX(this));
6235
6154
  this.registerPlugin(new Label_1L_3Line(this));
6236
6155
  this.registerPlugin(new Label_1L_070(this));
6237
6156
  this.registerPlugin(new Label_1L_660(this));
@@ -6244,7 +6163,6 @@ var MessageDecoder = class {
6244
6163
  this.registerPlugin(new Label_2P_FM3(this));
6245
6164
  this.registerPlugin(new Label_2P_FM4(this));
6246
6165
  this.registerPlugin(new Label_2P_FM5(this));
6247
- this.registerPlugin(new Label_2P_POS(this));
6248
6166
  this.registerPlugin(new Label_30_Slash_EA(this));
6249
6167
  this.registerPlugin(new Label_44_ETA(this));
6250
6168
  this.registerPlugin(new Label_44_IN(this));
@@ -6257,7 +6175,6 @@ var MessageDecoder = class {
6257
6175
  this.registerPlugin(new Label_4A_DIS(this));
6258
6176
  this.registerPlugin(new Label_4A_DOOR(this));
6259
6177
  this.registerPlugin(new Label_4A_Slash_01(this));
6260
- this.registerPlugin(new Label_4J_POS(this));
6261
6178
  this.registerPlugin(new Label_4N(this));
6262
6179
  this.registerPlugin(new Label_4T_AGFSR(this));
6263
6180
  this.registerPlugin(new Label_4T_ETA(this));