@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.js CHANGED
@@ -1867,698 +1867,6 @@ var Label_16_TOD = class extends DecoderPlugin {
1867
1867
  }
1868
1868
  };
1869
1869
 
1870
- // lib/utils/flight_plan_utils.ts
1871
- var FlightPlanUtils = class _FlightPlanUtils {
1872
- /**
1873
- * Processes flight plan data
1874
- *
1875
- * Expected format is [header, key1, val1, ... keyN, valN]
1876
- *
1877
- * @param decodeResult - results
1878
- * @param data - original message split by ':'
1879
- * @returns whether all fields were processed or not
1880
- */
1881
- static processFlightPlan(decodeResult, data) {
1882
- let allKnownFields = _FlightPlanUtils.parseHeader(decodeResult, data[0]);
1883
- for (let i = 1; i < data.length; i += 2) {
1884
- const key = data[i];
1885
- const value = data[i + 1];
1886
- switch (key) {
1887
- case "A":
1888
- _FlightPlanUtils.addProcedure(decodeResult, value, "arrival");
1889
- break;
1890
- case "AA":
1891
- addArrivalAirport(decodeResult, value);
1892
- break;
1893
- case "AP":
1894
- _FlightPlanUtils.addProcedure(decodeResult, value, "approach");
1895
- break;
1896
- case "CR":
1897
- addCompanyRoute(decodeResult, value);
1898
- break;
1899
- case "D":
1900
- _FlightPlanUtils.addProcedure(decodeResult, value, "departure");
1901
- break;
1902
- case "DA":
1903
- addDepartureAirport(decodeResult, value);
1904
- break;
1905
- case "F":
1906
- addRoute(decodeResult, value);
1907
- break;
1908
- case "FP":
1909
- ResultFormatter.flightPlan(decodeResult, value.trim());
1910
- break;
1911
- case "R":
1912
- addRunway(decodeResult, value);
1913
- break;
1914
- // case 'WS': // something about routes, has altitude, so current parsing won't work
1915
- // break;
1916
- default:
1917
- if (allKnownFields) {
1918
- decodeResult.remaining.text = "";
1919
- allKnownFields = false;
1920
- }
1921
- decodeResult.remaining.text += `:${key}:${value}`;
1922
- decodeResult.decoder.decodeLevel = "partial";
1923
- }
1924
- }
1925
- return allKnownFields;
1926
- }
1927
- static parseHeader(decodeResult, header) {
1928
- let allKnownFields = true;
1929
- if (header.startsWith("RF")) {
1930
- decodeResult.formatted.items.push({
1931
- type: "status",
1932
- code: "ROUTE_STATUS",
1933
- label: "Route Status",
1934
- value: "Route Filed"
1935
- });
1936
- decodeResult.raw.route_status = "RF";
1937
- if (header.length > 2) {
1938
- addRoute(decodeResult, header.substring(2));
1939
- }
1940
- } else if (header.startsWith("RP")) {
1941
- decodeResult.raw.route_status = "RP";
1942
- decodeResult.formatted.items.push({
1943
- type: "status",
1944
- code: "ROUTE_STATUS",
1945
- label: "Route Status",
1946
- value: "Route Planned"
1947
- });
1948
- decodeResult.raw.route_status = header;
1949
- } else if (header.startsWith("RI")) {
1950
- decodeResult.raw.route_status = "RI";
1951
- decodeResult.formatted.items.push({
1952
- type: "status",
1953
- code: "ROUTE_STATUS",
1954
- label: "Route Status",
1955
- value: "Route Inactive"
1956
- });
1957
- } else if (header.startsWith("RM")) {
1958
- decodeResult.raw.route_status = "RM";
1959
- decodeResult.formatted.items.push({
1960
- type: "status",
1961
- code: "ROUTE_STATUS",
1962
- label: "Route Status",
1963
- value: "Route Mapped"
1964
- });
1965
- } else if (header.startsWith("RS")) {
1966
- decodeResult.raw.route_status = "RS";
1967
- decodeResult.formatted.items.push({
1968
- type: "status",
1969
- code: "ROUTE_STATUS",
1970
- label: "Route Status",
1971
- value: "Route Saved"
1972
- });
1973
- } else {
1974
- decodeResult.remaining.text += header;
1975
- allKnownFields = false;
1976
- }
1977
- return allKnownFields;
1978
- }
1979
- static addProcedure(decodeResult, value, type) {
1980
- if (decodeResult.raw.procedures === void 0) {
1981
- decodeResult.raw.procedures = [];
1982
- }
1983
- const data = value.split(".");
1984
- let waypoints;
1985
- if (data.length > 1) {
1986
- waypoints = data.slice(1).map((leg) => RouteUtils.getWaypoint(leg));
1987
- }
1988
- const route = { name: data[0], waypoints };
1989
- decodeResult.raw.procedures.push({ type, route });
1990
- const procedureName = type.substring(0, 1).toUpperCase() + type.slice(1);
1991
- decodeResult.formatted.items.push({
1992
- type: "procedure",
1993
- code: "proc",
1994
- label: `${procedureName} Procedure`,
1995
- value: RouteUtils.routeToString(route)
1996
- });
1997
- }
1998
- };
1999
- function addArrivalAirport(decodeResult, value) {
2000
- ResultFormatter.arrivalAirport(decodeResult, value);
2001
- }
2002
- function addDepartureAirport(decodeResult, value) {
2003
- ResultFormatter.departureAirport(decodeResult, value);
2004
- }
2005
- function addRunway(decodeResult, value) {
2006
- if (value.length === 8) {
2007
- ResultFormatter.arrivalRunway(decodeResult, value.substring(4, 7));
2008
- }
2009
- ResultFormatter.departureRunway(decodeResult, value.substring(0, 3));
2010
- }
2011
- function addRoute(decodeResult, value) {
2012
- const route = value.split(".");
2013
- ResultFormatter.route(decodeResult, {
2014
- waypoints: route.map((leg) => RouteUtils.getWaypoint(leg))
2015
- });
2016
- }
2017
- function addCompanyRoute(decodeResult, value) {
2018
- const segments = value.split(".");
2019
- const parens_idx = segments[0].indexOf("(");
2020
- let name;
2021
- let runway;
2022
- if (parens_idx === -1) {
2023
- name = segments[0];
2024
- } else {
2025
- name = segments[0].slice(0, parens_idx);
2026
- runway = segments[0].slice(parens_idx + 1, segments[0].indexOf(")"));
2027
- }
2028
- let waypoints;
2029
- if (segments.length > 1) {
2030
- waypoints = segments.slice(1).map((leg) => RouteUtils.getWaypoint(leg));
2031
- }
2032
- decodeResult.raw.company_route = {
2033
- name,
2034
- runway,
2035
- waypoints
2036
- };
2037
- decodeResult.formatted.items.push({
2038
- type: "company_route",
2039
- code: "CR",
2040
- label: "Company Route",
2041
- value: RouteUtils.routeToString(decodeResult.raw.company_route)
2042
- });
2043
- }
2044
-
2045
- // lib/utils/h1_helper.ts
2046
- var H1Helper = class _H1Helper {
2047
- static decodeH1Message(decodeResult, message) {
2048
- const checksum = parseInt(message.slice(-4), 16);
2049
- const data = message.slice(0, message.length - 4);
2050
- let checksumAlgorithmUsed = "";
2051
- if (crc16IbmSdlcRev(data) === checksum) {
2052
- checksumAlgorithmUsed = "IBM-SDLC reversed";
2053
- } else if (crc16Genibus(data) === checksum) {
2054
- checksumAlgorithmUsed = "GENIBUS";
2055
- } else {
2056
- decodeResult.decoded = false;
2057
- decodeResult.decoder.decodeLevel = "none";
2058
- return false;
2059
- }
2060
- const fields = data.split("/");
2061
- const canDecode = parseMessageType(decodeResult, fields[0]);
2062
- if (!canDecode) {
2063
- decodeResult.decoded = false;
2064
- decodeResult.decoder.decodeLevel = "none";
2065
- return false;
2066
- }
2067
- for (let i = 1; i < fields.length; ++i) {
2068
- const key = fields[i].substring(0, 2);
2069
- const data2 = fields[i].substring(2);
2070
- switch (key) {
2071
- case "AF":
2072
- processAirField(decodeResult, data2.split(","));
2073
- break;
2074
- case "AK":
2075
- ResultFormatter.unknown(decodeResult, fields[i], "/");
2076
- break;
2077
- case "CG":
2078
- processCenterOfGravity(decodeResult, data2.split(","));
2079
- break;
2080
- case "DC":
2081
- processDateCode(decodeResult, data2.split(","));
2082
- break;
2083
- case "DI":
2084
- ResultFormatter.unknown(decodeResult, fields[i], "/");
2085
- break;
2086
- case "DT":
2087
- processDT(decodeResult, data2.split(","));
2088
- break;
2089
- case "DQ":
2090
- ResultFormatter.desiredAltitude(
2091
- decodeResult,
2092
- parseInt(data2, 10) * 100
2093
- );
2094
- break;
2095
- case "ET":
2096
- processETA(data2, decodeResult, fields, i);
2097
- break;
2098
- case "FB":
2099
- ResultFormatter.currentFuel(decodeResult, parseInt(data2, 10));
2100
- break;
2101
- case "FN":
2102
- decodeResult.raw.flight_number = data2;
2103
- break;
2104
- case "FX":
2105
- ResultFormatter.freetext(decodeResult, data2);
2106
- break;
2107
- case "GA":
2108
- ResultFormatter.groundAddress(decodeResult, data2);
2109
- break;
2110
- case "ID":
2111
- processIdentification(decodeResult, data2.split(","));
2112
- break;
2113
- case "LR":
2114
- processLandingReport(decodeResult, data2.split(","));
2115
- break;
2116
- case "PR":
2117
- ResultFormatter.unknown(decodeResult, fields[i], "/");
2118
- break;
2119
- case "PS":
2120
- _H1Helper.processPS(decodeResult, data2.split(","));
2121
- break;
2122
- case "RF":
2123
- case "RI":
2124
- case "RM":
2125
- case "RP":
2126
- case "RS":
2127
- FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
2128
- break;
2129
- case "RN":
2130
- ResultFormatter.routeNumber(decodeResult, data2);
2131
- break;
2132
- case "RW":
2133
- processRunway(decodeResult, data2.split(":"));
2134
- break;
2135
- case "SN":
2136
- decodeResult.raw.serial_number = data2;
2137
- break;
2138
- case "SP":
2139
- ResultFormatter.startPoint(decodeResult, data2);
2140
- break;
2141
- case "TD":
2142
- processTimeOfDeparture(decodeResult, data2.split(","));
2143
- break;
2144
- case "TS":
2145
- _H1Helper.processTimeStamp(decodeResult, data2.split(","));
2146
- break;
2147
- case "VR":
2148
- ResultFormatter.version(decodeResult, parseInt(data2, 10) / 10);
2149
- break;
2150
- case "WD":
2151
- processWindData(decodeResult, data2);
2152
- break;
2153
- case "WQ":
2154
- processWeatherQuery(decodeResult, data2.split(":"));
2155
- break;
2156
- default:
2157
- ResultFormatter.unknown(decodeResult, fields[i], "/");
2158
- }
2159
- }
2160
- ResultFormatter.checksumAlgorithm(decodeResult, checksumAlgorithmUsed);
2161
- ResultFormatter.checksum(decodeResult, checksum);
2162
- return true;
2163
- }
2164
- static processPS(decodeResult, data) {
2165
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
2166
- data[0]
2167
- );
2168
- if (position) {
2169
- ResultFormatter.position(decodeResult, position);
2170
- }
2171
- if (data.length === 9) {
2172
- processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
2173
- ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
2174
- ResultFormatter.temperature(decodeResult, data[6]);
2175
- ResultFormatter.unknown(decodeResult, data[7]);
2176
- ResultFormatter.unknown(decodeResult, data[8]);
2177
- }
2178
- if (data.length === 14) {
2179
- ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2180
- processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
2181
- ResultFormatter.temperature(decodeResult, data[7]);
2182
- ResultFormatter.unknownArr(decodeResult, data.slice(8));
2183
- }
2184
- }
2185
- static processPosition(decodeResult, data) {
2186
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
2187
- data[0]
2188
- );
2189
- if (position) {
2190
- ResultFormatter.position(decodeResult, position);
2191
- }
2192
- if (data.length >= 10) {
2193
- ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2194
- processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
2195
- ResultFormatter.temperature(decodeResult, data[7]);
2196
- ResultFormatter.unknown(decodeResult, data[8]);
2197
- ResultFormatter.unknown(decodeResult, data[9]);
2198
- }
2199
- if (data.length >= 14) {
2200
- ResultFormatter.unknownArr(decodeResult, data.slice(10));
2201
- }
2202
- }
2203
- static processTimeStamp(decodeResult, data) {
2204
- if (data.length > 2) {
2205
- const positionData = data.slice(1);
2206
- positionData[0] = positionData[0].substring(6);
2207
- this.processPosition(decodeResult, positionData);
2208
- }
2209
- let time = DateTimeUtils.convertDateTimeToEpoch(
2210
- data[0],
2211
- data[1].substring(0, 6)
2212
- );
2213
- if (Number.isNaN(time)) {
2214
- const date = data[1].substring(2, 4) + data[1].substring(0, 2) + data[1].substring(4, 6);
2215
- time = DateTimeUtils.convertDateTimeToEpoch(data[0], date);
2216
- }
2217
- decodeResult.raw.message_timestamp = time;
2218
- }
2219
- };
2220
- function processETA(data, decodeResult, fields, i) {
2221
- if (data.length === 5) {
2222
- ResultFormatter.day(decodeResult, Number(data.substring(0, 1)));
2223
- ResultFormatter.eta(
2224
- decodeResult,
2225
- DateTimeUtils.convertHHMMSSToTod(data.substring(1))
2226
- );
2227
- } else if (data.length === 6) {
2228
- ResultFormatter.day(decodeResult, Number(data.substring(0, 2)));
2229
- ResultFormatter.eta(
2230
- decodeResult,
2231
- DateTimeUtils.convertHHMMSSToTod(data.substring(2))
2232
- );
2233
- } else {
2234
- ResultFormatter.unknown(decodeResult, fields[i], "/");
2235
- }
2236
- }
2237
- function processAirField(decodeResult, data) {
2238
- if (data.length === 2) {
2239
- ResultFormatter.departureAirport(decodeResult, data[0]);
2240
- ResultFormatter.arrivalAirport(decodeResult, data[1]);
2241
- } else {
2242
- ResultFormatter.unknown(decodeResult, data.join(","), "AF/");
2243
- }
2244
- }
2245
- function processTimeOfDeparture(decodeResult, data) {
2246
- if (data.length === 2) {
2247
- decodeResult.raw.plannedDepartureTime = data[0];
2248
- decodeResult.formatted.items.push({
2249
- type: "ptd",
2250
- code: "ptd",
2251
- label: "Planned Departure Time",
2252
- value: `YYYY-MM-${data[0].substring(0, 2)}T${data[0].substring(2, 4)}:${data[0].substring(4)}:00Z`
2253
- });
2254
- decodeResult.raw.plannedDepartureTime = data[1];
2255
- decodeResult.formatted.items.push({
2256
- type: "etd",
2257
- code: "etd",
2258
- label: "Estimated Departure Time",
2259
- value: `${data[1].substring(0, 2)}:${data[1].substring(2)}`
2260
- });
2261
- } else {
2262
- ResultFormatter.unknown(decodeResult, data.join(","), "/TD");
2263
- }
2264
- }
2265
- function processIdentification(decodeResult, data) {
2266
- ResultFormatter.tail(decodeResult, data[0]);
2267
- if (data.length > 1) {
2268
- ResultFormatter.flightNumber(decodeResult, data[1]);
2269
- }
2270
- if (data.length > 2) {
2271
- decodeResult.raw.mission_number = data[2];
2272
- }
2273
- }
2274
- function processDT(decodeResult, data) {
2275
- if (data.length === 9) {
2276
- ResultFormatter.unknown(decodeResult, data[0]);
2277
- if (!decodeResult.raw.arrival_icao) {
2278
- ResultFormatter.arrivalAirport(decodeResult, data[1]);
2279
- }
2280
- ResultFormatter.arrivalRunway(decodeResult, data[2]);
2281
- ResultFormatter.currentFuel(decodeResult, parseInt(data[3], 10));
2282
- ResultFormatter.eta(
2283
- decodeResult,
2284
- DateTimeUtils.convertHHMMSSToTod(data[4])
2285
- );
2286
- ResultFormatter.unknown(decodeResult, data[5]);
2287
- ResultFormatter.position(
2288
- decodeResult,
2289
- CoordinateUtils.decodeStringCoordinates(data[6])
2290
- );
2291
- ResultFormatter.unknown(decodeResult, data[7]);
2292
- ResultFormatter.unknown(decodeResult, data[8]);
2293
- return;
2294
- }
2295
- if (data.length === 4 || data.length === 5) {
2296
- if (!decodeResult.raw.arrival_icao) {
2297
- ResultFormatter.arrivalAirport(decodeResult, data[0]);
2298
- }
2299
- ResultFormatter.arrivalRunway(decodeResult, data[1]);
2300
- ResultFormatter.currentFuel(decodeResult, parseInt(data[2], 10));
2301
- ResultFormatter.eta(
2302
- decodeResult,
2303
- DateTimeUtils.convertHHMMSSToTod(data[3])
2304
- );
2305
- if (data.length > 4) {
2306
- ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
2307
- }
2308
- return;
2309
- }
2310
- ResultFormatter.unknownArr(decodeResult, data, ",");
2311
- }
2312
- function processLandingReport(decodeResult, data) {
2313
- if (data.length === 19) {
2314
- ResultFormatter.unknown(decodeResult, data[1]);
2315
- ResultFormatter.flightNumber(decodeResult, data[2]);
2316
- ResultFormatter.departureAirport(decodeResult, data[3]);
2317
- ResultFormatter.arrivalAirport(decodeResult, data[4]);
2318
- ResultFormatter.arrivalRunway(decodeResult, data[5]);
2319
- ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
2320
- } else {
2321
- ResultFormatter.unknown(decodeResult, data.join(","));
2322
- }
2323
- }
2324
- function processCenterOfGravity(decodeResult, data) {
2325
- if (data.length === 1) {
2326
- if (data[0] !== void 0 && data[0] !== "") {
2327
- ResultFormatter.cg(decodeResult, parseInt(data[0], 10) / 10);
2328
- }
2329
- } else if (data.length === 3) {
2330
- if (data[0] !== void 0 && data[0] !== "") {
2331
- ResultFormatter.cg(decodeResult, parseInt(data[0], 10) / 10, "center");
2332
- }
2333
- if (data[1] !== void 0 && data[1] !== "") {
2334
- ResultFormatter.cg(decodeResult, parseInt(data[1], 10) / 10, "lower");
2335
- }
2336
- if (data[2] !== void 0 && data[2] !== "") {
2337
- ResultFormatter.cg(decodeResult, parseInt(data[2], 10) / 10, "upper");
2338
- }
2339
- } else {
2340
- ResultFormatter.unknown(decodeResult, data.join(","));
2341
- }
2342
- }
2343
- function parseMessageType(decodeResult, messagePart) {
2344
- const messageParts = messagePart.split(",");
2345
- const messageType = messageParts[0];
2346
- if (messageType.startsWith("POS")) {
2347
- H1Helper.processPosition(decodeResult, messagePart.substring(3).split(","));
2348
- return processMessageType(decodeResult, "POS");
2349
- } else if (messageType.length === 6) {
2350
- const part1 = processMessageType(decodeResult, messageType.substring(0, 3));
2351
- const description = decodeResult.formatted.description;
2352
- const part2 = processMessageType(decodeResult, messageType.substring(3, 6));
2353
- decodeResult.formatted.description = description + " for " + decodeResult.formatted.description;
2354
- if (messageParts.length > 1) {
2355
- ResultFormatter.unknown(
2356
- decodeResult,
2357
- messageParts.slice(1).join(","),
2358
- "/"
2359
- );
2360
- }
2361
- return part1 && part2;
2362
- }
2363
- if (messageParts.length > 1) {
2364
- ResultFormatter.unknown(decodeResult, messageParts.slice(1).join(","), "/");
2365
- }
2366
- return processMessageType(decodeResult, messageType);
2367
- }
2368
- function processMessageType(decodeResult, type) {
2369
- if (type === "FPN") {
2370
- decodeResult.formatted.description = "Flight Plan";
2371
- } else if (type === "FTX") {
2372
- decodeResult.formatted.description = "Free Text";
2373
- } else if (type === "INI") {
2374
- decodeResult.formatted.description = "Initial Report";
2375
- } else if (type === "INR") {
2376
- decodeResult.formatted.description = "In-Range Report";
2377
- } else if (type === "LDI") {
2378
- decodeResult.formatted.description = "Load Distribution Information";
2379
- } else if (type === "PER") {
2380
- decodeResult.formatted.description = "Performance Report";
2381
- } else if (type === "POS") {
2382
- decodeResult.formatted.description = "Position Report";
2383
- } else if (type === "PRG") {
2384
- decodeResult.formatted.description = "Progress Report";
2385
- } else if (type === "PWI") {
2386
- decodeResult.formatted.description = "Pilot Weather Information";
2387
- } else if (type === "WXR") {
2388
- decodeResult.formatted.description = "Weather Report";
2389
- } else if (type === "REJ") {
2390
- decodeResult.formatted.description = "Reject";
2391
- } else if (type === "REQ") {
2392
- decodeResult.formatted.description = "Request";
2393
- } else if (type === "RES") {
2394
- decodeResult.formatted.description = "Response";
2395
- } else {
2396
- decodeResult.formatted.description = "Unknown H1 Message";
2397
- return false;
2398
- }
2399
- return true;
2400
- }
2401
- function processDateCode(decodeResult, data) {
2402
- if (data.length === 1) {
2403
- } else if (data.length === 2) {
2404
- const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
2405
- const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
2406
- decodeResult.raw.message_timestamp = time;
2407
- }
2408
- }
2409
- function processWeatherQuery(decodeResult, data) {
2410
- if (data.length !== 2) {
2411
- ResultFormatter.unknown(decodeResult, data.join(":"), "WQ/");
2412
- return;
2413
- }
2414
- const alts = data[0].split(".");
2415
- const route = data[1].split(".");
2416
- ResultFormatter.requestedAltitudes(
2417
- decodeResult,
2418
- alts.map((a) => parseInt(a, 10) * 100)
2419
- );
2420
- const waypoints = route.map((wp) => {
2421
- return { name: wp };
2422
- });
2423
- ResultFormatter.route(decodeResult, { waypoints });
2424
- }
2425
- function processRoute(decodeResult, last, time, next, eta, then, date) {
2426
- const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
2427
- const nextTime = date ? DateTimeUtils.convertDateTimeToEpoch(eta, date) : DateTimeUtils.convertHHMMSSToTod(eta);
2428
- const timeFormat = date ? "epoch" : "tod";
2429
- const lastWaypoint = RouteUtils.getWaypoint(last);
2430
- lastWaypoint.time = lastTime;
2431
- lastWaypoint.timeFormat = timeFormat;
2432
- const nextWaypoint = RouteUtils.getWaypoint(next);
2433
- nextWaypoint.time = nextTime;
2434
- nextWaypoint.timeFormat = timeFormat;
2435
- const thenWaypoint = RouteUtils.getWaypoint(then || "?");
2436
- const waypoints = [lastWaypoint, nextWaypoint, thenWaypoint];
2437
- ResultFormatter.route(decodeResult, { waypoints });
2438
- }
2439
- function processWindData(decodeResult, message) {
2440
- const wind = [];
2441
- const flightLevel = Number(message.slice(0, 3));
2442
- const fields = message.slice(4).split(".");
2443
- fields.forEach((field) => {
2444
- if (field.length < 4) {
2445
- return;
2446
- }
2447
- const data = field.split(",");
2448
- const waypoint = { name: data[0] };
2449
- const windData = data[1];
2450
- const windDirection = parseInt(windData.slice(0, 3), 10);
2451
- const windSpeed = parseInt(windData.slice(3), 10);
2452
- if (data.length === 3) {
2453
- const tempData = data[2];
2454
- const tempFlightLevel = Number(tempData.slice(0, 3));
2455
- const tempString = tempData.slice(3);
2456
- const tempDegrees = Number(tempString.substring(1)) * (tempString.charAt(0) === "M" ? -1 : 1);
2457
- wind.push({
2458
- waypoint,
2459
- flightLevel,
2460
- windDirection,
2461
- windSpeed,
2462
- temperature: {
2463
- flightLevel: tempFlightLevel,
2464
- degreesC: tempDegrees
2465
- }
2466
- });
2467
- } else {
2468
- wind.push({
2469
- waypoint,
2470
- flightLevel,
2471
- windDirection,
2472
- windSpeed
2473
- });
2474
- }
2475
- });
2476
- ResultFormatter.windData(decodeResult, wind);
2477
- }
2478
- function processRunway(decodeResult, data) {
2479
- const parts = data[0].split(".");
2480
- const more = parts[0].split(",");
2481
- ResultFormatter.departureRunway(decodeResult, more[0]);
2482
- ResultFormatter.unknownArr(decodeResult, more.slice(1), ",");
2483
- ResultFormatter.unknownArr(decodeResult, parts.slice(1), ".");
2484
- ResultFormatter.departureAirport(decodeResult, data[1].split(",")[0]);
2485
- ResultFormatter.unknownArr(decodeResult, data[1].split(",").slice(1), ",");
2486
- }
2487
- function crc16IbmSdlcRev(data) {
2488
- let crc = 65535;
2489
- const bytes = Buffer.from(data, "ascii");
2490
- for (const byte of bytes) {
2491
- crc ^= byte;
2492
- for (let i = 0; i < 8; i++) {
2493
- if ((crc & 1) !== 0) {
2494
- crc = crc >>> 1 ^ 33800;
2495
- } else {
2496
- crc = crc >>> 1;
2497
- }
2498
- }
2499
- }
2500
- crc = (crc ^ 65535) & 65535;
2501
- const nibble1 = crc >> 12 & 15;
2502
- const nibble2 = crc >> 8 & 15;
2503
- const nibble3 = crc >> 4 & 15;
2504
- const nibble4 = crc & 15;
2505
- return nibble4 << 12 | nibble3 << 8 | nibble2 << 4 | nibble1;
2506
- }
2507
- function crc16Genibus(data) {
2508
- let crc = 65535;
2509
- const polynomial = 4129;
2510
- const bytes = Buffer.from(data, "ascii");
2511
- for (const byte of bytes) {
2512
- crc ^= byte << 8;
2513
- for (let i = 0; i < 8; i++) {
2514
- if ((crc & 32768) !== 0) {
2515
- crc = (crc << 1 ^ polynomial) & 65535;
2516
- } else {
2517
- crc = crc << 1 & 65535;
2518
- }
2519
- }
2520
- }
2521
- return (crc ^ 65535) & 65535;
2522
- }
2523
-
2524
- // lib/plugins/Label_1J_2J_FTX.ts
2525
- var Label_1J_2J_FTX = class extends DecoderPlugin {
2526
- name = "label-1j-2j-ftx";
2527
- qualifiers() {
2528
- return {
2529
- labels: ["1J", "2J"]
2530
- };
2531
- }
2532
- decode(message, options = {}) {
2533
- let decodeResult = this.defaultResult();
2534
- decodeResult.decoder.name = this.name;
2535
- decodeResult.message = message;
2536
- const msg = message.text.replace(/\n|\r/g, "");
2537
- const parts = msg.split("/");
2538
- let decoded = false;
2539
- if (parts[0].length > 3) {
2540
- decoded = H1Helper.decodeH1Message(
2541
- decodeResult,
2542
- msg.slice(parts[0].length - 3)
2543
- );
2544
- decodeResult.remaining.text = parts[0].slice(0, 3) + "/" + decodeResult.remaining.text;
2545
- } else {
2546
- decoded = H1Helper.decodeH1Message(decodeResult, msg);
2547
- }
2548
- decodeResult.decoded = decoded;
2549
- decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
2550
- if (decodeResult.formatted.items.length === 0) {
2551
- if (options.debug) {
2552
- console.log(`Decoder: Unknown 1J/2J message: ${message.text}`);
2553
- }
2554
- ResultFormatter.unknown(decodeResult, message.text);
2555
- decodeResult.decoded = false;
2556
- decodeResult.decoder.decodeLevel = "none";
2557
- }
2558
- return decodeResult;
2559
- }
2560
- };
2561
-
2562
1870
  // lib/plugins/Label_1M_Slash.ts
2563
1871
  var Label_1M_Slash = class extends DecoderPlugin {
2564
1872
  name = "label-1m-slash";
@@ -3323,44 +2631,6 @@ var Label_2P_FM5 = class extends DecoderPlugin {
3323
2631
  }
3324
2632
  };
3325
2633
 
3326
- // lib/plugins/Label_2P_POS.ts
3327
- var Label_2P_POS = class extends DecoderPlugin {
3328
- name = "label-2p-pos";
3329
- qualifiers() {
3330
- return {
3331
- labels: ["2P"]
3332
- };
3333
- }
3334
- decode(message, options = {}) {
3335
- let decodeResult = this.defaultResult();
3336
- decodeResult.decoder.name = this.name;
3337
- decodeResult.message = message;
3338
- const msg = message.text.replace(/\n|\r/g, "");
3339
- const parts = msg.split("/");
3340
- let decoded = false;
3341
- if (parts[0].length > 3) {
3342
- decoded = H1Helper.decodeH1Message(
3343
- decodeResult,
3344
- msg.slice(parts[0].length - 3)
3345
- );
3346
- decodeResult.remaining.text = parts[0].slice(0, 3) + "/" + decodeResult.remaining.text;
3347
- } else {
3348
- decoded = H1Helper.decodeH1Message(decodeResult, msg);
3349
- }
3350
- decodeResult.decoded = decoded;
3351
- decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
3352
- if (decodeResult.formatted.items.length === 0) {
3353
- if (options.debug) {
3354
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
3355
- }
3356
- ResultFormatter.unknown(decodeResult, message.text);
3357
- decodeResult.decoded = false;
3358
- decodeResult.decoder.decodeLevel = "none";
3359
- }
3360
- return decodeResult;
3361
- }
3362
- };
3363
-
3364
2634
  // lib/plugins/Label_24_Slash.ts
3365
2635
  var Label_24_Slash = class extends DecoderPlugin {
3366
2636
  name = "label-24-slash";
@@ -3735,7 +3005,182 @@ var Label_44_POS = class extends DecoderPlugin {
3735
3005
  decodeResult.decoder.decodeLevel = "full";
3736
3006
  return decodeResult;
3737
3007
  }
3738
- };
3008
+ };
3009
+
3010
+ // lib/utils/flight_plan_utils.ts
3011
+ var FlightPlanUtils = class _FlightPlanUtils {
3012
+ /**
3013
+ * Processes flight plan data
3014
+ *
3015
+ * Expected format is [header, key1, val1, ... keyN, valN]
3016
+ *
3017
+ * @param decodeResult - results
3018
+ * @param data - original message split by ':'
3019
+ * @returns whether all fields were processed or not
3020
+ */
3021
+ static processFlightPlan(decodeResult, data) {
3022
+ let allKnownFields = _FlightPlanUtils.parseHeader(decodeResult, data[0]);
3023
+ for (let i = 1; i < data.length; i += 2) {
3024
+ const key = data[i];
3025
+ const value = data[i + 1];
3026
+ switch (key) {
3027
+ case "A":
3028
+ _FlightPlanUtils.addProcedure(decodeResult, value, "arrival");
3029
+ break;
3030
+ case "AA":
3031
+ addArrivalAirport(decodeResult, value);
3032
+ break;
3033
+ case "AP":
3034
+ _FlightPlanUtils.addProcedure(decodeResult, value, "approach");
3035
+ break;
3036
+ case "CR":
3037
+ addCompanyRoute(decodeResult, value);
3038
+ break;
3039
+ case "D":
3040
+ _FlightPlanUtils.addProcedure(decodeResult, value, "departure");
3041
+ break;
3042
+ case "DA":
3043
+ addDepartureAirport(decodeResult, value);
3044
+ break;
3045
+ case "F":
3046
+ addRoute(decodeResult, value);
3047
+ break;
3048
+ case "FP":
3049
+ ResultFormatter.flightPlan(decodeResult, value.trim());
3050
+ break;
3051
+ case "R":
3052
+ addRunway(decodeResult, value);
3053
+ break;
3054
+ // case 'WS': // something about routes, has altitude, so current parsing won't work
3055
+ // break;
3056
+ default:
3057
+ if (allKnownFields) {
3058
+ decodeResult.remaining.text = "";
3059
+ allKnownFields = false;
3060
+ }
3061
+ decodeResult.remaining.text += `:${key}:${value}`;
3062
+ decodeResult.decoder.decodeLevel = "partial";
3063
+ }
3064
+ }
3065
+ return allKnownFields;
3066
+ }
3067
+ static parseHeader(decodeResult, header) {
3068
+ let allKnownFields = true;
3069
+ if (header.startsWith("RF")) {
3070
+ decodeResult.formatted.items.push({
3071
+ type: "status",
3072
+ code: "ROUTE_STATUS",
3073
+ label: "Route Status",
3074
+ value: "Route Filed"
3075
+ });
3076
+ decodeResult.raw.route_status = "RF";
3077
+ if (header.length > 2) {
3078
+ addRoute(decodeResult, header.substring(2));
3079
+ }
3080
+ } else if (header.startsWith("RP")) {
3081
+ decodeResult.raw.route_status = "RP";
3082
+ decodeResult.formatted.items.push({
3083
+ type: "status",
3084
+ code: "ROUTE_STATUS",
3085
+ label: "Route Status",
3086
+ value: "Route Planned"
3087
+ });
3088
+ decodeResult.raw.route_status = header;
3089
+ } else if (header.startsWith("RI")) {
3090
+ decodeResult.raw.route_status = "RI";
3091
+ decodeResult.formatted.items.push({
3092
+ type: "status",
3093
+ code: "ROUTE_STATUS",
3094
+ label: "Route Status",
3095
+ value: "Route Inactive"
3096
+ });
3097
+ } else if (header.startsWith("RM")) {
3098
+ decodeResult.raw.route_status = "RM";
3099
+ decodeResult.formatted.items.push({
3100
+ type: "status",
3101
+ code: "ROUTE_STATUS",
3102
+ label: "Route Status",
3103
+ value: "Route Mapped"
3104
+ });
3105
+ } else if (header.startsWith("RS")) {
3106
+ decodeResult.raw.route_status = "RS";
3107
+ decodeResult.formatted.items.push({
3108
+ type: "status",
3109
+ code: "ROUTE_STATUS",
3110
+ label: "Route Status",
3111
+ value: "Route Saved"
3112
+ });
3113
+ } else {
3114
+ decodeResult.remaining.text += header;
3115
+ allKnownFields = false;
3116
+ }
3117
+ return allKnownFields;
3118
+ }
3119
+ static addProcedure(decodeResult, value, type) {
3120
+ if (decodeResult.raw.procedures === void 0) {
3121
+ decodeResult.raw.procedures = [];
3122
+ }
3123
+ const data = value.split(".");
3124
+ let waypoints;
3125
+ if (data.length > 1) {
3126
+ waypoints = data.slice(1).map((leg) => RouteUtils.getWaypoint(leg));
3127
+ }
3128
+ const route = { name: data[0], waypoints };
3129
+ decodeResult.raw.procedures.push({ type, route });
3130
+ const procedureName = type.substring(0, 1).toUpperCase() + type.slice(1);
3131
+ decodeResult.formatted.items.push({
3132
+ type: "procedure",
3133
+ code: "proc",
3134
+ label: `${procedureName} Procedure`,
3135
+ value: RouteUtils.routeToString(route)
3136
+ });
3137
+ }
3138
+ };
3139
+ function addArrivalAirport(decodeResult, value) {
3140
+ ResultFormatter.arrivalAirport(decodeResult, value);
3141
+ }
3142
+ function addDepartureAirport(decodeResult, value) {
3143
+ ResultFormatter.departureAirport(decodeResult, value);
3144
+ }
3145
+ function addRunway(decodeResult, value) {
3146
+ if (value.length === 8) {
3147
+ ResultFormatter.arrivalRunway(decodeResult, value.substring(4, 7));
3148
+ }
3149
+ ResultFormatter.departureRunway(decodeResult, value.substring(0, 3));
3150
+ }
3151
+ function addRoute(decodeResult, value) {
3152
+ const route = value.split(".");
3153
+ ResultFormatter.route(decodeResult, {
3154
+ waypoints: route.map((leg) => RouteUtils.getWaypoint(leg))
3155
+ });
3156
+ }
3157
+ function addCompanyRoute(decodeResult, value) {
3158
+ const segments = value.split(".");
3159
+ const parens_idx = segments[0].indexOf("(");
3160
+ let name;
3161
+ let runway;
3162
+ if (parens_idx === -1) {
3163
+ name = segments[0];
3164
+ } else {
3165
+ name = segments[0].slice(0, parens_idx);
3166
+ runway = segments[0].slice(parens_idx + 1, segments[0].indexOf(")"));
3167
+ }
3168
+ let waypoints;
3169
+ if (segments.length > 1) {
3170
+ waypoints = segments.slice(1).map((leg) => RouteUtils.getWaypoint(leg));
3171
+ }
3172
+ decodeResult.raw.company_route = {
3173
+ name,
3174
+ runway,
3175
+ waypoints
3176
+ };
3177
+ decodeResult.formatted.items.push({
3178
+ type: "company_route",
3179
+ code: "CR",
3180
+ label: "Company Route",
3181
+ value: RouteUtils.routeToString(decodeResult.raw.company_route)
3182
+ });
3183
+ }
3739
3184
 
3740
3185
  // lib/plugins/Label_44_Slash.ts
3741
3186
  var Label_44_Slash = class extends DecoderPlugin {
@@ -3928,150 +3373,503 @@ var Label_4A_01 = class extends DecoderPlugin {
3928
3373
  }
3929
3374
  };
3930
3375
 
3931
- // lib/plugins/Label_4A_DIS.ts
3932
- var Label_4A_DIS = class extends DecoderPlugin {
3933
- name = "label-4a-dis";
3376
+ // lib/plugins/Label_4A_DIS.ts
3377
+ var Label_4A_DIS = class extends DecoderPlugin {
3378
+ name = "label-4a-dis";
3379
+ qualifiers() {
3380
+ return {
3381
+ labels: ["4A"],
3382
+ preambles: ["DIS"]
3383
+ };
3384
+ }
3385
+ decode(message, options = {}) {
3386
+ const decodeResult = this.defaultResult();
3387
+ decodeResult.decoder.name = this.name;
3388
+ decodeResult.message = message;
3389
+ decodeResult.formatted.description = "Latest New Format";
3390
+ decodeResult.decoded = true;
3391
+ const fields = message.text.split(",");
3392
+ ResultFormatter.time_of_day(
3393
+ decodeResult,
3394
+ DateTimeUtils.convertHHMMSSToTod(fields[1].substring(2) + "00")
3395
+ );
3396
+ ResultFormatter.callsign(decodeResult, fields[2]);
3397
+ ResultFormatter.freetext(decodeResult, fields.slice(3).join(""));
3398
+ if (decodeResult.decoded) {
3399
+ if (!decodeResult.remaining.text)
3400
+ decodeResult.decoder.decodeLevel = "full";
3401
+ else decodeResult.decoder.decodeLevel = "partial";
3402
+ } else {
3403
+ decodeResult.decoder.decodeLevel = "none";
3404
+ }
3405
+ return decodeResult;
3406
+ }
3407
+ };
3408
+
3409
+ // lib/plugins/Label_4A_DOOR.ts
3410
+ var Label_4A_DOOR = class extends DecoderPlugin {
3411
+ name = "label-4a-door";
3412
+ qualifiers() {
3413
+ return {
3414
+ labels: ["4A"],
3415
+ preambles: ["DOOR"]
3416
+ };
3417
+ }
3418
+ decode(message, options = {}) {
3419
+ const decodeResult = this.defaultResult();
3420
+ decodeResult.decoder.name = this.name;
3421
+ decodeResult.message = message;
3422
+ decodeResult.formatted.description = "Latest New Format";
3423
+ decodeResult.decoded = true;
3424
+ const fields = message.text.split(" ");
3425
+ if (fields.length === 3) {
3426
+ ResultFormatter.door_event(
3427
+ decodeResult,
3428
+ fields[0].split("/")[1],
3429
+ fields[1]
3430
+ );
3431
+ ResultFormatter.time_of_day(
3432
+ decodeResult,
3433
+ DateTimeUtils.convertHHMMSSToTod(fields[2] + "00")
3434
+ );
3435
+ } else {
3436
+ decodeResult.decoded = false;
3437
+ ResultFormatter.unknown(decodeResult, message.text);
3438
+ }
3439
+ if (decodeResult.decoded) {
3440
+ if (!decodeResult.remaining.text)
3441
+ decodeResult.decoder.decodeLevel = "full";
3442
+ else decodeResult.decoder.decodeLevel = "partial";
3443
+ } else {
3444
+ decodeResult.decoder.decodeLevel = "none";
3445
+ }
3446
+ return decodeResult;
3447
+ }
3448
+ };
3449
+
3450
+ // lib/plugins/Label_4A_Slash_01.ts
3451
+ var Label_4A_Slash_01 = class extends DecoderPlugin {
3452
+ name = "label-4a-slash-01";
3453
+ qualifiers() {
3454
+ return {
3455
+ labels: ["4A"],
3456
+ preambles: ["/01"]
3457
+ };
3458
+ }
3459
+ decode(message, options = {}) {
3460
+ const decodeResult = this.defaultResult();
3461
+ decodeResult.decoder.name = this.name;
3462
+ decodeResult.message = message;
3463
+ decodeResult.formatted.description = "Latest New Format";
3464
+ decodeResult.decoded = true;
3465
+ if (message.text.length === 5 && message.text.substring(0, 4) === "/01-") {
3466
+ ResultFormatter.unknown(decodeResult, message.text.substring(4));
3467
+ } else {
3468
+ decodeResult.decoded = false;
3469
+ ResultFormatter.unknown(decodeResult, message.text);
3470
+ }
3471
+ if (decodeResult.decoded) {
3472
+ if (!decodeResult.remaining.text)
3473
+ decodeResult.decoder.decodeLevel = "full";
3474
+ else decodeResult.decoder.decodeLevel = "partial";
3475
+ } else {
3476
+ decodeResult.decoder.decodeLevel = "none";
3477
+ }
3478
+ return decodeResult;
3479
+ }
3480
+ };
3481
+
3482
+ // lib/plugins/Label_4N.ts
3483
+ var Label_4N = class extends DecoderPlugin {
3484
+ name = "label-4n";
3485
+ qualifiers() {
3486
+ return {
3487
+ labels: ["4N"]
3488
+ };
3489
+ }
3490
+ decode(message, options = {}) {
3491
+ const decodeResult = this.defaultResult();
3492
+ decodeResult.decoder.name = this.name;
3493
+ decodeResult.message = message;
3494
+ decodeResult.formatted.description = "Airline Defined";
3495
+ decodeResult.decoded = true;
3496
+ const text = message.text;
3497
+ const fields = text.split(",");
3498
+ if (text.length === 51) {
3499
+ decodeResult.raw.day = text.substring(0, 2);
3500
+ ResultFormatter.departureAirport(decodeResult, text.substring(8, 11));
3501
+ ResultFormatter.arrivalAirport(decodeResult, text.substring(13, 16));
3502
+ ResultFormatter.position(
3503
+ decodeResult,
3504
+ CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
3505
+ text.substring(30, 45).replace(/^(.)0/, "$1")
3506
+ )
3507
+ );
3508
+ ResultFormatter.altitude(
3509
+ decodeResult,
3510
+ Number(text.substring(48, 51)) * 100
3511
+ );
3512
+ ResultFormatter.unknownArr(
3513
+ decodeResult,
3514
+ [text.substring(2, 4), text.substring(19, 29)],
3515
+ " "
3516
+ );
3517
+ } else if (fields.length === 33) {
3518
+ decodeResult.raw.date = fields[3];
3519
+ if (fields[1] === "B") {
3520
+ ResultFormatter.position(decodeResult, {
3521
+ latitude: Number(fields[4]),
3522
+ longitude: Number(fields[5])
3523
+ });
3524
+ ResultFormatter.altitude(decodeResult, Number(fields[6]));
3525
+ }
3526
+ ResultFormatter.departureAirport(decodeResult, fields[8]);
3527
+ ResultFormatter.arrivalAirport(decodeResult, fields[9]);
3528
+ ResultFormatter.alternateAirport(decodeResult, fields[10]);
3529
+ ResultFormatter.arrivalRunway(decodeResult, fields[11].split("/")[0]);
3530
+ if (fields[12].length > 1) {
3531
+ ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
3532
+ }
3533
+ ResultFormatter.checksum(decodeResult, parseInt(fields[32], 16));
3534
+ ResultFormatter.unknownArr(
3535
+ decodeResult,
3536
+ [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter(
3537
+ (f) => f != ""
3538
+ )
3539
+ );
3540
+ } else {
3541
+ decodeResult.decoded = false;
3542
+ ResultFormatter.unknown(decodeResult, text);
3543
+ }
3544
+ if (decodeResult.decoded) {
3545
+ if (!decodeResult.remaining.text)
3546
+ decodeResult.decoder.decodeLevel = "full";
3547
+ else decodeResult.decoder.decodeLevel = "partial";
3548
+ } else {
3549
+ decodeResult.decoder.decodeLevel = "none";
3550
+ }
3551
+ return decodeResult;
3552
+ }
3553
+ };
3554
+
3555
+ // lib/plugins/Label_4T_AGFSR.ts
3556
+ var Label_4T_AGFSR = class extends DecoderPlugin {
3557
+ name = "label-4t-agfsr";
3558
+ qualifiers() {
3559
+ return {
3560
+ labels: ["4T"],
3561
+ preambles: ["AGFSR"]
3562
+ };
3563
+ }
3564
+ decode(message, options = {}) {
3565
+ const decodeResult = this.defaultResult();
3566
+ decodeResult.decoder.name = this.name;
3567
+ decodeResult.formatted.description = "Position Report";
3568
+ decodeResult.message = message;
3569
+ const data = message.text.substring(5).split("/");
3570
+ if (!message.text.startsWith("AGFSR") || data.length !== 20) {
3571
+ if (options.debug) {
3572
+ console.log(`Decoder: Unknown 4T message: ${message.text}`);
3573
+ }
3574
+ ResultFormatter.unknown(decodeResult, message.text);
3575
+ decodeResult.decoded = false;
3576
+ decodeResult.decoder.decodeLevel = "none";
3577
+ return decodeResult;
3578
+ }
3579
+ ResultFormatter.flightNumber(decodeResult, data[0].trim());
3580
+ ResultFormatter.departureDay(decodeResult, Number(data[1]));
3581
+ ResultFormatter.arrivalDay(decodeResult, Number(data[2]));
3582
+ ResultFormatter.departureAirport(
3583
+ decodeResult,
3584
+ data[3].substring(0, 3),
3585
+ "IATA"
3586
+ );
3587
+ ResultFormatter.arrivalAirport(decodeResult, data[3].substring(3), "IATA");
3588
+ ResultFormatter.time_of_day(
3589
+ decodeResult,
3590
+ DateTimeUtils.convertHHMMSSToTod(data[4].substring(0, 4))
3591
+ );
3592
+ ResultFormatter.unknown(decodeResult, data[5], "/");
3593
+ const lat = data[6].substring(0, 7);
3594
+ const lon = data[6].substring(7, 15);
3595
+ ResultFormatter.position(decodeResult, {
3596
+ latitude: CoordinateUtils.getDirection(lat[6]) * Number(lat.substring(0, 2)) + Number(lat.substring(2, 6)) / 60,
3597
+ longitude: CoordinateUtils.getDirection(lon[7]) * Number(lon.substring(0, 3)) + Number(lon.substring(3, 7)) / 60
3598
+ });
3599
+ ResultFormatter.altitude(decodeResult, 100 * Number(data[7]));
3600
+ ResultFormatter.unknownArr(decodeResult, data.slice(8), "/");
3601
+ decodeResult.decoded = true;
3602
+ decodeResult.decoder.decodeLevel = "partial";
3603
+ return decodeResult;
3604
+ }
3605
+ };
3606
+
3607
+ // lib/plugins/Label_58.ts
3608
+ var Label_58 = class extends DecoderPlugin {
3609
+ name = "label-58";
3934
3610
  qualifiers() {
3935
3611
  return {
3936
- labels: ["4A"],
3937
- preambles: ["DIS"]
3612
+ labels: ["58"]
3938
3613
  };
3939
3614
  }
3940
3615
  decode(message, options = {}) {
3941
3616
  const decodeResult = this.defaultResult();
3942
3617
  decodeResult.decoder.name = this.name;
3618
+ decodeResult.formatted.description = "Position Report";
3943
3619
  decodeResult.message = message;
3944
- decodeResult.formatted.description = "Latest New Format";
3945
- decodeResult.decoded = true;
3946
- const fields = message.text.split(",");
3947
- ResultFormatter.time_of_day(
3948
- decodeResult,
3949
- DateTimeUtils.convertHHMMSSToTod(fields[1].substring(2) + "00")
3950
- );
3951
- ResultFormatter.callsign(decodeResult, fields[2]);
3952
- ResultFormatter.freetext(decodeResult, fields.slice(3).join(""));
3953
- if (decodeResult.decoded) {
3954
- if (!decodeResult.remaining.text)
3955
- decodeResult.decoder.decodeLevel = "full";
3956
- else decodeResult.decoder.decodeLevel = "partial";
3620
+ const data = message.text.split("/");
3621
+ if (data.length === 8) {
3622
+ ResultFormatter.flightNumber(decodeResult, data[0]);
3623
+ ResultFormatter.day(decodeResult, Number(data[1]));
3624
+ ResultFormatter.time_of_day(
3625
+ decodeResult,
3626
+ DateTimeUtils.convertHHMMSSToTod(data[2])
3627
+ );
3628
+ const lat = data[3];
3629
+ const lon = data[4];
3630
+ ResultFormatter.position(decodeResult, {
3631
+ latitude: CoordinateUtils.getDirection(lat[0]) * Number(lat.substring(1)),
3632
+ longitude: CoordinateUtils.getDirection(lon[0]) * Number(lon.substring(1))
3633
+ });
3634
+ ResultFormatter.altitude(decodeResult, Number(data[5]));
3635
+ ResultFormatter.unknown(decodeResult, data[6], "/");
3636
+ ResultFormatter.unknown(decodeResult, data[7], "/");
3957
3637
  } else {
3638
+ if (options.debug) {
3639
+ console.log(`Decoder: Unknown 58 message: ${message.text}`);
3640
+ }
3641
+ ResultFormatter.unknown(decodeResult, message.text);
3642
+ decodeResult.decoded = false;
3958
3643
  decodeResult.decoder.decodeLevel = "none";
3644
+ return decodeResult;
3959
3645
  }
3646
+ decodeResult.decoded = true;
3647
+ decodeResult.decoder.decodeLevel = "partial";
3960
3648
  return decodeResult;
3961
3649
  }
3962
3650
  };
3963
3651
 
3964
- // lib/plugins/Label_4A_DOOR.ts
3965
- var Label_4A_DOOR = class extends DecoderPlugin {
3966
- name = "label-4a-door";
3652
+ // lib/plugins/Label_4T_ETA.ts
3653
+ var Label_4T_ETA = class extends DecoderPlugin {
3654
+ name = "label-4t-eta";
3967
3655
  qualifiers() {
3968
3656
  return {
3969
- labels: ["4A"],
3970
- preambles: ["DOOR"]
3657
+ labels: ["4T"],
3658
+ preambles: ["ETA"]
3971
3659
  };
3972
3660
  }
3973
3661
  decode(message, options = {}) {
3974
3662
  const decodeResult = this.defaultResult();
3975
3663
  decodeResult.decoder.name = this.name;
3664
+ decodeResult.formatted.description = "ETA Report";
3976
3665
  decodeResult.message = message;
3977
- decodeResult.formatted.description = "Latest New Format";
3978
- decodeResult.decoded = true;
3979
- const fields = message.text.split(" ");
3980
- if (fields.length === 3) {
3981
- ResultFormatter.door_event(
3982
- decodeResult,
3983
- fields[0].split("/")[1],
3984
- fields[1]
3985
- );
3986
- ResultFormatter.time_of_day(
3987
- decodeResult,
3988
- DateTimeUtils.convertHHMMSSToTod(fields[2] + "00")
3989
- );
3990
- } else {
3991
- decodeResult.decoded = false;
3666
+ const data = message.text.substring(3).split("/");
3667
+ if (!message.text.startsWith("ETA") || data.length !== 3) {
3668
+ if (options.debug) {
3669
+ console.log(`Decoder: Unknown 4T message: ${message.text}`);
3670
+ }
3992
3671
  ResultFormatter.unknown(decodeResult, message.text);
3993
- }
3994
- if (decodeResult.decoded) {
3995
- if (!decodeResult.remaining.text)
3996
- decodeResult.decoder.decodeLevel = "full";
3997
- else decodeResult.decoder.decodeLevel = "partial";
3998
- } else {
3672
+ decodeResult.decoded = false;
3999
3673
  decodeResult.decoder.decodeLevel = "none";
3674
+ return decodeResult;
4000
3675
  }
3676
+ ResultFormatter.flightNumber(decodeResult, data[0].trim());
3677
+ ResultFormatter.departureDay(decodeResult, Number(data[1]));
3678
+ const etaData = data[2].split(" ");
3679
+ ResultFormatter.arrivalDay(decodeResult, Number(etaData[0]));
3680
+ ResultFormatter.arrivalAirport(decodeResult, etaData[1], "IATA");
3681
+ ResultFormatter.eta(
3682
+ decodeResult,
3683
+ DateTimeUtils.convertHHMMSSToTod(etaData[2].substring(0, 4))
3684
+ );
3685
+ decodeResult.decoded = true;
3686
+ decodeResult.decoder.decodeLevel = "full";
4001
3687
  return decodeResult;
4002
3688
  }
4003
3689
  };
4004
3690
 
4005
- // lib/plugins/Label_4A_Slash_01.ts
4006
- var Label_4A_Slash_01 = class extends DecoderPlugin {
4007
- name = "label-4a-slash-01";
3691
+ // lib/plugins/Label_80.ts
3692
+ var Label_80 = class extends DecoderPlugin {
3693
+ name = "label-80";
4008
3694
  qualifiers() {
4009
3695
  return {
4010
- labels: ["4A"],
4011
- preambles: ["/01"]
3696
+ labels: ["80"],
3697
+ preambles: []
4012
3698
  };
4013
3699
  }
4014
3700
  decode(message, options = {}) {
4015
3701
  const decodeResult = this.defaultResult();
4016
3702
  decodeResult.decoder.name = this.name;
4017
- decodeResult.message = message;
4018
- decodeResult.formatted.description = "Latest New Format";
4019
- decodeResult.decoded = true;
4020
- if (message.text.length === 5 && message.text.substring(0, 4) === "/01-") {
4021
- ResultFormatter.unknown(decodeResult, message.text.substring(4));
3703
+ decodeResult.formatted.description = "Airline Defined Position Report";
3704
+ const lines = message.text.split(/\r?\n/);
3705
+ if (lines.length === 1 && lines[0].includes(",")) {
3706
+ this.parseCsvFormat(lines[0], decodeResult);
4022
3707
  } else {
4023
- decodeResult.decoded = false;
4024
- ResultFormatter.unknown(decodeResult, message.text);
3708
+ const header = lines[0].trim();
3709
+ const headerParts = header.split(",");
3710
+ for (let i = 0; i < headerParts.length - 1; i++) {
3711
+ const moreFields = headerParts[i].split("/");
3712
+ for (const more of moreFields) {
3713
+ this.parseTags(more.trim(), decodeResult);
3714
+ }
3715
+ }
3716
+ this.parseHeader(
3717
+ headerParts[headerParts.length - 1].trim(),
3718
+ decodeResult
3719
+ );
3720
+ for (let i = 1; i < lines.length; i++) {
3721
+ const line = lines[i];
3722
+ const parts = line.split("/");
3723
+ for (const part of parts) {
3724
+ this.parseTags(part.trim(), decodeResult);
3725
+ }
3726
+ }
4025
3727
  }
4026
- if (decodeResult.decoded) {
4027
- if (!decodeResult.remaining.text)
4028
- decodeResult.decoder.decodeLevel = "full";
4029
- else decodeResult.decoder.decodeLevel = "partial";
4030
- } else {
4031
- decodeResult.decoder.decodeLevel = "none";
3728
+ if (decodeResult.formatted.items.length > 0) {
3729
+ decodeResult.decoded = true;
3730
+ decodeResult.decoder.decodeLevel = decodeResult.remaining.text === void 0 ? "full" : "partial";
4032
3731
  }
4033
3732
  return decodeResult;
4034
3733
  }
4035
- };
4036
-
4037
- // lib/plugins/Label_4J_POS.ts
4038
- var Label_4J_POS = class extends DecoderPlugin {
4039
- name = "label-4j-pos";
4040
- qualifiers() {
4041
- return {
4042
- labels: ["4J"],
4043
- preambles: ["POS/"]
4044
- };
3734
+ parseHeader(header, results) {
3735
+ const fields = header.split("/");
3736
+ if (fields.length < 3) {
3737
+ ResultFormatter.unknown(results, header, "/");
3738
+ return;
3739
+ }
3740
+ const msgInfo = fields[0].split(/\s+/);
3741
+ if (msgInfo.length === 3) {
3742
+ ResultFormatter.unknownArr(results, msgInfo.slice(0, 2), " ");
3743
+ ResultFormatter.flightNumber(results, msgInfo[2]);
3744
+ } else {
3745
+ ResultFormatter.unknown(results, header, "/");
3746
+ return;
3747
+ }
3748
+ const otherInfo1 = fields[1].split(/\s+/);
3749
+ if (otherInfo1.length === 2) {
3750
+ ResultFormatter.day(results, parseInt(otherInfo1[0], 10));
3751
+ ResultFormatter.departureAirport(results, otherInfo1[1]);
3752
+ } else {
3753
+ ResultFormatter.unknownArr(results, otherInfo1, " ");
3754
+ }
3755
+ const otherInfo2 = fields[2].split(/\s+/);
3756
+ if (otherInfo2.length === 2) {
3757
+ ResultFormatter.arrivalAirport(results, otherInfo2[0]);
3758
+ ResultFormatter.tail(results, otherInfo2[1].replace(".", ""));
3759
+ } else {
3760
+ ResultFormatter.unknownArr(results, otherInfo2, " ");
3761
+ }
3762
+ if (fields.length > 3) {
3763
+ ResultFormatter.unknownArr(results, fields.slice(3), "/");
3764
+ }
3765
+ }
3766
+ parseTags(part, results) {
3767
+ const kvPair = part.split(/\s+/);
3768
+ if (kvPair.length < 2) {
3769
+ ResultFormatter.unknown(results, part, "/");
3770
+ return;
3771
+ }
3772
+ const tag = kvPair[0];
3773
+ const val = kvPair.slice(1).join(" ");
3774
+ switch (tag) {
3775
+ case "POS":
3776
+ const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
3777
+ const posResult = val.match(posRegex);
3778
+ const lat = Number(posResult?.groups?.lat) * (posResult?.groups?.latd === "S" ? -1 : 1);
3779
+ const lon = Number(posResult?.groups?.lng) * (posResult?.groups?.lngd === "W" ? -1 : 1);
3780
+ const position = {
3781
+ latitude: Number.isInteger(lat) ? lat / 1e3 : lat / 100,
3782
+ longitude: Number.isInteger(lon) ? lon / 1e3 : lon / 100
3783
+ };
3784
+ ResultFormatter.position(results, position);
3785
+ break;
3786
+ case "ALT":
3787
+ ResultFormatter.altitude(results, parseInt(val.replace("+", ""), 10));
3788
+ break;
3789
+ case "FL":
3790
+ ResultFormatter.altitude(results, parseInt(val, 10) * 100);
3791
+ break;
3792
+ case "MCH":
3793
+ ResultFormatter.mach(results, parseInt(val, 10) / 1e3);
3794
+ break;
3795
+ case "SPD":
3796
+ ResultFormatter.groundspeed(results, parseInt(val, 10));
3797
+ break;
3798
+ case "TAS":
3799
+ ResultFormatter.airspeed(results, parseInt(val, 10));
3800
+ break;
3801
+ case "SAT":
3802
+ ResultFormatter.temperature(results, val);
3803
+ break;
3804
+ case "FB":
3805
+ break;
3806
+ case "FOB":
3807
+ ResultFormatter.currentFuel(
3808
+ results,
3809
+ parseInt(val.replace(/\D/g, ""), 10)
3810
+ );
3811
+ break;
3812
+ case "UTC":
3813
+ ResultFormatter.time_of_day(
3814
+ results,
3815
+ DateTimeUtils.convertHHMMSSToTod(val)
3816
+ );
3817
+ break;
3818
+ case "ETA":
3819
+ const hhmm = val.split(".")[0].replace(":", "");
3820
+ ResultFormatter.eta(results, DateTimeUtils.convertHHMMSSToTod(hhmm));
3821
+ break;
3822
+ case "HDG":
3823
+ ResultFormatter.heading(results, parseInt(val, 10));
3824
+ break;
3825
+ case "NWYP":
3826
+ results.raw.next_waypoint = val;
3827
+ break;
3828
+ case "SWN":
3829
+ ResultFormatter.unknown(results, part, "/");
3830
+ break;
3831
+ case "DWN":
3832
+ ResultFormatter.unknown(results, part, "/");
3833
+ break;
3834
+ case "AD":
3835
+ break;
3836
+ default:
3837
+ ResultFormatter.unknown(results, part, "/");
3838
+ }
4045
3839
  }
4046
- // copied from Label_H1.ts since i don't really want to have to have
4047
- // something named like that decode more than 1 type
4048
- // if we figure out a good name, i'll combine them
4049
- decode(message, options = {}) {
4050
- let decodeResult = this.defaultResult();
4051
- decodeResult.decoder.name = this.name;
4052
- decodeResult.message = message;
4053
- const msg = message.text.replace(/\n|\r/g, "");
4054
- const decoded = H1Helper.decodeH1Message(decodeResult, msg);
4055
- decodeResult.decoded = decoded;
4056
- decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
4057
- if (decodeResult.formatted.items.length === 0) {
4058
- if (options.debug) {
4059
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
4060
- }
4061
- ResultFormatter.unknown(decodeResult, message.text);
4062
- decodeResult.decoded = false;
4063
- decodeResult.decoder.decodeLevel = "none";
3840
+ parseCsvFormat(text, results) {
3841
+ const csvParts = text.split(",");
3842
+ if (csvParts.length !== 9) {
3843
+ return;
4064
3844
  }
4065
- return decodeResult;
3845
+ const header = csvParts[0].trim().split(/\s+/);
3846
+ ResultFormatter.unknown(results, header[0], " ");
3847
+ ResultFormatter.unknown(results, header[1], " ");
3848
+ ResultFormatter.position(
3849
+ results,
3850
+ CoordinateUtils.decodeStringCoordinates(header[2])
3851
+ );
3852
+ ResultFormatter.unknown(results, csvParts[1]);
3853
+ ResultFormatter.time_of_day(
3854
+ results,
3855
+ DateTimeUtils.convertHHMMSSToTod(csvParts[2])
3856
+ );
3857
+ ResultFormatter.unknownArr(results, csvParts.slice(4, 6), ",");
3858
+ ResultFormatter.temperature(
3859
+ results,
3860
+ ((csvParts[6].charAt(0) === "M" ? -1 : 1) * parseInt(csvParts[6].slice(1), 10)).toString()
3861
+ );
3862
+ ResultFormatter.airspeed(results, parseInt(csvParts[7], 10));
3863
+ ResultFormatter.currentFuel(results, parseInt(csvParts[8], 10));
4066
3864
  }
4067
3865
  };
4068
3866
 
4069
- // lib/plugins/Label_4N.ts
4070
- var Label_4N = class extends DecoderPlugin {
4071
- name = "label-4n";
3867
+ // lib/plugins/Label_83.ts
3868
+ var Label_83 = class extends DecoderPlugin {
3869
+ name = "label-83";
4072
3870
  qualifiers() {
4073
3871
  return {
4074
- labels: ["4N"]
3872
+ labels: ["83"]
4075
3873
  };
4076
3874
  }
4077
3875
  decode(message, options = {}) {
@@ -4081,52 +3879,49 @@ var Label_4N = class extends DecoderPlugin {
4081
3879
  decodeResult.formatted.description = "Airline Defined";
4082
3880
  decodeResult.decoded = true;
4083
3881
  const text = message.text;
4084
- const fields = text.split(",");
4085
- if (text.length === 51) {
4086
- decodeResult.raw.day = text.substring(0, 2);
4087
- ResultFormatter.departureAirport(decodeResult, text.substring(8, 11));
4088
- ResultFormatter.arrivalAirport(decodeResult, text.substring(13, 16));
4089
- ResultFormatter.position(
4090
- decodeResult,
4091
- CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
4092
- text.substring(30, 45).replace(/^(.)0/, "$1")
4093
- )
4094
- );
4095
- ResultFormatter.altitude(
3882
+ if (text.substring(0, 10) === "4DH3 ETAT2") {
3883
+ const fields = text.split(/\s+/);
3884
+ if (fields[2].length > 5) {
3885
+ decodeResult.raw.day = fields[2].substring(5);
3886
+ }
3887
+ ResultFormatter.unknown(decodeResult, fields[2].substring(0, 4));
3888
+ const subfields = fields[3].split("/");
3889
+ ResultFormatter.departureAirport(decodeResult, subfields[0]);
3890
+ ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
3891
+ ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
3892
+ ResultFormatter.eta(
4096
3893
  decodeResult,
4097
- Number(text.substring(48, 51)) * 100
3894
+ DateTimeUtils.convertHHMMSSToTod(fields[6] + "00")
4098
3895
  );
4099
- ResultFormatter.unknownArr(
4100
- decodeResult,
4101
- [text.substring(2, 4), text.substring(19, 29)],
4102
- " "
3896
+ } else if (text.substring(0, 5) === "001PR") {
3897
+ decodeResult.raw.day = text.substring(5, 7);
3898
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
3899
+ text.substring(13, 28).replace(/\./g, "")
4103
3900
  );
4104
- } else if (fields.length === 33) {
4105
- decodeResult.raw.date = fields[3];
4106
- if (fields[1] === "B") {
3901
+ if (position) {
3902
+ ResultFormatter.position(decodeResult, position);
3903
+ }
3904
+ ResultFormatter.altitude(decodeResult, Number(text.substring(28, 33)));
3905
+ ResultFormatter.unknown(decodeResult, text.substring(33));
3906
+ } else {
3907
+ const fields = text.replace(/\s/g, "").split(",");
3908
+ if (fields.length === 9) {
3909
+ ResultFormatter.departureAirport(decodeResult, fields[0]);
3910
+ ResultFormatter.arrivalAirport(decodeResult, fields[1]);
3911
+ decodeResult.raw.day = fields[2].substring(0, 2);
3912
+ decodeResult.raw.time = fields[2].substring(2);
4107
3913
  ResultFormatter.position(decodeResult, {
4108
- latitude: Number(fields[4]),
4109
- longitude: Number(fields[5])
3914
+ latitude: Number(fields[3].replace(/\s/g, "")),
3915
+ longitude: Number(fields[4].replace(/\s/g, ""))
4110
3916
  });
4111
- ResultFormatter.altitude(decodeResult, Number(fields[6]));
4112
- }
4113
- ResultFormatter.departureAirport(decodeResult, fields[8]);
4114
- ResultFormatter.arrivalAirport(decodeResult, fields[9]);
4115
- ResultFormatter.alternateAirport(decodeResult, fields[10]);
4116
- ResultFormatter.arrivalRunway(decodeResult, fields[11].split("/")[0]);
4117
- if (fields[12].length > 1) {
4118
- ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
3917
+ ResultFormatter.altitude(decodeResult, Number(fields[5]));
3918
+ ResultFormatter.groundspeed(decodeResult, Number(fields[6]));
3919
+ ResultFormatter.heading(decodeResult, Number(fields[7]));
3920
+ ResultFormatter.unknown(decodeResult, fields[8]);
3921
+ } else {
3922
+ decodeResult.decoded = false;
3923
+ ResultFormatter.unknown(decodeResult, text);
4119
3924
  }
4120
- ResultFormatter.checksum(decodeResult, parseInt(fields[32], 16));
4121
- ResultFormatter.unknownArr(
4122
- decodeResult,
4123
- [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter(
4124
- (f) => f != ""
4125
- )
4126
- );
4127
- } else {
4128
- decodeResult.decoded = false;
4129
- ResultFormatter.unknown(decodeResult, text);
4130
3925
  }
4131
3926
  if (decodeResult.decoded) {
4132
3927
  if (!decodeResult.remaining.text)
@@ -4139,469 +3934,569 @@ var Label_4N = class extends DecoderPlugin {
4139
3934
  }
4140
3935
  };
4141
3936
 
4142
- // lib/plugins/Label_4T_AGFSR.ts
4143
- var Label_4T_AGFSR = class extends DecoderPlugin {
4144
- name = "label-4t-agfsr";
3937
+ // lib/plugins/Label_8E.ts
3938
+ var Label_8E = class extends DecoderPlugin {
3939
+ name = "label-8e";
4145
3940
  qualifiers() {
4146
3941
  return {
4147
- labels: ["4T"],
4148
- preambles: ["AGFSR"]
3942
+ labels: ["8E"]
4149
3943
  };
4150
3944
  }
4151
3945
  decode(message, options = {}) {
4152
3946
  const decodeResult = this.defaultResult();
4153
3947
  decodeResult.decoder.name = this.name;
4154
- decodeResult.formatted.description = "Position Report";
3948
+ decodeResult.formatted.description = "ETA Report";
4155
3949
  decodeResult.message = message;
4156
- const data = message.text.substring(5).split("/");
4157
- if (!message.text.startsWith("AGFSR") || data.length !== 20) {
3950
+ const regex = /^(?<arrival_icao>\w{4}),(?<arrival_eta>\d{4})$/;
3951
+ const results = message.text.match(regex);
3952
+ if (results?.groups) {
4158
3953
  if (options.debug) {
4159
- console.log(`Decoder: Unknown 4T message: ${message.text}`);
3954
+ console.log("Label 8E ETA: groups");
3955
+ console.log(results.groups);
4160
3956
  }
4161
- ResultFormatter.unknown(decodeResult, message.text);
4162
- decodeResult.decoded = false;
4163
- decodeResult.decoder.decodeLevel = "none";
4164
- return decodeResult;
4165
- }
4166
- ResultFormatter.flightNumber(decodeResult, data[0].trim());
4167
- ResultFormatter.departureDay(decodeResult, Number(data[1]));
4168
- ResultFormatter.arrivalDay(decodeResult, Number(data[2]));
4169
- ResultFormatter.departureAirport(
4170
- decodeResult,
4171
- data[3].substring(0, 3),
4172
- "IATA"
4173
- );
4174
- ResultFormatter.arrivalAirport(decodeResult, data[3].substring(3), "IATA");
4175
- ResultFormatter.time_of_day(
4176
- decodeResult,
4177
- DateTimeUtils.convertHHMMSSToTod(data[4].substring(0, 4))
4178
- );
4179
- ResultFormatter.unknown(decodeResult, data[5], "/");
4180
- const lat = data[6].substring(0, 7);
4181
- const lon = data[6].substring(7, 15);
4182
- ResultFormatter.position(decodeResult, {
4183
- latitude: CoordinateUtils.getDirection(lat[6]) * Number(lat.substring(0, 2)) + Number(lat.substring(2, 6)) / 60,
4184
- longitude: CoordinateUtils.getDirection(lon[7]) * Number(lon.substring(0, 3)) + Number(lon.substring(3, 7)) / 60
4185
- });
4186
- ResultFormatter.altitude(decodeResult, 100 * Number(data[7]));
4187
- ResultFormatter.unknownArr(decodeResult, data.slice(8), "/");
4188
- decodeResult.decoded = true;
4189
- decodeResult.decoder.decodeLevel = "partial";
4190
- return decodeResult;
4191
- }
4192
- };
4193
-
4194
- // lib/plugins/Label_58.ts
4195
- var Label_58 = class extends DecoderPlugin {
4196
- name = "label-58";
4197
- qualifiers() {
4198
- return {
4199
- labels: ["58"]
4200
- };
4201
- }
4202
- decode(message, options = {}) {
4203
- const decodeResult = this.defaultResult();
4204
- decodeResult.decoder.name = this.name;
4205
- decodeResult.formatted.description = "Position Report";
4206
- decodeResult.message = message;
4207
- const data = message.text.split("/");
4208
- if (data.length === 8) {
4209
- ResultFormatter.flightNumber(decodeResult, data[0]);
4210
- ResultFormatter.day(decodeResult, Number(data[1]));
4211
- ResultFormatter.time_of_day(
3957
+ ResultFormatter.eta(
4212
3958
  decodeResult,
4213
- DateTimeUtils.convertHHMMSSToTod(data[2])
3959
+ DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta)
4214
3960
  );
4215
- const lat = data[3];
4216
- const lon = data[4];
4217
- ResultFormatter.position(decodeResult, {
4218
- latitude: CoordinateUtils.getDirection(lat[0]) * Number(lat.substring(1)),
4219
- longitude: CoordinateUtils.getDirection(lon[0]) * Number(lon.substring(1))
4220
- });
4221
- ResultFormatter.altitude(decodeResult, Number(data[5]));
4222
- ResultFormatter.unknown(decodeResult, data[6], "/");
4223
- ResultFormatter.unknown(decodeResult, data[7], "/");
4224
- } else {
4225
- if (options.debug) {
4226
- console.log(`Decoder: Unknown 58 message: ${message.text}`);
4227
- }
4228
- ResultFormatter.unknown(decodeResult, message.text);
4229
- decodeResult.decoded = false;
4230
- decodeResult.decoder.decodeLevel = "none";
4231
- return decodeResult;
3961
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
4232
3962
  }
4233
3963
  decodeResult.decoded = true;
4234
- decodeResult.decoder.decodeLevel = "partial";
3964
+ decodeResult.decoder.decodeLevel = "full";
4235
3965
  return decodeResult;
4236
3966
  }
4237
3967
  };
4238
3968
 
4239
- // lib/plugins/Label_4T_ETA.ts
4240
- var Label_4T_ETA = class extends DecoderPlugin {
4241
- name = "label-4t-eta";
3969
+ // lib/plugins/Label_B6.ts
3970
+ var Label_B6_Forwardslash = class extends DecoderPlugin {
3971
+ name = "label-b6-forwardslash";
4242
3972
  qualifiers() {
4243
3973
  return {
4244
- labels: ["4T"],
4245
- preambles: ["ETA"]
3974
+ labels: ["B6"],
3975
+ preambles: ["/"]
4246
3976
  };
4247
3977
  }
4248
3978
  decode(message, options = {}) {
4249
3979
  const decodeResult = this.defaultResult();
4250
3980
  decodeResult.decoder.name = this.name;
4251
- decodeResult.formatted.description = "ETA Report";
3981
+ decodeResult.formatted.description = "CPDLC Message";
4252
3982
  decodeResult.message = message;
4253
- const data = message.text.substring(3).split("/");
4254
- if (!message.text.startsWith("ETA") || data.length !== 3) {
4255
- if (options.debug) {
4256
- console.log(`Decoder: Unknown 4T message: ${message.text}`);
4257
- }
4258
- ResultFormatter.unknown(decodeResult, message.text);
4259
- decodeResult.decoded = false;
4260
- decodeResult.decoder.decodeLevel = "none";
4261
- return decodeResult;
3983
+ if (options.debug) {
3984
+ console.log("CPDLC: " + message);
4262
3985
  }
4263
- ResultFormatter.flightNumber(decodeResult, data[0].trim());
4264
- ResultFormatter.departureDay(decodeResult, Number(data[1]));
4265
- const etaData = data[2].split(" ");
4266
- ResultFormatter.arrivalDay(decodeResult, Number(etaData[0]));
4267
- ResultFormatter.arrivalAirport(decodeResult, etaData[1], "IATA");
4268
- ResultFormatter.eta(
4269
- decodeResult,
4270
- DateTimeUtils.convertHHMMSSToTod(etaData[2].substring(0, 4))
4271
- );
4272
- decodeResult.decoded = true;
4273
- decodeResult.decoder.decodeLevel = "full";
4274
3986
  return decodeResult;
4275
3987
  }
4276
3988
  };
4277
3989
 
4278
- // lib/plugins/Label_80.ts
4279
- var Label_80 = class extends DecoderPlugin {
4280
- name = "label-80";
3990
+ // lib/plugins/Label_ColonComma.ts
3991
+ var Label_ColonComma = class extends DecoderPlugin {
3992
+ name = "label-colon-comma";
4281
3993
  qualifiers() {
4282
3994
  return {
4283
- labels: ["80"],
4284
- preambles: []
3995
+ labels: [":;"]
4285
3996
  };
4286
3997
  }
4287
3998
  decode(message, options = {}) {
4288
3999
  const decodeResult = this.defaultResult();
4289
4000
  decodeResult.decoder.name = this.name;
4290
- decodeResult.formatted.description = "Airline Defined Position Report";
4291
- const lines = message.text.split(/\r?\n/);
4292
- if (lines.length === 1 && lines[0].includes(",")) {
4293
- this.parseCsvFormat(lines[0], decodeResult);
4294
- } else {
4295
- const header = lines[0].trim();
4296
- const headerParts = header.split(",");
4297
- for (let i = 0; i < headerParts.length - 1; i++) {
4298
- const moreFields = headerParts[i].split("/");
4299
- for (const more of moreFields) {
4300
- this.parseTags(more.trim(), decodeResult);
4301
- }
4302
- }
4303
- this.parseHeader(
4304
- headerParts[headerParts.length - 1].trim(),
4305
- decodeResult
4306
- );
4307
- for (let i = 1; i < lines.length; i++) {
4308
- const line = lines[i];
4309
- const parts = line.split("/");
4310
- for (const part of parts) {
4311
- this.parseTags(part.trim(), decodeResult);
4312
- }
4313
- }
4314
- }
4315
- if (decodeResult.formatted.items.length > 0) {
4316
- decodeResult.decoded = true;
4317
- decodeResult.decoder.decodeLevel = decodeResult.remaining.text === void 0 ? "full" : "partial";
4318
- }
4001
+ decodeResult.raw.frequency = Number(message.text) / 1e3;
4002
+ decodeResult.formatted.description = "Aircraft Transceiver Frequency Change";
4003
+ decodeResult.formatted.items.push({
4004
+ type: "frequency",
4005
+ label: "Frequency",
4006
+ value: `${decodeResult.raw.frequency} MHz`,
4007
+ code: "FREQ"
4008
+ });
4009
+ decodeResult.decoded = true;
4010
+ decodeResult.decoder.decodeLevel = "full";
4319
4011
  return decodeResult;
4320
4012
  }
4321
- parseHeader(header, results) {
4322
- const fields = header.split("/");
4323
- if (fields.length < 3) {
4324
- ResultFormatter.unknown(results, header, "/");
4325
- return;
4326
- }
4327
- const msgInfo = fields[0].split(/\s+/);
4328
- if (msgInfo.length === 3) {
4329
- ResultFormatter.unknownArr(results, msgInfo.slice(0, 2), " ");
4330
- ResultFormatter.flightNumber(results, msgInfo[2]);
4331
- } else {
4332
- ResultFormatter.unknown(results, header, "/");
4333
- return;
4334
- }
4335
- const otherInfo1 = fields[1].split(/\s+/);
4336
- if (otherInfo1.length === 2) {
4337
- ResultFormatter.day(results, parseInt(otherInfo1[0], 10));
4338
- ResultFormatter.departureAirport(results, otherInfo1[1]);
4339
- } else {
4340
- ResultFormatter.unknownArr(results, otherInfo1, " ");
4341
- }
4342
- const otherInfo2 = fields[2].split(/\s+/);
4343
- if (otherInfo2.length === 2) {
4344
- ResultFormatter.arrivalAirport(results, otherInfo2[0]);
4345
- ResultFormatter.tail(results, otherInfo2[1].replace(".", ""));
4013
+ };
4014
+
4015
+ // lib/utils/h1_helper.ts
4016
+ var H1Helper = class _H1Helper {
4017
+ static decodeH1Message(decodeResult, message) {
4018
+ const checksum = parseInt(message.slice(-4), 16);
4019
+ const data = message.slice(0, message.length - 4);
4020
+ let checksumAlgorithmUsed = "";
4021
+ if (crc16IbmSdlcRev(data) === checksum) {
4022
+ checksumAlgorithmUsed = "IBM-SDLC reversed";
4023
+ } else if (crc16Genibus(data) === checksum) {
4024
+ checksumAlgorithmUsed = "GENIBUS";
4346
4025
  } else {
4347
- ResultFormatter.unknownArr(results, otherInfo2, " ");
4348
- }
4349
- if (fields.length > 3) {
4350
- ResultFormatter.unknownArr(results, fields.slice(3), "/");
4026
+ decodeResult.decoded = false;
4027
+ decodeResult.decoder.decodeLevel = "none";
4028
+ return false;
4351
4029
  }
4352
- }
4353
- parseTags(part, results) {
4354
- const kvPair = part.split(/\s+/);
4355
- if (kvPair.length < 2) {
4356
- ResultFormatter.unknown(results, part, "/");
4357
- return;
4030
+ const fields = data.split("/");
4031
+ const canDecode = parseMessageType(decodeResult, fields[0]);
4032
+ if (!canDecode) {
4033
+ decodeResult.decoded = false;
4034
+ decodeResult.decoder.decodeLevel = "none";
4035
+ return false;
4358
4036
  }
4359
- const tag = kvPair[0];
4360
- const val = kvPair.slice(1).join(" ");
4361
- switch (tag) {
4362
- case "POS":
4363
- const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
4364
- const posResult = val.match(posRegex);
4365
- const lat = Number(posResult?.groups?.lat) * (posResult?.groups?.latd === "S" ? -1 : 1);
4366
- const lon = Number(posResult?.groups?.lng) * (posResult?.groups?.lngd === "W" ? -1 : 1);
4367
- const position = {
4368
- latitude: Number.isInteger(lat) ? lat / 1e3 : lat / 100,
4369
- longitude: Number.isInteger(lon) ? lon / 1e3 : lon / 100
4370
- };
4371
- ResultFormatter.position(results, position);
4372
- break;
4373
- case "ALT":
4374
- ResultFormatter.altitude(results, parseInt(val.replace("+", ""), 10));
4375
- break;
4376
- case "FL":
4377
- ResultFormatter.altitude(results, parseInt(val, 10) * 100);
4378
- break;
4379
- case "MCH":
4380
- ResultFormatter.mach(results, parseInt(val, 10) / 1e3);
4381
- break;
4382
- case "SPD":
4383
- ResultFormatter.groundspeed(results, parseInt(val, 10));
4384
- break;
4385
- case "TAS":
4386
- ResultFormatter.airspeed(results, parseInt(val, 10));
4387
- break;
4388
- case "SAT":
4389
- ResultFormatter.temperature(results, val);
4390
- break;
4391
- case "FB":
4392
- break;
4393
- case "FOB":
4394
- ResultFormatter.currentFuel(
4395
- results,
4396
- parseInt(val.replace(/\D/g, ""), 10)
4397
- );
4398
- break;
4399
- case "UTC":
4400
- ResultFormatter.time_of_day(
4401
- results,
4402
- DateTimeUtils.convertHHMMSSToTod(val)
4403
- );
4404
- break;
4405
- case "ETA":
4406
- const hhmm = val.split(".")[0].replace(":", "");
4407
- ResultFormatter.eta(results, DateTimeUtils.convertHHMMSSToTod(hhmm));
4408
- break;
4409
- case "HDG":
4410
- ResultFormatter.heading(results, parseInt(val, 10));
4411
- break;
4412
- case "NWYP":
4413
- results.raw.next_waypoint = val;
4414
- break;
4415
- case "SWN":
4416
- ResultFormatter.unknown(results, part, "/");
4417
- break;
4418
- case "DWN":
4419
- ResultFormatter.unknown(results, part, "/");
4420
- break;
4421
- case "AD":
4422
- break;
4423
- default:
4424
- ResultFormatter.unknown(results, part, "/");
4037
+ for (let i = 1; i < fields.length; ++i) {
4038
+ const key = fields[i].substring(0, 2);
4039
+ const data2 = fields[i].substring(2);
4040
+ switch (key) {
4041
+ case "AF":
4042
+ processAirField(decodeResult, data2.split(","));
4043
+ break;
4044
+ case "AK":
4045
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
4046
+ break;
4047
+ case "CG":
4048
+ processCenterOfGravity(decodeResult, data2.split(","));
4049
+ break;
4050
+ case "DC":
4051
+ processDateCode(decodeResult, data2.split(","));
4052
+ break;
4053
+ case "DI":
4054
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
4055
+ break;
4056
+ case "DT":
4057
+ processDT(decodeResult, data2.split(","));
4058
+ break;
4059
+ case "DQ":
4060
+ ResultFormatter.desiredAltitude(
4061
+ decodeResult,
4062
+ parseInt(data2, 10) * 100
4063
+ );
4064
+ break;
4065
+ case "ET":
4066
+ processETA(data2, decodeResult, fields, i);
4067
+ break;
4068
+ case "FB":
4069
+ ResultFormatter.currentFuel(decodeResult, parseInt(data2, 10));
4070
+ break;
4071
+ case "FN":
4072
+ decodeResult.raw.flight_number = data2;
4073
+ break;
4074
+ case "FX":
4075
+ ResultFormatter.freetext(decodeResult, data2);
4076
+ break;
4077
+ case "GA":
4078
+ ResultFormatter.groundAddress(decodeResult, data2);
4079
+ break;
4080
+ case "ID":
4081
+ processIdentification(decodeResult, data2.split(","));
4082
+ break;
4083
+ case "LR":
4084
+ processLandingReport(decodeResult, data2.split(","));
4085
+ break;
4086
+ case "PR":
4087
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
4088
+ break;
4089
+ case "PS":
4090
+ _H1Helper.processPS(decodeResult, data2.split(","));
4091
+ break;
4092
+ case "RF":
4093
+ case "RI":
4094
+ case "RM":
4095
+ case "RP":
4096
+ case "RS":
4097
+ FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
4098
+ break;
4099
+ case "RN":
4100
+ ResultFormatter.routeNumber(decodeResult, data2);
4101
+ break;
4102
+ case "RW":
4103
+ processRunway(decodeResult, data2.split(":"));
4104
+ break;
4105
+ case "SN":
4106
+ decodeResult.raw.serial_number = data2;
4107
+ break;
4108
+ case "SP":
4109
+ ResultFormatter.startPoint(decodeResult, data2);
4110
+ break;
4111
+ case "TD":
4112
+ processTimeOfDeparture(decodeResult, data2.split(","));
4113
+ break;
4114
+ case "TS":
4115
+ _H1Helper.processTimeStamp(decodeResult, data2.split(","));
4116
+ break;
4117
+ case "VR":
4118
+ ResultFormatter.version(decodeResult, parseInt(data2, 10) / 10);
4119
+ break;
4120
+ case "WD":
4121
+ processWindData(decodeResult, data2);
4122
+ break;
4123
+ case "WQ":
4124
+ processWeatherQuery(decodeResult, data2.split(":"));
4125
+ break;
4126
+ default:
4127
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
4128
+ }
4425
4129
  }
4130
+ ResultFormatter.checksumAlgorithm(decodeResult, checksumAlgorithmUsed);
4131
+ ResultFormatter.checksum(decodeResult, checksum);
4132
+ return true;
4426
4133
  }
4427
- parseCsvFormat(text, results) {
4428
- const csvParts = text.split(",");
4429
- const header = csvParts[0].trim().split(/\s+/);
4430
- ResultFormatter.unknown(results, header[0], " ");
4431
- ResultFormatter.unknown(results, header[1], " ");
4432
- ResultFormatter.position(
4433
- results,
4434
- CoordinateUtils.decodeStringCoordinates(header[2])
4134
+ static processPS(decodeResult, data) {
4135
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
4136
+ data[0]
4435
4137
  );
4436
- ResultFormatter.unknown(results, csvParts[1]);
4437
- ResultFormatter.time_of_day(
4438
- results,
4439
- DateTimeUtils.convertHHMMSSToTod(csvParts[2])
4138
+ if (position) {
4139
+ ResultFormatter.position(decodeResult, position);
4140
+ }
4141
+ if (data.length === 9) {
4142
+ processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
4143
+ ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
4144
+ ResultFormatter.temperature(decodeResult, data[6]);
4145
+ ResultFormatter.unknown(decodeResult, data[7]);
4146
+ ResultFormatter.unknown(decodeResult, data[8]);
4147
+ }
4148
+ if (data.length === 14) {
4149
+ ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
4150
+ processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
4151
+ ResultFormatter.temperature(decodeResult, data[7]);
4152
+ ResultFormatter.unknownArr(decodeResult, data.slice(8));
4153
+ }
4154
+ }
4155
+ static processPosition(decodeResult, data) {
4156
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
4157
+ data[0]
4440
4158
  );
4441
- ResultFormatter.unknownArr(results, csvParts.slice(4, 6), ",");
4442
- ResultFormatter.temperature(
4443
- results,
4444
- ((csvParts[6].charAt(0) === "M" ? -1 : 1) * parseInt(csvParts[6].slice(1), 10)).toString()
4159
+ if (position) {
4160
+ ResultFormatter.position(decodeResult, position);
4161
+ }
4162
+ if (data.length >= 10) {
4163
+ ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
4164
+ processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
4165
+ ResultFormatter.temperature(decodeResult, data[7]);
4166
+ ResultFormatter.unknown(decodeResult, data[8]);
4167
+ ResultFormatter.unknown(decodeResult, data[9]);
4168
+ }
4169
+ if (data.length >= 14) {
4170
+ ResultFormatter.unknownArr(decodeResult, data.slice(10));
4171
+ }
4172
+ }
4173
+ static processTimeStamp(decodeResult, data) {
4174
+ if (data.length > 2) {
4175
+ const positionData = data.slice(1);
4176
+ positionData[0] = positionData[0].substring(6);
4177
+ this.processPosition(decodeResult, positionData);
4178
+ }
4179
+ let time = DateTimeUtils.convertDateTimeToEpoch(
4180
+ data[0],
4181
+ data[1].substring(0, 6)
4445
4182
  );
4446
- ResultFormatter.airspeed(results, parseInt(csvParts[7], 10));
4447
- ResultFormatter.currentFuel(results, parseInt(csvParts[8], 10));
4183
+ if (Number.isNaN(time)) {
4184
+ const date = data[1].substring(2, 4) + data[1].substring(0, 2) + data[1].substring(4, 6);
4185
+ time = DateTimeUtils.convertDateTimeToEpoch(data[0], date);
4186
+ }
4187
+ decodeResult.raw.message_timestamp = time;
4448
4188
  }
4449
4189
  };
4450
-
4451
- // lib/plugins/Label_83.ts
4452
- var Label_83 = class extends DecoderPlugin {
4453
- name = "label-83";
4454
- qualifiers() {
4455
- return {
4456
- labels: ["83"]
4457
- };
4190
+ function processETA(data, decodeResult, fields, i) {
4191
+ if (data.length === 5) {
4192
+ ResultFormatter.day(decodeResult, Number(data.substring(0, 1)));
4193
+ ResultFormatter.eta(
4194
+ decodeResult,
4195
+ DateTimeUtils.convertHHMMSSToTod(data.substring(1))
4196
+ );
4197
+ } else if (data.length === 6) {
4198
+ ResultFormatter.day(decodeResult, Number(data.substring(0, 2)));
4199
+ ResultFormatter.eta(
4200
+ decodeResult,
4201
+ DateTimeUtils.convertHHMMSSToTod(data.substring(2))
4202
+ );
4203
+ } else {
4204
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
4458
4205
  }
4459
- decode(message, options = {}) {
4460
- const decodeResult = this.defaultResult();
4461
- decodeResult.decoder.name = this.name;
4462
- decodeResult.message = message;
4463
- decodeResult.formatted.description = "Airline Defined";
4464
- decodeResult.decoded = true;
4465
- const text = message.text;
4466
- if (text.substring(0, 10) === "4DH3 ETAT2") {
4467
- const fields = text.split(/\s+/);
4468
- if (fields[2].length > 5) {
4469
- decodeResult.raw.day = fields[2].substring(5);
4470
- }
4471
- ResultFormatter.unknown(decodeResult, fields[2].substring(0, 4));
4472
- const subfields = fields[3].split("/");
4473
- ResultFormatter.departureAirport(decodeResult, subfields[0]);
4474
- ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
4475
- ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
4476
- ResultFormatter.eta(
4477
- decodeResult,
4478
- DateTimeUtils.convertHHMMSSToTod(fields[6] + "00")
4479
- );
4480
- } else if (text.substring(0, 5) === "001PR") {
4481
- decodeResult.raw.day = text.substring(5, 7);
4482
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
4483
- text.substring(13, 28).replace(/\./g, "")
4484
- );
4485
- if (position) {
4486
- ResultFormatter.position(decodeResult, position);
4487
- }
4488
- ResultFormatter.altitude(decodeResult, Number(text.substring(28, 33)));
4489
- ResultFormatter.unknown(decodeResult, text.substring(33));
4490
- } else {
4491
- const fields = text.replace(/\s/g, "").split(",");
4492
- if (fields.length === 9) {
4493
- ResultFormatter.departureAirport(decodeResult, fields[0]);
4494
- ResultFormatter.arrivalAirport(decodeResult, fields[1]);
4495
- decodeResult.raw.day = fields[2].substring(0, 2);
4496
- decodeResult.raw.time = fields[2].substring(2);
4497
- ResultFormatter.position(decodeResult, {
4498
- latitude: Number(fields[3].replace(/\s/g, "")),
4499
- longitude: Number(fields[4].replace(/\s/g, ""))
4500
- });
4501
- ResultFormatter.altitude(decodeResult, Number(fields[5]));
4502
- ResultFormatter.groundspeed(decodeResult, Number(fields[6]));
4503
- ResultFormatter.heading(decodeResult, Number(fields[7]));
4504
- ResultFormatter.unknown(decodeResult, fields[8]);
4505
- } else {
4506
- decodeResult.decoded = false;
4507
- ResultFormatter.unknown(decodeResult, text);
4508
- }
4206
+ }
4207
+ function processAirField(decodeResult, data) {
4208
+ if (data.length === 2) {
4209
+ ResultFormatter.departureAirport(decodeResult, data[0]);
4210
+ ResultFormatter.arrivalAirport(decodeResult, data[1]);
4211
+ } else {
4212
+ ResultFormatter.unknown(decodeResult, data.join(","), "AF/");
4213
+ }
4214
+ }
4215
+ function processTimeOfDeparture(decodeResult, data) {
4216
+ if (data.length === 2) {
4217
+ decodeResult.raw.plannedDepartureTime = data[0];
4218
+ decodeResult.formatted.items.push({
4219
+ type: "ptd",
4220
+ code: "ptd",
4221
+ label: "Planned Departure Time",
4222
+ value: `YYYY-MM-${data[0].substring(0, 2)}T${data[0].substring(2, 4)}:${data[0].substring(4)}:00Z`
4223
+ });
4224
+ decodeResult.raw.plannedDepartureTime = data[1];
4225
+ decodeResult.formatted.items.push({
4226
+ type: "etd",
4227
+ code: "etd",
4228
+ label: "Estimated Departure Time",
4229
+ value: `${data[1].substring(0, 2)}:${data[1].substring(2)}`
4230
+ });
4231
+ } else {
4232
+ ResultFormatter.unknown(decodeResult, data.join(","), "/TD");
4233
+ }
4234
+ }
4235
+ function processIdentification(decodeResult, data) {
4236
+ ResultFormatter.tail(decodeResult, data[0]);
4237
+ if (data.length > 1) {
4238
+ ResultFormatter.flightNumber(decodeResult, data[1]);
4239
+ }
4240
+ if (data.length > 2) {
4241
+ decodeResult.raw.mission_number = data[2];
4242
+ }
4243
+ }
4244
+ function processDT(decodeResult, data) {
4245
+ if (data.length === 9) {
4246
+ ResultFormatter.unknown(decodeResult, data[0]);
4247
+ if (!decodeResult.raw.arrival_icao) {
4248
+ ResultFormatter.arrivalAirport(decodeResult, data[1]);
4509
4249
  }
4510
- if (decodeResult.decoded) {
4511
- if (!decodeResult.remaining.text)
4512
- decodeResult.decoder.decodeLevel = "full";
4513
- else decodeResult.decoder.decodeLevel = "partial";
4514
- } else {
4515
- decodeResult.decoder.decodeLevel = "none";
4250
+ ResultFormatter.arrivalRunway(decodeResult, data[2]);
4251
+ ResultFormatter.currentFuel(decodeResult, parseInt(data[3], 10));
4252
+ ResultFormatter.eta(
4253
+ decodeResult,
4254
+ DateTimeUtils.convertHHMMSSToTod(data[4])
4255
+ );
4256
+ ResultFormatter.unknown(decodeResult, data[5]);
4257
+ ResultFormatter.position(
4258
+ decodeResult,
4259
+ CoordinateUtils.decodeStringCoordinates(data[6])
4260
+ );
4261
+ ResultFormatter.unknown(decodeResult, data[7]);
4262
+ ResultFormatter.unknown(decodeResult, data[8]);
4263
+ return;
4264
+ }
4265
+ if (data.length === 4 || data.length === 5) {
4266
+ if (!decodeResult.raw.arrival_icao) {
4267
+ ResultFormatter.arrivalAirport(decodeResult, data[0]);
4516
4268
  }
4517
- return decodeResult;
4269
+ ResultFormatter.arrivalRunway(decodeResult, data[1]);
4270
+ ResultFormatter.currentFuel(decodeResult, parseInt(data[2], 10));
4271
+ ResultFormatter.eta(
4272
+ decodeResult,
4273
+ DateTimeUtils.convertHHMMSSToTod(data[3])
4274
+ );
4275
+ if (data.length > 4) {
4276
+ ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
4277
+ }
4278
+ return;
4518
4279
  }
4519
- };
4520
-
4521
- // lib/plugins/Label_8E.ts
4522
- var Label_8E = class extends DecoderPlugin {
4523
- name = "label-8e";
4524
- qualifiers() {
4525
- return {
4526
- labels: ["8E"]
4527
- };
4280
+ ResultFormatter.unknownArr(decodeResult, data, ",");
4281
+ }
4282
+ function processLandingReport(decodeResult, data) {
4283
+ if (data.length === 19) {
4284
+ ResultFormatter.unknown(decodeResult, data[1]);
4285
+ ResultFormatter.flightNumber(decodeResult, data[2]);
4286
+ ResultFormatter.departureAirport(decodeResult, data[3]);
4287
+ ResultFormatter.arrivalAirport(decodeResult, data[4]);
4288
+ ResultFormatter.arrivalRunway(decodeResult, data[5]);
4289
+ ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
4290
+ } else {
4291
+ ResultFormatter.unknown(decodeResult, data.join(","));
4292
+ }
4293
+ }
4294
+ function processCenterOfGravity(decodeResult, data) {
4295
+ if (data.length === 1) {
4296
+ if (data[0] !== void 0 && data[0] !== "") {
4297
+ ResultFormatter.cg(decodeResult, parseInt(data[0], 10) / 10);
4298
+ }
4299
+ } else if (data.length === 3) {
4300
+ if (data[0] !== void 0 && data[0] !== "") {
4301
+ ResultFormatter.cg(decodeResult, parseInt(data[0], 10) / 10, "center");
4302
+ }
4303
+ if (data[1] !== void 0 && data[1] !== "") {
4304
+ ResultFormatter.cg(decodeResult, parseInt(data[1], 10) / 10, "lower");
4305
+ }
4306
+ if (data[2] !== void 0 && data[2] !== "") {
4307
+ ResultFormatter.cg(decodeResult, parseInt(data[2], 10) / 10, "upper");
4308
+ }
4309
+ } else {
4310
+ ResultFormatter.unknown(decodeResult, data.join(","));
4528
4311
  }
4529
- decode(message, options = {}) {
4530
- const decodeResult = this.defaultResult();
4531
- decodeResult.decoder.name = this.name;
4532
- decodeResult.formatted.description = "ETA Report";
4533
- decodeResult.message = message;
4534
- const regex = /^(?<arrival_icao>\w{4}),(?<arrival_eta>\d{4})$/;
4535
- const results = message.text.match(regex);
4536
- if (results?.groups) {
4537
- if (options.debug) {
4538
- console.log("Label 8E ETA: groups");
4539
- console.log(results.groups);
4540
- }
4541
- ResultFormatter.eta(
4312
+ }
4313
+ function parseMessageType(decodeResult, messagePart) {
4314
+ const messageParts = messagePart.split(",");
4315
+ const messageType = messageParts[0];
4316
+ if (messageType.startsWith("POS")) {
4317
+ H1Helper.processPosition(decodeResult, messagePart.substring(3).split(","));
4318
+ return processMessageType(decodeResult, "POS");
4319
+ } else if (messageType.length === 6) {
4320
+ const part1 = processMessageType(decodeResult, messageType.substring(0, 3));
4321
+ const description = decodeResult.formatted.description;
4322
+ const part2 = processMessageType(decodeResult, messageType.substring(3, 6));
4323
+ decodeResult.formatted.description = description + " for " + decodeResult.formatted.description;
4324
+ if (messageParts.length > 1) {
4325
+ ResultFormatter.unknown(
4542
4326
  decodeResult,
4543
- DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta)
4327
+ messageParts.slice(1).join(","),
4328
+ "/"
4544
4329
  );
4545
- ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
4546
4330
  }
4547
- decodeResult.decoded = true;
4548
- decodeResult.decoder.decodeLevel = "full";
4549
- return decodeResult;
4331
+ return part1 && part2;
4550
4332
  }
4551
- };
4552
-
4553
- // lib/plugins/Label_B6.ts
4554
- var Label_B6_Forwardslash = class extends DecoderPlugin {
4555
- name = "label-b6-forwardslash";
4556
- qualifiers() {
4557
- return {
4558
- labels: ["B6"],
4559
- preambles: ["/"]
4560
- };
4333
+ if (messageParts.length > 1) {
4334
+ ResultFormatter.unknown(decodeResult, messageParts.slice(1).join(","), "/");
4561
4335
  }
4562
- decode(message, options = {}) {
4563
- const decodeResult = this.defaultResult();
4564
- decodeResult.decoder.name = this.name;
4565
- decodeResult.formatted.description = "CPDLC Message";
4566
- decodeResult.message = message;
4567
- if (options.debug) {
4568
- console.log("CPDLC: " + message);
4569
- }
4570
- return decodeResult;
4336
+ return processMessageType(decodeResult, messageType);
4337
+ }
4338
+ function processMessageType(decodeResult, type) {
4339
+ if (type === "FPN") {
4340
+ decodeResult.formatted.description = "Flight Plan";
4341
+ } else if (type === "FTX") {
4342
+ decodeResult.formatted.description = "Free Text";
4343
+ } else if (type === "INI") {
4344
+ decodeResult.formatted.description = "Initial Report";
4345
+ } else if (type === "INR") {
4346
+ decodeResult.formatted.description = "In-Range Report";
4347
+ } else if (type === "LDI") {
4348
+ decodeResult.formatted.description = "Load Distribution Information";
4349
+ } else if (type === "PER") {
4350
+ decodeResult.formatted.description = "Performance Report";
4351
+ } else if (type === "POS") {
4352
+ decodeResult.formatted.description = "Position Report";
4353
+ } else if (type === "PRG") {
4354
+ decodeResult.formatted.description = "Progress Report";
4355
+ } else if (type === "PWI") {
4356
+ decodeResult.formatted.description = "Pilot Weather Information";
4357
+ } else if (type === "WXR") {
4358
+ decodeResult.formatted.description = "Weather Report";
4359
+ } else if (type === "REJ") {
4360
+ decodeResult.formatted.description = "Reject";
4361
+ } else if (type === "REQ") {
4362
+ decodeResult.formatted.description = "Request";
4363
+ } else if (type === "RES") {
4364
+ decodeResult.formatted.description = "Response";
4365
+ } else {
4366
+ decodeResult.formatted.description = "Unknown H1 Message";
4367
+ return false;
4571
4368
  }
4572
- };
4573
-
4574
- // lib/plugins/Label_ColonComma.ts
4575
- var Label_ColonComma = class extends DecoderPlugin {
4576
- name = "label-colon-comma";
4577
- qualifiers() {
4578
- return {
4579
- labels: [":;"]
4580
- };
4369
+ return true;
4370
+ }
4371
+ function processDateCode(decodeResult, data) {
4372
+ if (data.length === 1) {
4373
+ } else if (data.length === 2) {
4374
+ const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
4375
+ const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
4376
+ decodeResult.raw.message_timestamp = time;
4581
4377
  }
4582
- decode(message, options = {}) {
4583
- const decodeResult = this.defaultResult();
4584
- decodeResult.decoder.name = this.name;
4585
- decodeResult.raw.frequency = Number(message.text) / 1e3;
4586
- decodeResult.formatted.description = "Aircraft Transceiver Frequency Change";
4587
- decodeResult.formatted.items.push({
4588
- type: "frequency",
4589
- label: "Frequency",
4590
- value: `${decodeResult.raw.frequency} MHz`,
4591
- code: "FREQ"
4592
- });
4593
- decodeResult.decoded = true;
4594
- decodeResult.decoder.decodeLevel = "full";
4595
- return decodeResult;
4378
+ }
4379
+ function processWeatherQuery(decodeResult, data) {
4380
+ if (data.length !== 2) {
4381
+ ResultFormatter.unknown(decodeResult, data.join(":"), "WQ/");
4382
+ return;
4596
4383
  }
4597
- };
4384
+ const alts = data[0].split(".");
4385
+ const route = data[1].split(".");
4386
+ ResultFormatter.requestedAltitudes(
4387
+ decodeResult,
4388
+ alts.map((a) => parseInt(a, 10) * 100)
4389
+ );
4390
+ const waypoints = route.map((wp) => {
4391
+ return { name: wp };
4392
+ });
4393
+ ResultFormatter.route(decodeResult, { waypoints });
4394
+ }
4395
+ function processRoute(decodeResult, last, time, next, eta, then, date) {
4396
+ const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
4397
+ const nextTime = date ? DateTimeUtils.convertDateTimeToEpoch(eta, date) : DateTimeUtils.convertHHMMSSToTod(eta);
4398
+ const timeFormat = date ? "epoch" : "tod";
4399
+ const lastWaypoint = RouteUtils.getWaypoint(last);
4400
+ lastWaypoint.time = lastTime;
4401
+ lastWaypoint.timeFormat = timeFormat;
4402
+ const nextWaypoint = RouteUtils.getWaypoint(next);
4403
+ nextWaypoint.time = nextTime;
4404
+ nextWaypoint.timeFormat = timeFormat;
4405
+ const thenWaypoint = RouteUtils.getWaypoint(then || "?");
4406
+ const waypoints = [lastWaypoint, nextWaypoint, thenWaypoint];
4407
+ ResultFormatter.route(decodeResult, { waypoints });
4408
+ }
4409
+ function processWindData(decodeResult, message) {
4410
+ const wind = [];
4411
+ const flightLevel = Number(message.slice(0, 3));
4412
+ const fields = message.slice(4).split(".");
4413
+ fields.forEach((field) => {
4414
+ if (field.length < 4) {
4415
+ return;
4416
+ }
4417
+ const data = field.split(",");
4418
+ const waypoint = { name: data[0] };
4419
+ const windData = data[1];
4420
+ const windDirection = parseInt(windData.slice(0, 3), 10);
4421
+ const windSpeed = parseInt(windData.slice(3), 10);
4422
+ if (data.length === 3) {
4423
+ const tempData = data[2];
4424
+ const tempFlightLevel = Number(tempData.slice(0, 3));
4425
+ const tempString = tempData.slice(3);
4426
+ const tempDegrees = Number(tempString.substring(1)) * (tempString.charAt(0) === "M" ? -1 : 1);
4427
+ wind.push({
4428
+ waypoint,
4429
+ flightLevel,
4430
+ windDirection,
4431
+ windSpeed,
4432
+ temperature: {
4433
+ flightLevel: tempFlightLevel,
4434
+ degreesC: tempDegrees
4435
+ }
4436
+ });
4437
+ } else {
4438
+ wind.push({
4439
+ waypoint,
4440
+ flightLevel,
4441
+ windDirection,
4442
+ windSpeed
4443
+ });
4444
+ }
4445
+ });
4446
+ ResultFormatter.windData(decodeResult, wind);
4447
+ }
4448
+ function processRunway(decodeResult, data) {
4449
+ const parts = data[0].split(".");
4450
+ const more = parts[0].split(",");
4451
+ ResultFormatter.departureRunway(decodeResult, more[0]);
4452
+ ResultFormatter.unknownArr(decodeResult, more.slice(1), ",");
4453
+ ResultFormatter.unknownArr(decodeResult, parts.slice(1), ".");
4454
+ ResultFormatter.departureAirport(decodeResult, data[1].split(",")[0]);
4455
+ ResultFormatter.unknownArr(decodeResult, data[1].split(",").slice(1), ",");
4456
+ }
4457
+ function crc16IbmSdlcRev(data) {
4458
+ let crc = 65535;
4459
+ const bytes = Buffer.from(data, "ascii");
4460
+ for (const byte of bytes) {
4461
+ crc ^= byte;
4462
+ for (let i = 0; i < 8; i++) {
4463
+ if ((crc & 1) !== 0) {
4464
+ crc = crc >>> 1 ^ 33800;
4465
+ } else {
4466
+ crc = crc >>> 1;
4467
+ }
4468
+ }
4469
+ }
4470
+ crc = (crc ^ 65535) & 65535;
4471
+ const nibble1 = crc >> 12 & 15;
4472
+ const nibble2 = crc >> 8 & 15;
4473
+ const nibble3 = crc >> 4 & 15;
4474
+ const nibble4 = crc & 15;
4475
+ return nibble4 << 12 | nibble3 << 8 | nibble2 << 4 | nibble1;
4476
+ }
4477
+ function crc16Genibus(data) {
4478
+ let crc = 65535;
4479
+ const polynomial = 4129;
4480
+ const bytes = Buffer.from(data, "ascii");
4481
+ for (const byte of bytes) {
4482
+ crc ^= byte << 8;
4483
+ for (let i = 0; i < 8; i++) {
4484
+ if ((crc & 32768) !== 0) {
4485
+ crc = (crc << 1 ^ polynomial) & 65535;
4486
+ } else {
4487
+ crc = crc << 1 & 65535;
4488
+ }
4489
+ }
4490
+ }
4491
+ return (crc ^ 65535) & 65535;
4492
+ }
4598
4493
 
4599
4494
  // lib/plugins/Label_H1.ts
4600
4495
  var Label_H1 = class extends DecoderPlugin {
4601
4496
  name = "label-h1";
4602
4497
  qualifiers() {
4603
4498
  return {
4604
- labels: ["H1"]
4499
+ labels: ["1J", "2J", "2P", "4J", "80", "H1"]
4605
4500
  };
4606
4501
  }
4607
4502
  decode(message, options = {}) {
@@ -4609,33 +4504,58 @@ var Label_H1 = class extends DecoderPlugin {
4609
4504
  decodeResult.decoder.name = this.name;
4610
4505
  decodeResult.message = message;
4611
4506
  const msg = message.text.replace(/\n|\r/g, "");
4612
- const parts = msg.split("#");
4613
4507
  let decoded = false;
4508
+ decoded = H1Helper.decodeH1Message(decodeResult, msg);
4509
+ if (decoded) {
4510
+ return this.processDecodeResult(decodeResult, decoded, options, message);
4511
+ }
4614
4512
  if (msg.startsWith("/")) {
4615
4513
  const headerData = msg.split(".");
4616
- const decoded2 = H1Helper.decodeH1Message(
4514
+ decoded = H1Helper.decodeH1Message(
4617
4515
  decodeResult,
4618
4516
  headerData.slice(1).join(".")
4619
4517
  );
4620
- if (decoded2) {
4518
+ if (decoded) {
4621
4519
  decodeResult.remaining.text = headerData[0] + "." + decodeResult.remaining.text;
4622
- decodeResult.decoded = decoded2;
4623
- decodeResult.decoder.decodeLevel = "partial";
4520
+ return this.processDecodeResult(
4521
+ decodeResult,
4522
+ decoded,
4523
+ options,
4524
+ message
4525
+ );
4624
4526
  }
4625
- return decodeResult;
4626
- } else if (parts.length === 1) {
4627
- decoded = H1Helper.decodeH1Message(decodeResult, msg);
4628
- } else if (parts.length == 2) {
4629
- const offset = parts[0] === "- " || isNaN(parseInt(parts[1][1])) ? 3 : 4;
4527
+ }
4528
+ const hashParts = msg.split("#");
4529
+ if (hashParts.length == 2) {
4530
+ const offset = hashParts[0] === "- " || isNaN(parseInt(hashParts[1][1])) ? 3 : 4;
4630
4531
  decoded = H1Helper.decodeH1Message(
4631
4532
  decodeResult,
4632
- msg.slice(parts[0].length + offset)
4533
+ msg.slice(hashParts[0].length + offset)
4633
4534
  );
4634
- if (decoded && parts[0].length > 0) {
4635
- ResultFormatter.flightNumber(decodeResult, parts[0].substring(4));
4636
- decodeResult.remaining.text = parts[0].substring(0, 4) + "#" + parts[1].substring(0, offset - 1) + "/" + decodeResult.remaining.text;
4535
+ if (decoded && hashParts[0].length > 0) {
4536
+ ResultFormatter.flightNumber(decodeResult, hashParts[0].substring(4));
4537
+ decodeResult.remaining.text = hashParts[0].substring(0, 4) + "#" + hashParts[1].substring(0, offset - 1) + "/" + decodeResult.remaining.text;
4637
4538
  }
4539
+ if (decoded) {
4540
+ return this.processDecodeResult(
4541
+ decodeResult,
4542
+ decoded,
4543
+ options,
4544
+ message
4545
+ );
4546
+ }
4547
+ }
4548
+ const slashParts = msg.split("/");
4549
+ if (slashParts[0].length > 3) {
4550
+ decoded = H1Helper.decodeH1Message(
4551
+ decodeResult,
4552
+ msg.slice(slashParts[0].length - 3)
4553
+ );
4554
+ decodeResult.remaining.text = slashParts[0].slice(0, 3) + "/" + decodeResult.remaining.text;
4638
4555
  }
4556
+ return this.processDecodeResult(decodeResult, decoded, options, message);
4557
+ }
4558
+ processDecodeResult(decodeResult, decoded, options, message) {
4639
4559
  decodeResult.decoded = decoded;
4640
4560
  decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
4641
4561
  if (decodeResult.formatted.items.length === 0) {
@@ -6268,7 +6188,6 @@ var MessageDecoder = class {
6268
6188
  this.registerPlugin(new Label_16_N_Space(this));
6269
6189
  this.registerPlugin(new Label_16_POSA1(this));
6270
6190
  this.registerPlugin(new Label_16_TOD(this));
6271
- this.registerPlugin(new Label_1J_2J_FTX(this));
6272
6191
  this.registerPlugin(new Label_1L_3Line(this));
6273
6192
  this.registerPlugin(new Label_1L_070(this));
6274
6193
  this.registerPlugin(new Label_1L_660(this));
@@ -6281,7 +6200,6 @@ var MessageDecoder = class {
6281
6200
  this.registerPlugin(new Label_2P_FM3(this));
6282
6201
  this.registerPlugin(new Label_2P_FM4(this));
6283
6202
  this.registerPlugin(new Label_2P_FM5(this));
6284
- this.registerPlugin(new Label_2P_POS(this));
6285
6203
  this.registerPlugin(new Label_30_Slash_EA(this));
6286
6204
  this.registerPlugin(new Label_44_ETA(this));
6287
6205
  this.registerPlugin(new Label_44_IN(this));
@@ -6294,7 +6212,6 @@ var MessageDecoder = class {
6294
6212
  this.registerPlugin(new Label_4A_DIS(this));
6295
6213
  this.registerPlugin(new Label_4A_DOOR(this));
6296
6214
  this.registerPlugin(new Label_4A_Slash_01(this));
6297
- this.registerPlugin(new Label_4J_POS(this));
6298
6215
  this.registerPlugin(new Label_4N(this));
6299
6216
  this.registerPlugin(new Label_4T_AGFSR(this));
6300
6217
  this.registerPlugin(new Label_4T_ETA(this));