@airframes/acars-decoder 1.6.10 → 1.6.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1198 -691
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1198 -691
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -49,6 +49,74 @@ var IcaoDecoder = class {
|
|
|
49
49
|
}
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
+
// lib/DateTimeUtils.ts
|
|
53
|
+
var DateTimeUtils = class {
|
|
54
|
+
// Expects a four digit UTC time string (HHMM)
|
|
55
|
+
static UTCToString(UTCString) {
|
|
56
|
+
let utcDate = /* @__PURE__ */ new Date();
|
|
57
|
+
utcDate.setUTCHours(+UTCString.substr(0, 2), +UTCString.substr(2, 2), 0);
|
|
58
|
+
return utcDate.toTimeString();
|
|
59
|
+
}
|
|
60
|
+
// Expects a six digit date string and a four digit UTC time string
|
|
61
|
+
// (DDMMYY) (HHMM)
|
|
62
|
+
static UTCDateTimeToString(dateString, timeString) {
|
|
63
|
+
let utcDate = /* @__PURE__ */ new Date();
|
|
64
|
+
utcDate.setUTCDate(+dateString.substr(0, 2));
|
|
65
|
+
utcDate.setUTCMonth(+dateString.substr(2, 2));
|
|
66
|
+
if (dateString.length === 6) {
|
|
67
|
+
utcDate.setUTCFullYear(2e3 + +dateString.substr(4, 2));
|
|
68
|
+
}
|
|
69
|
+
if (timeString.length === 6) {
|
|
70
|
+
utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), +timeString.substr(4, 2));
|
|
71
|
+
} else {
|
|
72
|
+
utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), 0);
|
|
73
|
+
}
|
|
74
|
+
return utcDate.toUTCString();
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
*
|
|
78
|
+
* @param time HHMMSS
|
|
79
|
+
* @returns seconds since midnight
|
|
80
|
+
*/
|
|
81
|
+
static convertHHMMSSToTod(time) {
|
|
82
|
+
const h = Number(time.substring(0, 2));
|
|
83
|
+
const m = Number(time.substring(2, 4));
|
|
84
|
+
const s = Number(time.substring(4, 6));
|
|
85
|
+
const tod = h * 3600 + m * 60 + s;
|
|
86
|
+
return tod;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
*
|
|
90
|
+
* @param time HHMMSS
|
|
91
|
+
* @param date MMDDYY or MMDDYYYY
|
|
92
|
+
* @returns seconds since epoch
|
|
93
|
+
*/
|
|
94
|
+
static convertDateTimeToEpoch(time, date) {
|
|
95
|
+
if (date.length === 6) {
|
|
96
|
+
date = date.substring(0, 4) + `20${date.substring(4, 6)}`;
|
|
97
|
+
}
|
|
98
|
+
const timestamp = `${date.substring(4, 8)}-${date.substring(0, 2)}-${date.substring(2, 4)}T${time.substring(0, 2)}:${time.substring(2, 4)}:${time.substring(4, 6)}.000Z`;
|
|
99
|
+
const millis = Date.parse(timestamp);
|
|
100
|
+
return millis / 1e3;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Converts a timestamp to a string
|
|
104
|
+
*
|
|
105
|
+
* ISO-8601 format for 'epoch'
|
|
106
|
+
* HH:MM:SS for 'tod'
|
|
107
|
+
* @param time
|
|
108
|
+
* @param format
|
|
109
|
+
* @returns
|
|
110
|
+
*/
|
|
111
|
+
static timestampToString(time, format) {
|
|
112
|
+
const date = new Date(time * 1e3);
|
|
113
|
+
if (format == "tod") {
|
|
114
|
+
return date.toISOString().slice(11, 19);
|
|
115
|
+
}
|
|
116
|
+
return date.toISOString().slice(0, -5) + "Z";
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
52
120
|
// lib/DecoderPlugin.ts
|
|
53
121
|
var DecoderPlugin = class {
|
|
54
122
|
decoder;
|
|
@@ -154,10 +222,137 @@ var CoordinateUtils = class {
|
|
|
154
222
|
const lonDir = coords.longitude > 0 ? "E" : "W";
|
|
155
223
|
return `${Math.abs(coords.latitude).toFixed(3)} ${latDir}, ${Math.abs(coords.longitude).toFixed(3)} ${lonDir}`;
|
|
156
224
|
}
|
|
225
|
+
static getDirection(coord) {
|
|
226
|
+
if (coord.startsWith("N") || coord.startsWith("E")) {
|
|
227
|
+
return 1;
|
|
228
|
+
} else if (coord.startsWith("S") || coord.startsWith("W")) {
|
|
229
|
+
return -1;
|
|
230
|
+
}
|
|
231
|
+
return NaN;
|
|
232
|
+
}
|
|
233
|
+
static dmsToDecimalDegrees(degrees, minutes, seconds) {
|
|
234
|
+
return degrees + minutes / 60 + seconds / 3600;
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// lib/utils/route_utils.ts
|
|
239
|
+
var RouteUtils = class _RouteUtils {
|
|
240
|
+
static formatFlightState(state) {
|
|
241
|
+
switch (state) {
|
|
242
|
+
case "TO":
|
|
243
|
+
return "Takeoff";
|
|
244
|
+
case "IC":
|
|
245
|
+
return "Initial Climb";
|
|
246
|
+
case "CL":
|
|
247
|
+
return "Climb";
|
|
248
|
+
case "ER":
|
|
249
|
+
return "En Route";
|
|
250
|
+
case "DC":
|
|
251
|
+
return "Descent";
|
|
252
|
+
case "AP":
|
|
253
|
+
return "Approach";
|
|
254
|
+
default:
|
|
255
|
+
return `Unknown ${state}`;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
static routeToString(route) {
|
|
259
|
+
let str = "";
|
|
260
|
+
if (route.name) {
|
|
261
|
+
str += route.name;
|
|
262
|
+
}
|
|
263
|
+
if (route.runway) {
|
|
264
|
+
str += `(${route.runway})`;
|
|
265
|
+
}
|
|
266
|
+
if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
|
|
267
|
+
str += " starting at ";
|
|
268
|
+
} else if (str.length !== 0 && route.waypoints) {
|
|
269
|
+
str += ": ";
|
|
270
|
+
}
|
|
271
|
+
if (route.waypoints) {
|
|
272
|
+
str += _RouteUtils.waypointsToString(route.waypoints);
|
|
273
|
+
}
|
|
274
|
+
return str;
|
|
275
|
+
}
|
|
276
|
+
static waypointToString(waypoint) {
|
|
277
|
+
let s = waypoint.name;
|
|
278
|
+
if (waypoint.latitude && waypoint.longitude) {
|
|
279
|
+
s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
|
|
280
|
+
}
|
|
281
|
+
if (waypoint.offset) {
|
|
282
|
+
s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
|
|
283
|
+
}
|
|
284
|
+
if (waypoint.time && waypoint.timeFormat) {
|
|
285
|
+
s += `@${DateTimeUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
|
|
286
|
+
}
|
|
287
|
+
return s;
|
|
288
|
+
}
|
|
289
|
+
static getWaypoint(leg) {
|
|
290
|
+
const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
|
|
291
|
+
if (regex?.length == 4) {
|
|
292
|
+
return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
|
|
293
|
+
}
|
|
294
|
+
const waypoint = leg.split(",");
|
|
295
|
+
if (waypoint.length == 2) {
|
|
296
|
+
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
|
|
297
|
+
if (position) {
|
|
298
|
+
return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (leg.length == 13 || leg.length == 14) {
|
|
302
|
+
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
|
|
303
|
+
const name = waypoint.length == 2 ? waypoint[0] : "";
|
|
304
|
+
if (position) {
|
|
305
|
+
return { name, latitude: position.latitude, longitude: position.longitude };
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return { name: leg };
|
|
309
|
+
}
|
|
310
|
+
static waypointsToString(waypoints) {
|
|
311
|
+
let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
|
|
312
|
+
if (str.startsWith(" > ")) {
|
|
313
|
+
str = ">>" + str.slice(2);
|
|
314
|
+
}
|
|
315
|
+
return str;
|
|
316
|
+
}
|
|
157
317
|
};
|
|
158
318
|
|
|
159
319
|
// lib/utils/result_formatter.ts
|
|
160
320
|
var ResultFormatter = class {
|
|
321
|
+
static state_change(decodeResult, from, to) {
|
|
322
|
+
decodeResult.raw.state_change = {
|
|
323
|
+
from,
|
|
324
|
+
to
|
|
325
|
+
};
|
|
326
|
+
from = RouteUtils.formatFlightState(from);
|
|
327
|
+
to = RouteUtils.formatFlightState(to);
|
|
328
|
+
decodeResult.formatted.items.push({
|
|
329
|
+
type: "state_change",
|
|
330
|
+
code: "STATE_CHANGE",
|
|
331
|
+
label: "State Change",
|
|
332
|
+
value: `${from} -> ${to}`
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
static freetext(decodeResult, value) {
|
|
336
|
+
decodeResult.raw.freetext = value;
|
|
337
|
+
decodeResult.formatted.items.push({
|
|
338
|
+
type: "freetext",
|
|
339
|
+
code: "FREE_TEXT",
|
|
340
|
+
label: "Free Text",
|
|
341
|
+
value
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
static door_event(decodeResult, name, state) {
|
|
345
|
+
decodeResult.raw.door_event = {
|
|
346
|
+
door: name,
|
|
347
|
+
state
|
|
348
|
+
};
|
|
349
|
+
decodeResult.formatted.items.push({
|
|
350
|
+
type: "door_event",
|
|
351
|
+
code: "DOOR",
|
|
352
|
+
label: "Door Event",
|
|
353
|
+
value: `${name} ${state}`
|
|
354
|
+
});
|
|
355
|
+
}
|
|
161
356
|
static position(decodeResult, value) {
|
|
162
357
|
decodeResult.raw.position = value;
|
|
163
358
|
decodeResult.formatted.items.push({
|
|
@@ -178,16 +373,41 @@ var ResultFormatter = class {
|
|
|
178
373
|
}
|
|
179
374
|
static flightNumber(decodeResult, value) {
|
|
180
375
|
decodeResult.raw.flight_number = value;
|
|
376
|
+
decodeResult.formatted.items.push({
|
|
377
|
+
type: "flight_number",
|
|
378
|
+
code: "FLIGHT",
|
|
379
|
+
label: "Flight Number",
|
|
380
|
+
value: decodeResult.raw.flight_number
|
|
381
|
+
});
|
|
181
382
|
}
|
|
182
|
-
static
|
|
183
|
-
decodeResult.raw.
|
|
383
|
+
static callsign(decodeResult, value) {
|
|
384
|
+
decodeResult.raw.callsign = value;
|
|
184
385
|
decodeResult.formatted.items.push({
|
|
185
|
-
type: "
|
|
186
|
-
code: "
|
|
187
|
-
label: "
|
|
188
|
-
value: decodeResult.raw.
|
|
386
|
+
type: "callsign",
|
|
387
|
+
code: "CALLSIGN",
|
|
388
|
+
label: "Callsign",
|
|
389
|
+
value: decodeResult.raw.callsign
|
|
189
390
|
});
|
|
190
391
|
}
|
|
392
|
+
static departureAirport(decodeResult, value, type = "ICAO") {
|
|
393
|
+
if (type === "ICAO") {
|
|
394
|
+
decodeResult.raw.departure_icao = value;
|
|
395
|
+
decodeResult.formatted.items.push({
|
|
396
|
+
type: "icao",
|
|
397
|
+
code: "ORG",
|
|
398
|
+
label: "Origin",
|
|
399
|
+
value
|
|
400
|
+
});
|
|
401
|
+
} else {
|
|
402
|
+
decodeResult.raw.departure_iata = value;
|
|
403
|
+
decodeResult.formatted.items.push({
|
|
404
|
+
type: "iata",
|
|
405
|
+
code: "ORG",
|
|
406
|
+
label: "Origin",
|
|
407
|
+
value
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
}
|
|
191
411
|
static departureRunway(decodeResult, value) {
|
|
192
412
|
decodeResult.raw.departure_runway = value;
|
|
193
413
|
decodeResult.formatted.items.push({
|
|
@@ -197,24 +417,53 @@ var ResultFormatter = class {
|
|
|
197
417
|
value: decodeResult.raw.departure_runway
|
|
198
418
|
});
|
|
199
419
|
}
|
|
200
|
-
static arrivalAirport(decodeResult, value) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
420
|
+
static arrivalAirport(decodeResult, value, type = "ICAO") {
|
|
421
|
+
if (type === "ICAO") {
|
|
422
|
+
decodeResult.raw.arrival_icao = value;
|
|
423
|
+
decodeResult.formatted.items.push({
|
|
424
|
+
type: "icao",
|
|
425
|
+
code: "DST",
|
|
426
|
+
label: "Destination",
|
|
427
|
+
value
|
|
428
|
+
});
|
|
429
|
+
} else {
|
|
430
|
+
decodeResult.raw.arrival_iata = value;
|
|
431
|
+
decodeResult.formatted.items.push({
|
|
432
|
+
type: "iata",
|
|
433
|
+
code: "DST",
|
|
434
|
+
label: "Destination",
|
|
435
|
+
value
|
|
436
|
+
});
|
|
437
|
+
}
|
|
208
438
|
}
|
|
209
|
-
static
|
|
210
|
-
decodeResult.raw.
|
|
439
|
+
static alternateAirport(decodeResult, value) {
|
|
440
|
+
decodeResult.raw.alternate_icao = value;
|
|
211
441
|
decodeResult.formatted.items.push({
|
|
212
|
-
type: "
|
|
213
|
-
code: "
|
|
214
|
-
label: "
|
|
215
|
-
value:
|
|
442
|
+
type: "icao",
|
|
443
|
+
code: "ALT_DST",
|
|
444
|
+
label: "Alternate Destination",
|
|
445
|
+
value: decodeResult.raw.alternate_icao
|
|
216
446
|
});
|
|
217
447
|
}
|
|
448
|
+
static eta(decodeResult, time, type = "tod") {
|
|
449
|
+
if (type === "tod") {
|
|
450
|
+
decodeResult.raw.eta_time = time;
|
|
451
|
+
decodeResult.formatted.items.push({
|
|
452
|
+
type: "time_of_day",
|
|
453
|
+
code: "ETA",
|
|
454
|
+
label: "Estimated Time of Arrival",
|
|
455
|
+
value: DateTimeUtils.timestampToString(time, "tod")
|
|
456
|
+
});
|
|
457
|
+
} else {
|
|
458
|
+
decodeResult.raw.eta_date = time;
|
|
459
|
+
decodeResult.formatted.items.push({
|
|
460
|
+
type: "epoch",
|
|
461
|
+
code: "ETA",
|
|
462
|
+
label: "Estimated Time of Arrival",
|
|
463
|
+
value: DateTimeUtils.timestampToString(time, "epoch")
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
}
|
|
218
467
|
static arrivalRunway(decodeResult, value) {
|
|
219
468
|
decodeResult.raw.arrival_runway = value;
|
|
220
469
|
decodeResult.formatted.items.push({
|
|
@@ -224,6 +473,15 @@ var ResultFormatter = class {
|
|
|
224
473
|
value: decodeResult.raw.arrival_runway
|
|
225
474
|
});
|
|
226
475
|
}
|
|
476
|
+
static alternateRunway(decodeResult, value) {
|
|
477
|
+
decodeResult.raw.alternate_runway = value;
|
|
478
|
+
decodeResult.formatted.items.push({
|
|
479
|
+
type: "runway",
|
|
480
|
+
code: "ALT_ARWY",
|
|
481
|
+
label: "Alternate Runway",
|
|
482
|
+
value: decodeResult.raw.alternate_runway
|
|
483
|
+
});
|
|
484
|
+
}
|
|
227
485
|
static currentFuel(decodeResult, value) {
|
|
228
486
|
decodeResult.raw.fuel_on_board = value;
|
|
229
487
|
decodeResult.formatted.items.push({
|
|
@@ -257,16 +515,16 @@ var ResultFormatter = class {
|
|
|
257
515
|
type: "aircraft_groundspeed",
|
|
258
516
|
code: "GSPD",
|
|
259
517
|
label: "Aircraft Groundspeed",
|
|
260
|
-
value: `${decodeResult.raw.groundspeed}`
|
|
518
|
+
value: `${decodeResult.raw.groundspeed} knots`
|
|
261
519
|
});
|
|
262
520
|
}
|
|
263
521
|
static temperature(decodeResult, value) {
|
|
264
|
-
decodeResult.raw.outside_air_temperature = Number(value.
|
|
522
|
+
decodeResult.raw.outside_air_temperature = Number(value.replace("M", "-").replace("P", "+"));
|
|
265
523
|
decodeResult.formatted.items.push({
|
|
266
524
|
type: "outside_air_temperature",
|
|
267
525
|
code: "OATEMP",
|
|
268
526
|
label: "Outside Air Temperature (C)",
|
|
269
|
-
value: `${decodeResult.raw.outside_air_temperature}`
|
|
527
|
+
value: `${decodeResult.raw.outside_air_temperature} degrees`
|
|
270
528
|
});
|
|
271
529
|
}
|
|
272
530
|
static heading(decodeResult, value) {
|
|
@@ -278,14 +536,77 @@ var ResultFormatter = class {
|
|
|
278
536
|
value: `${decodeResult.raw.heading}`
|
|
279
537
|
});
|
|
280
538
|
}
|
|
539
|
+
static tail(decodeResult, value) {
|
|
540
|
+
decodeResult.raw.tail = value;
|
|
541
|
+
decodeResult.formatted.items.push({
|
|
542
|
+
type: "tail",
|
|
543
|
+
code: "TAIL",
|
|
544
|
+
label: "Tail",
|
|
545
|
+
value: decodeResult.raw.tail
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
static out(decodeResult, time) {
|
|
549
|
+
decodeResult.raw.out_time = time;
|
|
550
|
+
decodeResult.formatted.items.push({
|
|
551
|
+
type: "time_of_day",
|
|
552
|
+
code: "OUT",
|
|
553
|
+
label: "Out of Gate Time",
|
|
554
|
+
value: DateTimeUtils.timestampToString(time, "tod")
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
static off(decodeResult, time) {
|
|
558
|
+
decodeResult.raw.off_time = time;
|
|
559
|
+
decodeResult.formatted.items.push({
|
|
560
|
+
type: "time_of_day",
|
|
561
|
+
code: "OFF",
|
|
562
|
+
label: "Takeoff Time",
|
|
563
|
+
value: DateTimeUtils.timestampToString(time, "tod")
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
static on(decodeResult, time) {
|
|
567
|
+
decodeResult.raw.on_time = time;
|
|
568
|
+
decodeResult.formatted.items.push({
|
|
569
|
+
type: "time_of_day",
|
|
570
|
+
code: "ON",
|
|
571
|
+
label: "Landing Time",
|
|
572
|
+
value: DateTimeUtils.timestampToString(time, "tod")
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
static in(decodeResult, time) {
|
|
576
|
+
decodeResult.raw.in_time = time;
|
|
577
|
+
decodeResult.formatted.items.push({
|
|
578
|
+
type: "time_of_day",
|
|
579
|
+
code: "IN",
|
|
580
|
+
label: "In Gate Time",
|
|
581
|
+
value: DateTimeUtils.timestampToString(time, "tod")
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
static time_of_day(decodeResult, time) {
|
|
585
|
+
decodeResult.raw.time_of_day = time;
|
|
586
|
+
decodeResult.formatted.items.push({
|
|
587
|
+
type: "time_of_day",
|
|
588
|
+
code: "MSG_TOD",
|
|
589
|
+
label: "Message Timestamp",
|
|
590
|
+
value: DateTimeUtils.timestampToString(time, "tod")
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
static text(decodeResult, text2) {
|
|
594
|
+
decodeResult.raw.text = text2;
|
|
595
|
+
decodeResult.formatted.items.push({
|
|
596
|
+
type: "text",
|
|
597
|
+
code: "TEXT",
|
|
598
|
+
label: "Text Message",
|
|
599
|
+
value: text2
|
|
600
|
+
});
|
|
601
|
+
}
|
|
281
602
|
static unknown(decodeResult, value) {
|
|
282
603
|
decodeResult.remaining.text += "," + value;
|
|
283
604
|
}
|
|
284
605
|
};
|
|
285
606
|
|
|
286
|
-
// lib/plugins/
|
|
287
|
-
var
|
|
288
|
-
name = "label-5z";
|
|
607
|
+
// lib/plugins/Label_5Z_Slash.ts
|
|
608
|
+
var Label_5Z_Slash = class extends DecoderPlugin {
|
|
609
|
+
name = "label-5z-slash";
|
|
289
610
|
descriptions = {
|
|
290
611
|
B1: "Request Weight and Balance",
|
|
291
612
|
B3: "Request Departure Clearance",
|
|
@@ -303,6 +624,7 @@ var Label_5Z = class extends DecoderPlugin {
|
|
|
303
624
|
D6: "From-To + Date",
|
|
304
625
|
D7: "From-To + Alternate + Time",
|
|
305
626
|
EO: "In Range",
|
|
627
|
+
ET: "Expected Time",
|
|
306
628
|
PW: "Position Weather",
|
|
307
629
|
RL: "Request Release",
|
|
308
630
|
R3: "Request HOWGOZIT Message",
|
|
@@ -313,48 +635,82 @@ var Label_5Z = class extends DecoderPlugin {
|
|
|
313
635
|
};
|
|
314
636
|
qualifiers() {
|
|
315
637
|
return {
|
|
316
|
-
labels: ["5Z"]
|
|
638
|
+
labels: ["5Z"],
|
|
639
|
+
preambles: ["/"]
|
|
317
640
|
};
|
|
318
641
|
}
|
|
319
642
|
decode(message, options = {}) {
|
|
320
643
|
const decodeResult = this.defaultResult();
|
|
321
644
|
decodeResult.decoder.name = this.name;
|
|
322
645
|
decodeResult.formatted.description = "Airline Designated Downlink";
|
|
323
|
-
const
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
646
|
+
const lines = message.text.split("\r\n");
|
|
647
|
+
if (lines[0] === "/TXT") {
|
|
648
|
+
ResultFormatter.text(decodeResult, lines.slice(1).join("\r\n"));
|
|
649
|
+
decodeResult.decoded = true;
|
|
650
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
651
|
+
return decodeResult;
|
|
652
|
+
}
|
|
653
|
+
const data = lines[0].split("/");
|
|
654
|
+
const header = data[1].split(" ");
|
|
655
|
+
const type = header[0];
|
|
656
|
+
const typeDescription = this.descriptions[type];
|
|
657
|
+
if (typeDescription) {
|
|
329
658
|
decodeResult.raw.airline = "United Airlines";
|
|
330
659
|
decodeResult.formatted.items.push({
|
|
331
660
|
type: "airline",
|
|
661
|
+
code: "AIRLINE",
|
|
332
662
|
label: "Airline",
|
|
333
663
|
value: "United Airlines"
|
|
334
664
|
});
|
|
335
665
|
decodeResult.raw.message_type = type;
|
|
336
666
|
decodeResult.formatted.items.push({
|
|
337
667
|
type: "message_type",
|
|
668
|
+
code: "MSG_TYPE",
|
|
338
669
|
label: "Message Type",
|
|
339
670
|
value: `${typeDescription} (${type})`
|
|
340
671
|
});
|
|
341
|
-
if (type === "B3") {
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
672
|
+
if (type === "B3" && data[1] === "B3 TO DATA REQ ") {
|
|
673
|
+
const info = data[2].split(" ");
|
|
674
|
+
ResultFormatter.departureAirport(decodeResult, info[1]);
|
|
675
|
+
ResultFormatter.arrivalAirport(decodeResult, info[2]);
|
|
676
|
+
decodeResult.raw.day_of_month = Number(info[3]);
|
|
677
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
|
|
678
|
+
ResultFormatter.arrivalRunway(decodeResult, info[5].slice(1));
|
|
679
|
+
decodeResult.remaining.text = data.slice(3).join("/");
|
|
680
|
+
} else if (type === "B3") {
|
|
681
|
+
ResultFormatter.departureAirport(decodeResult, header[1].substring(0, 3), "IATA");
|
|
682
|
+
ResultFormatter.arrivalAirport(decodeResult, header[1].substring(3), "IATA");
|
|
683
|
+
decodeResult.raw.day_of_month = Number(header[2]);
|
|
684
|
+
ResultFormatter.arrivalRunway(decodeResult, header[3].slice(1));
|
|
685
|
+
if (header.length > 4) {
|
|
686
|
+
decodeResult.remaining.text = header.slice(4).join(" ");
|
|
352
687
|
}
|
|
688
|
+
} else if (type === "C3" && data[1] === "C3 GATE REQ ") {
|
|
689
|
+
const info = data[2].split(" ");
|
|
690
|
+
ResultFormatter.departureAirport(decodeResult, info[1]);
|
|
691
|
+
ResultFormatter.arrivalAirport(decodeResult, info[2]);
|
|
692
|
+
decodeResult.raw.day_of_month = Number(info[3]);
|
|
693
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
|
|
694
|
+
decodeResult.remaining.text = info.slice(5).join(" ");
|
|
695
|
+
} else if (type === "C3") {
|
|
696
|
+
ResultFormatter.departureAirport(decodeResult, header[1].substring(0, 3), "IATA");
|
|
697
|
+
ResultFormatter.arrivalAirport(decodeResult, header[1].substring(3), "IATA");
|
|
698
|
+
} else if (type === "ET") {
|
|
699
|
+
const airports = data[2].split(" ");
|
|
700
|
+
ResultFormatter.departureAirport(decodeResult, airports[1]);
|
|
701
|
+
ResultFormatter.arrivalAirport(decodeResult, airports[2]);
|
|
702
|
+
decodeResult.raw.day_of_month = Number(airports[3]);
|
|
703
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(airports[4]));
|
|
704
|
+
const estimates = data[3].split(" ");
|
|
705
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(estimates[1] + "00"));
|
|
706
|
+
decodeResult.remaining.text = estimates[2];
|
|
353
707
|
} else {
|
|
354
|
-
|
|
708
|
+
if (options.debug) {
|
|
709
|
+
console.log(`Decoder: Unkown 5Z RDC format: ${message.text}`);
|
|
710
|
+
}
|
|
355
711
|
}
|
|
356
712
|
decodeResult.decoded = true;
|
|
357
|
-
decodeResult.decoder.decodeLevel = "partial";
|
|
713
|
+
decodeResult.decoder.decodeLevel = decodeResult.remaining.text ? "partial" : "full";
|
|
358
714
|
} else {
|
|
359
715
|
if (options.debug) {
|
|
360
716
|
console.log(`Decoder: Unknown 5Z message: ${message.text}`);
|
|
@@ -384,7 +740,7 @@ var Label_10_LDR = class extends DecoderPlugin {
|
|
|
384
740
|
decodeResult.message = message;
|
|
385
741
|
const parts = message.text.split(",");
|
|
386
742
|
if (parts.length < 17) {
|
|
387
|
-
if (options
|
|
743
|
+
if (options.debug) {
|
|
388
744
|
console.log(`Decoder: Unknown 10 message: ${message.text}`);
|
|
389
745
|
}
|
|
390
746
|
decodeResult.remaining.text = message.text;
|
|
@@ -402,8 +758,13 @@ var Label_10_LDR = class extends DecoderPlugin {
|
|
|
402
758
|
ResultFormatter.altitude(decodeResult, Number(parts[7]));
|
|
403
759
|
ResultFormatter.departureAirport(decodeResult, parts[9]);
|
|
404
760
|
ResultFormatter.arrivalAirport(decodeResult, parts[10]);
|
|
761
|
+
ResultFormatter.alternateAirport(decodeResult, parts[11]);
|
|
405
762
|
ResultFormatter.arrivalRunway(decodeResult, parts[12].split("/")[0]);
|
|
406
|
-
|
|
763
|
+
const altRwy = [parts[13].split("/")[0], parts[14].split("/")[0]].filter((r) => r != "").join(",");
|
|
764
|
+
if (altRwy != "") {
|
|
765
|
+
ResultFormatter.alternateRunway(decodeResult, altRwy);
|
|
766
|
+
}
|
|
767
|
+
decodeResult.remaining.text = [...parts.slice(0, 5), ...parts.slice(15)].join(",");
|
|
407
768
|
decodeResult.decoded = true;
|
|
408
769
|
decodeResult.decoder.decodeLevel = "partial";
|
|
409
770
|
return decodeResult;
|
|
@@ -427,7 +788,7 @@ var Label_10_POS = class extends DecoderPlugin {
|
|
|
427
788
|
decodeResult.message = message;
|
|
428
789
|
const parts = message.text.split(",");
|
|
429
790
|
if (parts.length !== 12) {
|
|
430
|
-
if (options
|
|
791
|
+
if (options.debug) {
|
|
431
792
|
console.log(`Decoder: Unknown 10 message: ${message.text}`);
|
|
432
793
|
}
|
|
433
794
|
decodeResult.remaining.text = message.text;
|
|
@@ -450,153 +811,30 @@ var Label_10_POS = class extends DecoderPlugin {
|
|
|
450
811
|
}
|
|
451
812
|
};
|
|
452
813
|
|
|
453
|
-
// lib/
|
|
454
|
-
var
|
|
455
|
-
//
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
814
|
+
// lib/plugins/Label_10_Slash.ts
|
|
815
|
+
var Label_10_Slash = class extends DecoderPlugin {
|
|
816
|
+
// eslint-disable-line camelcase
|
|
817
|
+
name = "label-10-slash";
|
|
818
|
+
qualifiers() {
|
|
819
|
+
return {
|
|
820
|
+
labels: ["10"],
|
|
821
|
+
preambles: ["/"]
|
|
822
|
+
};
|
|
460
823
|
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
if (
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
return utcDate.toUTCString();
|
|
476
|
-
}
|
|
477
|
-
/**
|
|
478
|
-
*
|
|
479
|
-
* @param time HHMMSS
|
|
480
|
-
* @returns seconds since midnight
|
|
481
|
-
*/
|
|
482
|
-
static convertHHMMSSToTod(time) {
|
|
483
|
-
const h = Number(time.substring(0, 2));
|
|
484
|
-
const m = Number(time.substring(2, 4));
|
|
485
|
-
const s = Number(time.substring(4, 6));
|
|
486
|
-
const tod = h * 3600 + m * 60 + s;
|
|
487
|
-
return tod;
|
|
488
|
-
}
|
|
489
|
-
/**
|
|
490
|
-
*
|
|
491
|
-
* @param time HHMMSS
|
|
492
|
-
* @param date MMDDYY or MMDDYYYY
|
|
493
|
-
* @returns seconds since epoch
|
|
494
|
-
*/
|
|
495
|
-
static convertDateTimeToEpoch(time, date) {
|
|
496
|
-
if (date.length === 6) {
|
|
497
|
-
date = date.substring(0, 4) + `20${date.substring(4, 6)}`;
|
|
498
|
-
}
|
|
499
|
-
const timestamp = `${date.substring(4, 8)}-${date.substring(0, 2)}-${date.substring(2, 4)}T${time.substring(0, 2)}:${time.substring(2, 4)}:${time.substring(4, 6)}.000Z`;
|
|
500
|
-
const millis = Date.parse(timestamp);
|
|
501
|
-
return millis / 1e3;
|
|
502
|
-
}
|
|
503
|
-
};
|
|
504
|
-
|
|
505
|
-
// lib/utils/route_utils.ts
|
|
506
|
-
var RouteUtils = class _RouteUtils {
|
|
507
|
-
static routeToString(route) {
|
|
508
|
-
let str = "";
|
|
509
|
-
if (route.name) {
|
|
510
|
-
str += route.name;
|
|
511
|
-
}
|
|
512
|
-
if (route.runway) {
|
|
513
|
-
str += `(${route.runway})`;
|
|
514
|
-
}
|
|
515
|
-
if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
|
|
516
|
-
str += " starting at ";
|
|
517
|
-
} else if (str.length !== 0 && route.waypoints) {
|
|
518
|
-
str += ": ";
|
|
519
|
-
}
|
|
520
|
-
if (route.waypoints) {
|
|
521
|
-
str += _RouteUtils.waypointsToString(route.waypoints);
|
|
522
|
-
}
|
|
523
|
-
return str;
|
|
524
|
-
}
|
|
525
|
-
static waypointToString(waypoint) {
|
|
526
|
-
let s = waypoint.name;
|
|
527
|
-
if (waypoint.latitude && waypoint.longitude) {
|
|
528
|
-
s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
|
|
529
|
-
}
|
|
530
|
-
if (waypoint.offset) {
|
|
531
|
-
s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
|
|
532
|
-
}
|
|
533
|
-
if (waypoint.time && waypoint.timeFormat) {
|
|
534
|
-
s += `@${_RouteUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
|
|
535
|
-
}
|
|
536
|
-
return s;
|
|
537
|
-
}
|
|
538
|
-
static getWaypoint(leg) {
|
|
539
|
-
const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
|
|
540
|
-
if (regex?.length == 4) {
|
|
541
|
-
return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
|
|
542
|
-
}
|
|
543
|
-
const waypoint = leg.split(",");
|
|
544
|
-
if (waypoint.length == 2) {
|
|
545
|
-
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
|
|
546
|
-
if (position) {
|
|
547
|
-
return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
if (leg.length == 13 || leg.length == 14) {
|
|
551
|
-
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
|
|
552
|
-
const name = waypoint.length == 2 ? waypoint[0] : "";
|
|
553
|
-
if (position) {
|
|
554
|
-
return { name, latitude: position.latitude, longitude: position.longitude };
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
return { name: leg };
|
|
558
|
-
}
|
|
559
|
-
// move out if we want public
|
|
560
|
-
static timestampToString(time, format) {
|
|
561
|
-
const date = new Date(time * 1e3);
|
|
562
|
-
if (format == "tod") {
|
|
563
|
-
return date.toISOString().slice(11, 19);
|
|
564
|
-
}
|
|
565
|
-
return date.toISOString().slice(0, -5) + "Z";
|
|
566
|
-
}
|
|
567
|
-
static waypointsToString(waypoints) {
|
|
568
|
-
let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
|
|
569
|
-
if (str.startsWith(" > ")) {
|
|
570
|
-
str = ">>" + str.slice(2);
|
|
571
|
-
}
|
|
572
|
-
return str;
|
|
573
|
-
}
|
|
574
|
-
};
|
|
575
|
-
|
|
576
|
-
// lib/plugins/Label_10_Slash.ts
|
|
577
|
-
var Label_10_Slash = class extends DecoderPlugin {
|
|
578
|
-
// eslint-disable-line camelcase
|
|
579
|
-
name = "label-10-slash";
|
|
580
|
-
qualifiers() {
|
|
581
|
-
return {
|
|
582
|
-
labels: ["10"],
|
|
583
|
-
preambles: ["/"]
|
|
584
|
-
};
|
|
585
|
-
}
|
|
586
|
-
decode(message, options = {}) {
|
|
587
|
-
const decodeResult = this.defaultResult();
|
|
588
|
-
decodeResult.decoder.name = this.name;
|
|
589
|
-
decodeResult.formatted.description = "Position Report";
|
|
590
|
-
decodeResult.message = message;
|
|
591
|
-
const parts = message.text.split("/");
|
|
592
|
-
if (parts.length < 17) {
|
|
593
|
-
if (options?.debug) {
|
|
594
|
-
console.log(`Decoder: Unknown 10 message: ${message.text}`);
|
|
595
|
-
}
|
|
596
|
-
decodeResult.remaining.text = message.text;
|
|
597
|
-
decodeResult.decoded = false;
|
|
598
|
-
decodeResult.decoder.decodeLevel = "none";
|
|
599
|
-
return decodeResult;
|
|
824
|
+
decode(message, options = {}) {
|
|
825
|
+
const decodeResult = this.defaultResult();
|
|
826
|
+
decodeResult.decoder.name = this.name;
|
|
827
|
+
decodeResult.formatted.description = "Position Report";
|
|
828
|
+
decodeResult.message = message;
|
|
829
|
+
const parts = message.text.split("/");
|
|
830
|
+
if (parts.length < 17) {
|
|
831
|
+
if (options.debug) {
|
|
832
|
+
console.log(`Decoder: Unknown 10 message: ${message.text}`);
|
|
833
|
+
}
|
|
834
|
+
decodeResult.remaining.text = message.text;
|
|
835
|
+
decodeResult.decoded = false;
|
|
836
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
837
|
+
return decodeResult;
|
|
600
838
|
}
|
|
601
839
|
const lat = parts[1];
|
|
602
840
|
const lon = parts[2];
|
|
@@ -608,7 +846,7 @@ var Label_10_Slash = class extends DecoderPlugin {
|
|
|
608
846
|
ResultFormatter.heading(decodeResult, Number(parts[5]));
|
|
609
847
|
ResultFormatter.altitude(decodeResult, 100 * Number(parts[6]));
|
|
610
848
|
ResultFormatter.arrivalAirport(decodeResult, parts[7]);
|
|
611
|
-
ResultFormatter.eta(decodeResult, parts[8] + "00");
|
|
849
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[8] + "00"));
|
|
612
850
|
const waypoints = [{
|
|
613
851
|
name: parts[11]
|
|
614
852
|
}, {
|
|
@@ -685,6 +923,97 @@ var Label_12_N_Space = class extends DecoderPlugin {
|
|
|
685
923
|
}
|
|
686
924
|
};
|
|
687
925
|
|
|
926
|
+
// lib/plugins/Label_13Through18_Slash.ts
|
|
927
|
+
var Label_13Through18_Slash = class extends DecoderPlugin {
|
|
928
|
+
// eslint-disable-line camelcase
|
|
929
|
+
name = "label-13-18-slash";
|
|
930
|
+
qualifiers() {
|
|
931
|
+
return {
|
|
932
|
+
labels: ["13", "14", "15", "16", "17", "18"],
|
|
933
|
+
preambles: ["/"]
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
decode(message, options = {}) {
|
|
937
|
+
const decodeResult = this.defaultResult();
|
|
938
|
+
decodeResult.decoder.name = this.name;
|
|
939
|
+
decodeResult.message = message;
|
|
940
|
+
const lines = message.text.split("\r\n");
|
|
941
|
+
const parts = lines[0].split("/");
|
|
942
|
+
const labelNumber = Number(parts[1].substring(0, 2));
|
|
943
|
+
decodeResult.formatted.description = getMsgType(labelNumber);
|
|
944
|
+
if (labelNumber !== 18 && parts.length !== 4 || labelNumber === 18 && parts.length !== 7) {
|
|
945
|
+
if (options?.debug) {
|
|
946
|
+
console.log(`Decoder: Unknown OOOI message: ${message.text}`);
|
|
947
|
+
}
|
|
948
|
+
decodeResult.remaining.text = message.text;
|
|
949
|
+
decodeResult.decoded = false;
|
|
950
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
951
|
+
return decodeResult;
|
|
952
|
+
}
|
|
953
|
+
decodeResult.remaining.text = "";
|
|
954
|
+
const data = parts[2].split(" ");
|
|
955
|
+
ResultFormatter.departureAirport(decodeResult, data[1]);
|
|
956
|
+
ResultFormatter.arrivalAirport(decodeResult, data[2]);
|
|
957
|
+
decodeResult.raw.day_of_month = Number(data[3]);
|
|
958
|
+
const time = DateTimeUtils.convertHHMMSSToTod(data[4]);
|
|
959
|
+
if (labelNumber === 13) {
|
|
960
|
+
ResultFormatter.out(decodeResult, time);
|
|
961
|
+
} else if (labelNumber === 14) {
|
|
962
|
+
ResultFormatter.off(decodeResult, time);
|
|
963
|
+
} else if (labelNumber === 15) {
|
|
964
|
+
ResultFormatter.on(decodeResult, time);
|
|
965
|
+
} else if (labelNumber === 16) {
|
|
966
|
+
ResultFormatter.in(decodeResult, time);
|
|
967
|
+
}
|
|
968
|
+
if (parts.length === 7) {
|
|
969
|
+
decodeResult.remaining.text += parts.slice(4).join("/");
|
|
970
|
+
}
|
|
971
|
+
for (let i = 1; i < lines.length; i++) {
|
|
972
|
+
if (lines[i].startsWith("/LOC")) {
|
|
973
|
+
const location = lines[i].substring(5).split(",");
|
|
974
|
+
let position;
|
|
975
|
+
if (location[0].startsWith("+") || location[0].startsWith("-")) {
|
|
976
|
+
position = { latitude: Number(location[0]), longitude: Number(location[1]) };
|
|
977
|
+
} else {
|
|
978
|
+
position = {
|
|
979
|
+
latitude: CoordinateUtils.getDirection(location[0][0]) * CoordinateUtils.dmsToDecimalDegrees(Number(location[0].substring(1, 3)), Number(location[0].substring(3, 5)), Number(location[0].substring(5, 7))),
|
|
980
|
+
longitude: CoordinateUtils.getDirection(location[1][0]) * CoordinateUtils.dmsToDecimalDegrees(Number(location[1].substring(1, 4)), Number(location[1].substring(4, 6)), Number(location[1].substring(6, 8)))
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
if (!isNaN(position.latitude) && !isNaN(position.longitude)) {
|
|
984
|
+
ResultFormatter.position(decodeResult, position);
|
|
985
|
+
}
|
|
986
|
+
} else {
|
|
987
|
+
decodeResult.remaining.text += "\r\n" + lines[i];
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
decodeResult.decoded = true;
|
|
991
|
+
decodeResult.decoder.decodeLevel = decodeResult.remaining.text ? "partial" : "full";
|
|
992
|
+
return decodeResult;
|
|
993
|
+
}
|
|
994
|
+
};
|
|
995
|
+
function getMsgType(labelNumber) {
|
|
996
|
+
if (labelNumber === 13) {
|
|
997
|
+
return "Out of Gate Report";
|
|
998
|
+
}
|
|
999
|
+
if (labelNumber === 14) {
|
|
1000
|
+
return "Takeoff Report";
|
|
1001
|
+
}
|
|
1002
|
+
if (labelNumber === 15) {
|
|
1003
|
+
return "On Ground Report";
|
|
1004
|
+
}
|
|
1005
|
+
if (labelNumber === 16) {
|
|
1006
|
+
return "In Gate Report";
|
|
1007
|
+
}
|
|
1008
|
+
if (labelNumber === 17) {
|
|
1009
|
+
return "Post Report";
|
|
1010
|
+
}
|
|
1011
|
+
if (labelNumber === 18) {
|
|
1012
|
+
return "Post Times Report";
|
|
1013
|
+
}
|
|
1014
|
+
return "Unknown";
|
|
1015
|
+
}
|
|
1016
|
+
|
|
688
1017
|
// lib/plugins/Label_15.ts
|
|
689
1018
|
var Label_15 = class extends DecoderPlugin {
|
|
690
1019
|
name = "label-5z";
|
|
@@ -851,28 +1180,12 @@ var Label_1M_Slash = class extends DecoderPlugin {
|
|
|
851
1180
|
console.log(results);
|
|
852
1181
|
}
|
|
853
1182
|
decodeResult.raw.flight_number = results[0];
|
|
854
|
-
decodeResult
|
|
855
|
-
decodeResult
|
|
856
|
-
decodeResult
|
|
857
|
-
decodeResult
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
code: "ETA",
|
|
861
|
-
label: "Estimated Time of Arrival",
|
|
862
|
-
value: DateTimeUtils.UTCDateTimeToString(results[2], results[7])
|
|
863
|
-
});
|
|
864
|
-
decodeResult.formatted.items.push({
|
|
865
|
-
type: "destination",
|
|
866
|
-
code: "DST",
|
|
867
|
-
label: "Destination",
|
|
868
|
-
value: decodeResult.raw.arrival_icao
|
|
869
|
-
});
|
|
870
|
-
decodeResult.formatted.items.push({
|
|
871
|
-
type: "origin",
|
|
872
|
-
code: "ORG",
|
|
873
|
-
label: "Origin",
|
|
874
|
-
value: decodeResult.raw.departure_icao
|
|
875
|
-
});
|
|
1183
|
+
ResultFormatter.departureAirport(decodeResult, results[3]);
|
|
1184
|
+
ResultFormatter.arrivalAirport(decodeResult, results[4]);
|
|
1185
|
+
ResultFormatter.alternateAirport(decodeResult, results[5]);
|
|
1186
|
+
ResultFormatter.arrivalRunway(decodeResult, results[8].replace(results[4], ""));
|
|
1187
|
+
const yymmdd = results[2];
|
|
1188
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertDateTimeToEpoch(results[7] + "00", yymmdd.substring(2, 4) + yymmdd.substring(4, 6) + yymmdd.substring(0, 2)), "epoch");
|
|
876
1189
|
}
|
|
877
1190
|
decodeResult.decoded = true;
|
|
878
1191
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -896,11 +1209,11 @@ var Label_20_POS = class extends DecoderPlugin {
|
|
|
896
1209
|
decodeResult.message = message;
|
|
897
1210
|
decodeResult.raw.preamble = message.text.substring(0, 3);
|
|
898
1211
|
const content = message.text.substring(3);
|
|
899
|
-
console.log("Content: " + content);
|
|
900
1212
|
const fields = content.split(",");
|
|
901
|
-
console.log("Field Count: " + fields.length);
|
|
902
1213
|
if (fields.length == 11) {
|
|
903
|
-
|
|
1214
|
+
if (options.debug) {
|
|
1215
|
+
console.log(`DEBUG: ${this.name}: Variation 1 detected`);
|
|
1216
|
+
}
|
|
904
1217
|
const rawCoords = fields[0];
|
|
905
1218
|
decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
|
|
906
1219
|
if (decodeResult.raw.position) {
|
|
@@ -914,7 +1227,9 @@ var Label_20_POS = class extends DecoderPlugin {
|
|
|
914
1227
|
decodeResult.decoded = true;
|
|
915
1228
|
decodeResult.decoder.decodeLevel = "full";
|
|
916
1229
|
} else if (fields.length == 5) {
|
|
917
|
-
|
|
1230
|
+
if (options.debug) {
|
|
1231
|
+
console.log(`DEBUG: ${this.name}: Variation 2 detected`);
|
|
1232
|
+
}
|
|
918
1233
|
const rawCoords = fields[0];
|
|
919
1234
|
decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
|
|
920
1235
|
if (decodeResult.raw.position) {
|
|
@@ -928,7 +1243,9 @@ var Label_20_POS = class extends DecoderPlugin {
|
|
|
928
1243
|
decodeResult.decoded = true;
|
|
929
1244
|
decodeResult.decoder.decodeLevel = "full";
|
|
930
1245
|
} else {
|
|
931
|
-
|
|
1246
|
+
if (options.debug) {
|
|
1247
|
+
console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
|
|
1248
|
+
}
|
|
932
1249
|
decodeResult.decoded = false;
|
|
933
1250
|
decodeResult.decoder.decodeLevel = "none";
|
|
934
1251
|
}
|
|
@@ -952,25 +1269,25 @@ var Label_21_POS = class extends DecoderPlugin {
|
|
|
952
1269
|
decodeResult.message = message;
|
|
953
1270
|
decodeResult.raw.preamble = message.text.substring(0, 3);
|
|
954
1271
|
const content = message.text.substring(3);
|
|
955
|
-
console.log("Content: " + content);
|
|
956
1272
|
const fields = content.split(",");
|
|
957
|
-
console.log("Field Count: " + fields.length);
|
|
958
1273
|
if (fields.length == 9) {
|
|
959
1274
|
processPosition(decodeResult, fields[0].trim());
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1275
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2]));
|
|
1276
|
+
ResultFormatter.altitude(decodeResult, Number(fields[3]));
|
|
1277
|
+
ResultFormatter.temperature(decodeResult, fields[6].replace(/ /g, ""));
|
|
1278
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[7]));
|
|
1279
|
+
ResultFormatter.arrivalAirport(decodeResult, fields[8]);
|
|
963
1280
|
decodeResult.remaining.text = [
|
|
964
1281
|
fields[1],
|
|
965
|
-
fields[2],
|
|
966
1282
|
fields[4],
|
|
967
|
-
fields[5]
|
|
968
|
-
fields[7]
|
|
1283
|
+
fields[5]
|
|
969
1284
|
].join(",");
|
|
970
1285
|
decodeResult.decoded = true;
|
|
971
1286
|
decodeResult.decoder.decodeLevel = "partial";
|
|
972
1287
|
} else {
|
|
973
|
-
|
|
1288
|
+
if (options.debug) {
|
|
1289
|
+
console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
|
|
1290
|
+
}
|
|
974
1291
|
decodeResult.decoded = false;
|
|
975
1292
|
decodeResult.decoder.decodeLevel = "none";
|
|
976
1293
|
}
|
|
@@ -979,7 +1296,7 @@ var Label_21_POS = class extends DecoderPlugin {
|
|
|
979
1296
|
};
|
|
980
1297
|
function processPosition(decodeResult, value) {
|
|
981
1298
|
if (value.length !== 16 && value[0] !== "N" && value[0] !== "S" && value[8] !== "W" && value[8] !== "E") {
|
|
982
|
-
return
|
|
1299
|
+
return;
|
|
983
1300
|
}
|
|
984
1301
|
const latDir = value[0] === "N" ? 1 : -1;
|
|
985
1302
|
const lonDir = value[8] === "E" ? 1 : -1;
|
|
@@ -987,45 +1304,52 @@ function processPosition(decodeResult, value) {
|
|
|
987
1304
|
latitude: latDir * Number(value.substring(1, 7)),
|
|
988
1305
|
longitude: lonDir * Number(value.substring(9, 15))
|
|
989
1306
|
};
|
|
990
|
-
|
|
991
|
-
decodeResult.raw.position = position;
|
|
992
|
-
decodeResult.formatted.items.push({
|
|
993
|
-
type: "aircraft_position",
|
|
994
|
-
code: "POS",
|
|
995
|
-
label: "Aircraft Position",
|
|
996
|
-
value: CoordinateUtils.coordinateString(position)
|
|
997
|
-
});
|
|
998
|
-
}
|
|
999
|
-
return !!position;
|
|
1000
|
-
}
|
|
1001
|
-
function processAlt(decodeResult, value) {
|
|
1002
|
-
decodeResult.raw.altitude = Number(value);
|
|
1003
|
-
decodeResult.formatted.items.push({
|
|
1004
|
-
type: "altitude",
|
|
1005
|
-
code: "ALT",
|
|
1006
|
-
label: "Altitude",
|
|
1007
|
-
value: `${decodeResult.raw.altitude} feet`
|
|
1008
|
-
});
|
|
1009
|
-
}
|
|
1010
|
-
function processTemp(decodeResult, value) {
|
|
1011
|
-
decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
|
|
1012
|
-
decodeResult.formatted.items.push({
|
|
1013
|
-
type: "outside_air_temperature",
|
|
1014
|
-
code: "OATEMP",
|
|
1015
|
-
label: "Outside Air Temperature (C)",
|
|
1016
|
-
value: `${decodeResult.raw.outside_air_temperature}`
|
|
1017
|
-
});
|
|
1018
|
-
}
|
|
1019
|
-
function processArrvApt(decodeResult, value) {
|
|
1020
|
-
decodeResult.raw.arrival_icao = value;
|
|
1021
|
-
decodeResult.formatted.items.push({
|
|
1022
|
-
type: "destination",
|
|
1023
|
-
code: "DST",
|
|
1024
|
-
label: "Destination",
|
|
1025
|
-
value: decodeResult.raw.arrival_icao
|
|
1026
|
-
});
|
|
1307
|
+
ResultFormatter.position(decodeResult, position);
|
|
1027
1308
|
}
|
|
1028
1309
|
|
|
1310
|
+
// lib/plugins/Label_24_Slash.ts
|
|
1311
|
+
var Label_24_Slash = class extends DecoderPlugin {
|
|
1312
|
+
name = "label-24-slash";
|
|
1313
|
+
qualifiers() {
|
|
1314
|
+
return {
|
|
1315
|
+
labels: ["24"],
|
|
1316
|
+
preambles: ["/"]
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
decode(message, options = {}) {
|
|
1320
|
+
const decodeResult = this.defaultResult();
|
|
1321
|
+
decodeResult.decoder.name = this.name;
|
|
1322
|
+
decodeResult.formatted.description = "Position Report";
|
|
1323
|
+
decodeResult.message = message;
|
|
1324
|
+
const fields = message.text.split("/");
|
|
1325
|
+
if (fields.length == 10 && fields[0] == "" && fields[9] == "") {
|
|
1326
|
+
const mmddyy = fields[1].substring(4, 6) + fields[1].substring(2, 4) + fields[1].substring(0, 2);
|
|
1327
|
+
const hhmmss = fields[2] + "00";
|
|
1328
|
+
decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(hhmmss, mmddyy);
|
|
1329
|
+
ResultFormatter.flightNumber(decodeResult, fields[3]);
|
|
1330
|
+
ResultFormatter.altitude(decodeResult, Number(fields[4]));
|
|
1331
|
+
const lat = fields[5];
|
|
1332
|
+
const lon = fields[6];
|
|
1333
|
+
const position = {
|
|
1334
|
+
latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1)),
|
|
1335
|
+
longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1))
|
|
1336
|
+
};
|
|
1337
|
+
ResultFormatter.position(decodeResult, position);
|
|
1338
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[8] + "00"));
|
|
1339
|
+
decodeResult.remaining.text = fields[7];
|
|
1340
|
+
decodeResult.decoded = true;
|
|
1341
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1342
|
+
} else {
|
|
1343
|
+
if (options.debug) {
|
|
1344
|
+
console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}. Message: ${message.text}`);
|
|
1345
|
+
}
|
|
1346
|
+
decodeResult.decoded = false;
|
|
1347
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1348
|
+
}
|
|
1349
|
+
return decodeResult;
|
|
1350
|
+
}
|
|
1351
|
+
};
|
|
1352
|
+
|
|
1029
1353
|
// lib/plugins/Label_30_Slash_EA.ts
|
|
1030
1354
|
var Label_30_Slash_EA = class extends DecoderPlugin {
|
|
1031
1355
|
name = "label-30-slash-ea";
|
|
@@ -1047,20 +1371,9 @@ var Label_30_Slash_EA = class extends DecoderPlugin {
|
|
|
1047
1371
|
console.log(results);
|
|
1048
1372
|
}
|
|
1049
1373
|
}
|
|
1050
|
-
decodeResult.
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
label: "Estimated Time of Arrival",
|
|
1054
|
-
value: DateTimeUtils.UTCToString(results[0].substr(2, 4))
|
|
1055
|
-
});
|
|
1056
|
-
if (results[1].substr(0, 2) === "DS") {
|
|
1057
|
-
decodeResult.raw.arrival_icao = results[1].substr(2, 4);
|
|
1058
|
-
decodeResult.formatted.items.push({
|
|
1059
|
-
type: "destination",
|
|
1060
|
-
code: "DST",
|
|
1061
|
-
label: "Destination",
|
|
1062
|
-
value: decodeResult.raw.arrival_icao
|
|
1063
|
-
});
|
|
1374
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results[0].substr(2, 4) + "00"));
|
|
1375
|
+
if (results[1].substring(0, 2) === "DS") {
|
|
1376
|
+
ResultFormatter.arrivalAirport(decodeResult, results[1].substring(2, 6));
|
|
1064
1377
|
decodeResult.remaining.text = "/".concat(results[2]);
|
|
1065
1378
|
} else {
|
|
1066
1379
|
decodeResult.remaining.text = "/".concat(results[1], "/", results[2]);
|
|
@@ -1352,23 +1665,296 @@ var Label_44_POS = class extends DecoderPlugin {
|
|
|
1352
1665
|
}
|
|
1353
1666
|
};
|
|
1354
1667
|
|
|
1355
|
-
// lib/plugins/
|
|
1356
|
-
var
|
|
1357
|
-
name = "label-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1668
|
+
// lib/plugins/Label_4A.ts
|
|
1669
|
+
var Label_4A = class extends DecoderPlugin {
|
|
1670
|
+
name = "label-4a";
|
|
1671
|
+
qualifiers() {
|
|
1672
|
+
return {
|
|
1673
|
+
labels: ["4A"]
|
|
1674
|
+
};
|
|
1675
|
+
}
|
|
1676
|
+
decode(message, options = {}) {
|
|
1677
|
+
const decodeResult = this.defaultResult();
|
|
1678
|
+
decodeResult.decoder.name = this.name;
|
|
1679
|
+
decodeResult.message = message;
|
|
1680
|
+
decodeResult.formatted.description = "Latest New Format";
|
|
1681
|
+
let text2 = message.text;
|
|
1682
|
+
if (text2.match(/^M\d{2}A\w{6}/)) {
|
|
1683
|
+
ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
|
|
1684
|
+
text2 = text2.substring(10);
|
|
1685
|
+
}
|
|
1686
|
+
decodeResult.decoded = true;
|
|
1687
|
+
const fields = text2.split(",");
|
|
1688
|
+
if (fields.length === 11) {
|
|
1689
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[0]));
|
|
1690
|
+
ResultFormatter.tail(decodeResult, fields[2].replace(".", ""));
|
|
1691
|
+
if (fields[3])
|
|
1692
|
+
ResultFormatter.callsign(decodeResult, fields[3]);
|
|
1693
|
+
ResultFormatter.departureAirport(decodeResult, fields[4]);
|
|
1694
|
+
ResultFormatter.arrivalAirport(decodeResult, fields[5]);
|
|
1695
|
+
ResultFormatter.altitude(decodeResult, text2.substring(48, 51) * 100);
|
|
1696
|
+
decodeResult.remaining.text = fields.slice(8).join(",");
|
|
1697
|
+
} else if (fields.length === 6) {
|
|
1698
|
+
if (fields[0].match(/^[NS]/)) {
|
|
1699
|
+
ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(fields[0].substring(0, 13)));
|
|
1700
|
+
let wp1 = {
|
|
1701
|
+
name: fields[0].substring(13).trim(),
|
|
1702
|
+
time: DateTimeUtils.convertHHMMSSToTod(fields[1].substring(0, 6)),
|
|
1703
|
+
timeFormat: "tod"
|
|
1704
|
+
};
|
|
1705
|
+
ResultFormatter.altitude(decodeResult, fields[1].substring(6, 9) * 100);
|
|
1706
|
+
let wp2 = {
|
|
1707
|
+
name: fields[1].substring(9).trim(),
|
|
1708
|
+
time: DateTimeUtils.convertHHMMSSToTod(fields[2]),
|
|
1709
|
+
timeFormat: "tod"
|
|
1710
|
+
};
|
|
1711
|
+
decodeResult.raw.route = { waypoints: [wp1, wp2] };
|
|
1712
|
+
decodeResult.formatted.items.push({
|
|
1713
|
+
type: "aircraft_route",
|
|
1714
|
+
code: "ROUTE",
|
|
1715
|
+
label: "Aircraft Route",
|
|
1716
|
+
value: RouteUtils.routeToString(decodeResult.raw.route)
|
|
1717
|
+
});
|
|
1718
|
+
ResultFormatter.temperature(decodeResult, fields[3]);
|
|
1719
|
+
decodeResult.remaining.text = fields.slice(4).join(",");
|
|
1720
|
+
} else {
|
|
1721
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[0]));
|
|
1722
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1]));
|
|
1723
|
+
decodeResult.remaining.text = fields[2];
|
|
1724
|
+
ResultFormatter.altitude(decodeResult, fields[3]);
|
|
1725
|
+
ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates((fields[4] + fields[5]).replace(/[ \.]/g, "")));
|
|
1726
|
+
}
|
|
1727
|
+
} else {
|
|
1728
|
+
decodeResult.decoded = false;
|
|
1729
|
+
decodeResult.remaining.text = text2;
|
|
1730
|
+
}
|
|
1731
|
+
if (decodeResult.decoded) {
|
|
1732
|
+
if (!decodeResult.remaining.text)
|
|
1733
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
1734
|
+
else
|
|
1735
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1736
|
+
} else {
|
|
1737
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1738
|
+
}
|
|
1739
|
+
return decodeResult;
|
|
1740
|
+
}
|
|
1741
|
+
};
|
|
1742
|
+
|
|
1743
|
+
// lib/plugins/Label_4A_01.ts
|
|
1744
|
+
var Label_4A_01 = class extends DecoderPlugin {
|
|
1745
|
+
name = "label-4a-01";
|
|
1746
|
+
qualifiers() {
|
|
1747
|
+
return {
|
|
1748
|
+
labels: ["4A"],
|
|
1749
|
+
preambles: ["01"]
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
decode(message, options = {}) {
|
|
1753
|
+
const decodeResult = this.defaultResult();
|
|
1754
|
+
decodeResult.decoder.name = this.name;
|
|
1755
|
+
decodeResult.message = message;
|
|
1756
|
+
decodeResult.formatted.description = "Latest New Format";
|
|
1757
|
+
decodeResult.decoded = true;
|
|
1758
|
+
let rgx = message.text.match(/^01([A-Z]{2})([A-Z]{2})\s*(\w+)\/(\d{6})([A-Z]{4})([A-Z]{4})\r\n([+-]\s*\d+)(\d{3}\.\d)([+-]\s*\d+\.\d)/);
|
|
1759
|
+
if (rgx) {
|
|
1760
|
+
ResultFormatter.state_change(decodeResult, rgx[1], rgx[2]);
|
|
1761
|
+
ResultFormatter.callsign(decodeResult, rgx[3]);
|
|
1762
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(rgx[4] + "00"));
|
|
1763
|
+
ResultFormatter.departureAirport(decodeResult, rgx[5]);
|
|
1764
|
+
ResultFormatter.arrivalAirport(decodeResult, rgx[6]);
|
|
1765
|
+
ResultFormatter.altitude(decodeResult, Number(rgx[7].replace(/ /g, "")));
|
|
1766
|
+
decodeResult.remaining.text = rgx[8];
|
|
1767
|
+
ResultFormatter.temperature(decodeResult, rgx[9].replace(/ /g, ""));
|
|
1768
|
+
} else {
|
|
1769
|
+
decodeResult.decoded = false;
|
|
1770
|
+
decodeResult.remaining.text = message.text;
|
|
1771
|
+
}
|
|
1772
|
+
if (decodeResult.decoded) {
|
|
1773
|
+
if (!decodeResult.remaining.text)
|
|
1774
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
1775
|
+
else
|
|
1776
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1777
|
+
} else {
|
|
1778
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1779
|
+
}
|
|
1780
|
+
return decodeResult;
|
|
1781
|
+
}
|
|
1782
|
+
};
|
|
1783
|
+
|
|
1784
|
+
// lib/plugins/Label_4A_DIS.ts
|
|
1785
|
+
var Label_4A_DIS = class extends DecoderPlugin {
|
|
1786
|
+
name = "label-4a-dis";
|
|
1787
|
+
qualifiers() {
|
|
1788
|
+
return {
|
|
1789
|
+
labels: ["4A"],
|
|
1790
|
+
preambles: ["DIS"]
|
|
1791
|
+
};
|
|
1792
|
+
}
|
|
1793
|
+
decode(message, options = {}) {
|
|
1794
|
+
const decodeResult = this.defaultResult();
|
|
1795
|
+
decodeResult.decoder.name = this.name;
|
|
1796
|
+
decodeResult.message = message;
|
|
1797
|
+
decodeResult.formatted.description = "Latest New Format";
|
|
1798
|
+
decodeResult.decoded = true;
|
|
1799
|
+
const fields = message.text.split(",");
|
|
1800
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(2) + "00"));
|
|
1801
|
+
ResultFormatter.callsign(decodeResult, fields[2]);
|
|
1802
|
+
ResultFormatter.freetext(decodeResult, fields.slice(3).join(""));
|
|
1803
|
+
if (decodeResult.decoded) {
|
|
1804
|
+
if (!decodeResult.remaining.text)
|
|
1805
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
1806
|
+
else
|
|
1807
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1808
|
+
} else {
|
|
1809
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1810
|
+
}
|
|
1811
|
+
return decodeResult;
|
|
1812
|
+
}
|
|
1813
|
+
};
|
|
1814
|
+
|
|
1815
|
+
// lib/plugins/Label_4A_DOOR.ts
|
|
1816
|
+
var Label_4A_DOOR = class extends DecoderPlugin {
|
|
1817
|
+
name = "label-4a-door";
|
|
1818
|
+
qualifiers() {
|
|
1819
|
+
return {
|
|
1820
|
+
labels: ["4A"],
|
|
1821
|
+
preambles: ["DOOR"]
|
|
1822
|
+
};
|
|
1823
|
+
}
|
|
1824
|
+
decode(message, options = {}) {
|
|
1825
|
+
const decodeResult = this.defaultResult();
|
|
1826
|
+
decodeResult.decoder.name = this.name;
|
|
1827
|
+
decodeResult.message = message;
|
|
1828
|
+
decodeResult.formatted.description = "Latest New Format";
|
|
1829
|
+
decodeResult.decoded = true;
|
|
1830
|
+
const fields = message.text.split(" ");
|
|
1831
|
+
if (fields.length === 3) {
|
|
1832
|
+
ResultFormatter.door_event(decodeResult, fields[0].split("/")[1], fields[1]);
|
|
1833
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2] + "00"));
|
|
1834
|
+
} else {
|
|
1835
|
+
decodeResult.decoded = false;
|
|
1836
|
+
decodeResult.remaining.text = text;
|
|
1837
|
+
}
|
|
1838
|
+
if (decodeResult.decoded) {
|
|
1839
|
+
if (!decodeResult.remaining.text)
|
|
1840
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
1841
|
+
else
|
|
1842
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1843
|
+
} else {
|
|
1844
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1845
|
+
}
|
|
1846
|
+
return decodeResult;
|
|
1847
|
+
}
|
|
1848
|
+
};
|
|
1849
|
+
|
|
1850
|
+
// lib/plugins/Label_4A_Slash_01.ts
|
|
1851
|
+
var Label_4A_Slash_01 = class extends DecoderPlugin {
|
|
1852
|
+
name = "label-4a-slash-01";
|
|
1853
|
+
qualifiers() {
|
|
1854
|
+
return {
|
|
1855
|
+
labels: ["4A"],
|
|
1856
|
+
preambles: ["/01"]
|
|
1857
|
+
};
|
|
1858
|
+
}
|
|
1859
|
+
decode(message, options = {}) {
|
|
1860
|
+
const decodeResult = this.defaultResult();
|
|
1861
|
+
decodeResult.decoder.name = this.name;
|
|
1862
|
+
decodeResult.message = message;
|
|
1863
|
+
decodeResult.formatted.description = "Latest New Format";
|
|
1864
|
+
decodeResult.decoded = true;
|
|
1865
|
+
if (message.text.length === 5 && message.text.substring(0, 4) === "/01-") {
|
|
1866
|
+
decodeResult.remaining.text = message.text.substring(4);
|
|
1867
|
+
} else {
|
|
1868
|
+
decodeResult.decoded = false;
|
|
1869
|
+
decodeResult.remaining.text = message.text;
|
|
1870
|
+
}
|
|
1871
|
+
if (decodeResult.decoded) {
|
|
1872
|
+
if (!decodeResult.remaining.text)
|
|
1873
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
1874
|
+
else
|
|
1875
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1876
|
+
} else {
|
|
1877
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1878
|
+
}
|
|
1879
|
+
return decodeResult;
|
|
1880
|
+
}
|
|
1881
|
+
};
|
|
1882
|
+
|
|
1883
|
+
// lib/plugins/Label_4N.ts
|
|
1884
|
+
var Label_4N = class extends DecoderPlugin {
|
|
1885
|
+
name = "label-4n";
|
|
1886
|
+
qualifiers() {
|
|
1887
|
+
return {
|
|
1888
|
+
labels: ["4N"]
|
|
1889
|
+
};
|
|
1890
|
+
}
|
|
1891
|
+
decode(message, options = {}) {
|
|
1892
|
+
const decodeResult = this.defaultResult();
|
|
1893
|
+
decodeResult.decoder.name = this.name;
|
|
1894
|
+
decodeResult.message = message;
|
|
1895
|
+
decodeResult.formatted.description = "Airline Defined";
|
|
1896
|
+
let text2 = message.text;
|
|
1897
|
+
if (text2.match(/^M\d{2}A\w{6}/)) {
|
|
1898
|
+
ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
|
|
1899
|
+
text2 = text2.substring(10);
|
|
1900
|
+
}
|
|
1901
|
+
decodeResult.decoded = true;
|
|
1902
|
+
const fields = text2.split(",");
|
|
1903
|
+
if (text2.length === 51) {
|
|
1904
|
+
decodeResult.raw.day_of_month = text2.substring(0, 2);
|
|
1905
|
+
ResultFormatter.departureAirport(decodeResult, text2.substring(8, 11));
|
|
1906
|
+
ResultFormatter.arrivalAirport(decodeResult, text2.substring(13, 16));
|
|
1907
|
+
ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text2.substring(30, 45).replace(/^(.)0/, "$1")));
|
|
1908
|
+
ResultFormatter.altitude(decodeResult, text2.substring(48, 51) * 100);
|
|
1909
|
+
decodeResult.remaining.text = [text2.substring(2, 4), text2.substring(19, 29)].join(" ");
|
|
1910
|
+
} else if (fields.length === 33) {
|
|
1911
|
+
decodeResult.raw.date = fields[3];
|
|
1912
|
+
if (fields[1] === "B") {
|
|
1913
|
+
ResultFormatter.position(decodeResult, { latitude: Number(fields[4]), longitude: Number(fields[5]) });
|
|
1914
|
+
ResultFormatter.altitude(decodeResult, fields[6]);
|
|
1915
|
+
}
|
|
1916
|
+
ResultFormatter.departureAirport(decodeResult, fields[8]);
|
|
1917
|
+
ResultFormatter.arrivalAirport(decodeResult, fields[9]);
|
|
1918
|
+
ResultFormatter.alternateAirport(decodeResult, fields[10]);
|
|
1919
|
+
ResultFormatter.arrivalRunway(decodeResult, fields[11].split("/")[0]);
|
|
1920
|
+
if (fields[12].length > 1) {
|
|
1921
|
+
ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
|
|
1922
|
+
}
|
|
1923
|
+
ResultFormatter.checksum(decodeResult, fields[32]);
|
|
1924
|
+
decodeResult.remaining.text = [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != "").join(",");
|
|
1925
|
+
} else {
|
|
1926
|
+
decodeResult.decoded = false;
|
|
1927
|
+
decodeResult.remaining.text = text2;
|
|
1928
|
+
}
|
|
1929
|
+
if (decodeResult.decoded) {
|
|
1930
|
+
if (!decodeResult.remaining.text)
|
|
1931
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
1932
|
+
else
|
|
1933
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1934
|
+
} else {
|
|
1935
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1936
|
+
}
|
|
1937
|
+
return decodeResult;
|
|
1938
|
+
}
|
|
1939
|
+
};
|
|
1940
|
+
|
|
1941
|
+
// lib/plugins/Label_80.ts
|
|
1942
|
+
var Label_80 = class extends DecoderPlugin {
|
|
1943
|
+
name = "label-80";
|
|
1944
|
+
descriptions = {
|
|
1945
|
+
ALT: "Altitude",
|
|
1946
|
+
DWND: "Wind Direction",
|
|
1947
|
+
ETA: "Estimated Time of Arrival",
|
|
1948
|
+
FOB: "Fuel on Board",
|
|
1949
|
+
FL: "Flight Level",
|
|
1950
|
+
HDG: "Heading",
|
|
1951
|
+
MCH: "Aircraft Speed",
|
|
1952
|
+
NWYP: "Next Waypoint",
|
|
1953
|
+
POS: "Aircraft Position",
|
|
1954
|
+
SAT: "Static Air Temperature",
|
|
1955
|
+
SWND: "Wind Speed",
|
|
1956
|
+
TAS: "True Airspeed",
|
|
1957
|
+
WYP: "Waypoint"
|
|
1372
1958
|
};
|
|
1373
1959
|
qualifiers() {
|
|
1374
1960
|
return {
|
|
@@ -1383,27 +1969,15 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1383
1969
|
const parts = message.text.split("\n");
|
|
1384
1970
|
let posRptRegex = /^3N01 POSRPT \d\d\d\d\/\d\d (?<orig>\w+)\/(?<dest>\w+) \.(?<tail>[\w-]+)(\/(?<agate>.+) (?<sta>\w+:\w+))*/;
|
|
1385
1971
|
let results = parts[0].match(posRptRegex);
|
|
1972
|
+
if (!results?.groups) {
|
|
1973
|
+
decodeResult.decoded = false;
|
|
1974
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1975
|
+
return decodeResult;
|
|
1976
|
+
}
|
|
1386
1977
|
if (results && results.length > 0) {
|
|
1387
|
-
decodeResult
|
|
1388
|
-
decodeResult.
|
|
1389
|
-
|
|
1390
|
-
code: "ORG",
|
|
1391
|
-
label: "Origin",
|
|
1392
|
-
value: `${results.groups.orig}`
|
|
1393
|
-
});
|
|
1394
|
-
decodeResult.raw.destination = results.groups.dest;
|
|
1395
|
-
decodeResult.formatted.items.push({
|
|
1396
|
-
type: "destination",
|
|
1397
|
-
code: "DST",
|
|
1398
|
-
label: "Destination",
|
|
1399
|
-
value: `${results.groups.dest}`
|
|
1400
|
-
});
|
|
1401
|
-
decodeResult.raw.tail = results.groups.tail;
|
|
1402
|
-
decodeResult.formatted.items.push({
|
|
1403
|
-
type: "tail",
|
|
1404
|
-
label: "Tail",
|
|
1405
|
-
value: `${results.groups.tail}`
|
|
1406
|
-
});
|
|
1978
|
+
ResultFormatter.departureAirport(decodeResult, results.groups.orig);
|
|
1979
|
+
ResultFormatter.arrivalAirport(decodeResult, results.groups.dest);
|
|
1980
|
+
ResultFormatter.tail(decodeResult, results.groups.tail);
|
|
1407
1981
|
if (results.groups.agate) {
|
|
1408
1982
|
decodeResult.raw.arrival_gate = results.groups.agate;
|
|
1409
1983
|
decodeResult.formatted.items.push({
|
|
@@ -1425,15 +1999,9 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1425
1999
|
for (const part of remainingParts) {
|
|
1426
2000
|
const matches = part.matchAll(posRptRegex);
|
|
1427
2001
|
for (const match of matches) {
|
|
1428
|
-
switch (match.groups
|
|
2002
|
+
switch (match.groups?.field) {
|
|
1429
2003
|
case "ALT": {
|
|
1430
|
-
|
|
1431
|
-
decodeResult.formatted.items.push({
|
|
1432
|
-
type: "altitude",
|
|
1433
|
-
code: "ALT",
|
|
1434
|
-
label: this.descriptions[match.groups.field],
|
|
1435
|
-
value: `${decodeResult.raw.altitude} feet`
|
|
1436
|
-
});
|
|
2004
|
+
ResultFormatter.altitude(decodeResult, Number(match.groups.value));
|
|
1437
2005
|
break;
|
|
1438
2006
|
}
|
|
1439
2007
|
case "DWND": {
|
|
@@ -1447,9 +2015,8 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1447
2015
|
break;
|
|
1448
2016
|
}
|
|
1449
2017
|
case "FL": {
|
|
1450
|
-
const flight_level = match.groups.value;
|
|
1451
|
-
|
|
1452
|
-
ResultFormatter.altitude(decodeResult, decodeResult.raw.altitude);
|
|
2018
|
+
const flight_level = Number(match.groups.value);
|
|
2019
|
+
ResultFormatter.altitude(decodeResult, flight_level * 100);
|
|
1453
2020
|
break;
|
|
1454
2021
|
}
|
|
1455
2022
|
case "FOB": {
|
|
@@ -1473,7 +2040,7 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1473
2040
|
break;
|
|
1474
2041
|
}
|
|
1475
2042
|
case "MCH": {
|
|
1476
|
-
decodeResult.raw.mach = match.groups.value / 1e3;
|
|
2043
|
+
decodeResult.raw.mach = Number(match.groups.value) / 1e3;
|
|
1477
2044
|
decodeResult.formatted.items.push({
|
|
1478
2045
|
type: "mach",
|
|
1479
2046
|
code: "MCH",
|
|
@@ -1495,20 +2062,13 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1495
2062
|
case "POS": {
|
|
1496
2063
|
const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
|
|
1497
2064
|
const posResult = match.groups.value.match(posRegex);
|
|
1498
|
-
const lat = Number(posResult
|
|
1499
|
-
const lon = Number(posResult
|
|
1500
|
-
const
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
latitude,
|
|
1504
|
-
longitude
|
|
2065
|
+
const lat = Number(posResult?.groups?.lat) * (posResult?.groups?.lngd === "S" ? -1 : 1);
|
|
2066
|
+
const lon = Number(posResult?.groups?.lng) * (posResult?.groups?.lngd === "W" ? -1 : 1);
|
|
2067
|
+
const position = {
|
|
2068
|
+
latitude: Number.isInteger(lat) ? lat / 1e3 : lat / 100,
|
|
2069
|
+
longitude: Number.isInteger(lon) ? lon / 1e3 : lon / 100
|
|
1505
2070
|
};
|
|
1506
|
-
|
|
1507
|
-
type: "position",
|
|
1508
|
-
code: "POS",
|
|
1509
|
-
label: "Position",
|
|
1510
|
-
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
1511
|
-
});
|
|
2071
|
+
ResultFormatter.position(decodeResult, position);
|
|
1512
2072
|
break;
|
|
1513
2073
|
}
|
|
1514
2074
|
case "SWND": {
|
|
@@ -1522,7 +2082,7 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1522
2082
|
break;
|
|
1523
2083
|
}
|
|
1524
2084
|
default: {
|
|
1525
|
-
if (match.groups
|
|
2085
|
+
if (match.groups?.field != void 0) {
|
|
1526
2086
|
const description = this.descriptions[match.groups.field] ? this.descriptions[match.groups.field] : "Unknown";
|
|
1527
2087
|
decodeResult.formatted.items.push({
|
|
1528
2088
|
type: match.groups.field,
|
|
@@ -1536,7 +2096,80 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1536
2096
|
}
|
|
1537
2097
|
}
|
|
1538
2098
|
decodeResult.decoded = true;
|
|
1539
|
-
decodeResult.decodeLevel = "partial";
|
|
2099
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
2100
|
+
}
|
|
2101
|
+
return decodeResult;
|
|
2102
|
+
}
|
|
2103
|
+
};
|
|
2104
|
+
|
|
2105
|
+
// lib/plugins/Label_83.ts
|
|
2106
|
+
var Label_83 = class extends DecoderPlugin {
|
|
2107
|
+
name = "label-83";
|
|
2108
|
+
qualifiers() {
|
|
2109
|
+
return {
|
|
2110
|
+
labels: ["83"]
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
2113
|
+
decode(message, options = {}) {
|
|
2114
|
+
const decodeResult = this.defaultResult();
|
|
2115
|
+
decodeResult.decoder.name = this.name;
|
|
2116
|
+
decodeResult.message = message;
|
|
2117
|
+
decodeResult.formatted.description = "Airline Defined";
|
|
2118
|
+
let text2 = message.text;
|
|
2119
|
+
if (text2.match(/^M\d{2}A\w{6}/)) {
|
|
2120
|
+
ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
|
|
2121
|
+
text2 = text2.substring(10);
|
|
2122
|
+
}
|
|
2123
|
+
decodeResult.decoded = true;
|
|
2124
|
+
if (text2.substring(0, 10) === "4DH3 ETAT2") {
|
|
2125
|
+
const fields = text2.split(/\s+/);
|
|
2126
|
+
if (fields[2].length > 5) {
|
|
2127
|
+
decodeResult.raw.day_of_month = fields[2].substring(5);
|
|
2128
|
+
}
|
|
2129
|
+
decodeResult.remaining.text = fields[2].substring(0, 4);
|
|
2130
|
+
const subfields = fields[3].split("/");
|
|
2131
|
+
ResultFormatter.departureAirport(decodeResult, subfields[0]);
|
|
2132
|
+
ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
|
|
2133
|
+
ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
|
|
2134
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[6] + "00"));
|
|
2135
|
+
} else if (text2.substring(0, 5) === "001PR") {
|
|
2136
|
+
decodeResult.raw.day_of_month = text2.substring(5, 7);
|
|
2137
|
+
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text2.substring(13, 28).replace(/\./g, ""));
|
|
2138
|
+
if (position) {
|
|
2139
|
+
ResultFormatter.position(decodeResult, position);
|
|
2140
|
+
}
|
|
2141
|
+
ResultFormatter.altitude(decodeResult, Number(text2.substring(28, 33)));
|
|
2142
|
+
decodeResult.remaining.text = text2.substring(33);
|
|
2143
|
+
} else {
|
|
2144
|
+
const fields = text2.replace(/\s/g, "").split(",");
|
|
2145
|
+
if (fields.length === 9) {
|
|
2146
|
+
ResultFormatter.departureAirport(decodeResult, fields[0]);
|
|
2147
|
+
ResultFormatter.arrivalAirport(decodeResult, fields[1]);
|
|
2148
|
+
decodeResult.raw.day_of_month = fields[2].substring(0, 2);
|
|
2149
|
+
decodeResult.raw.time = fields[2].substring(2);
|
|
2150
|
+
ResultFormatter.position(
|
|
2151
|
+
decodeResult,
|
|
2152
|
+
{
|
|
2153
|
+
latitude: Number(fields[3].replace(/\s/g, "")),
|
|
2154
|
+
longitude: Number(fields[4].replace(/\s/g, ""))
|
|
2155
|
+
}
|
|
2156
|
+
);
|
|
2157
|
+
ResultFormatter.altitude(decodeResult, Number(fields[5]));
|
|
2158
|
+
ResultFormatter.groundspeed(decodeResult, fields[6]);
|
|
2159
|
+
ResultFormatter.heading(decodeResult, fields[7]);
|
|
2160
|
+
decodeResult.remaining.text = fields[8];
|
|
2161
|
+
} else {
|
|
2162
|
+
decodeResult.decoded = false;
|
|
2163
|
+
decodeResult.remaining.text = message.text;
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
if (decodeResult.decoded) {
|
|
2167
|
+
if (!decodeResult.remaining.text)
|
|
2168
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
2169
|
+
else
|
|
2170
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
2171
|
+
} else {
|
|
2172
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1540
2173
|
}
|
|
1541
2174
|
return decodeResult;
|
|
1542
2175
|
}
|
|
@@ -1562,19 +2195,8 @@ var Label_8E = class extends DecoderPlugin {
|
|
|
1562
2195
|
console.log(`Label 8E ETA: groups`);
|
|
1563
2196
|
console.log(results.groups);
|
|
1564
2197
|
}
|
|
1565
|
-
decodeResult.
|
|
1566
|
-
|
|
1567
|
-
code: "ETA",
|
|
1568
|
-
label: "Estimated Time of Arrival",
|
|
1569
|
-
value: DateTimeUtils.UTCToString(results.groups.arrival_eta)
|
|
1570
|
-
});
|
|
1571
|
-
decodeResult.raw.arrival_icao = results.groups.arrival_icao;
|
|
1572
|
-
decodeResult.formatted.items.push({
|
|
1573
|
-
type: "destination",
|
|
1574
|
-
code: "DST",
|
|
1575
|
-
label: "Destination",
|
|
1576
|
-
value: decodeResult.raw.arrival_icao
|
|
1577
|
-
});
|
|
2198
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta + "00"));
|
|
2199
|
+
ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
|
|
1578
2200
|
}
|
|
1579
2201
|
decodeResult.decoded = true;
|
|
1580
2202
|
decodeResult.decoder.decodeLevel = "full";
|
|
@@ -1627,44 +2249,158 @@ var Label_ColonComma = class extends DecoderPlugin {
|
|
|
1627
2249
|
}
|
|
1628
2250
|
};
|
|
1629
2251
|
|
|
1630
|
-
// lib/plugins/Label_H1_FLR.ts
|
|
1631
|
-
var Label_H1_FLR = class extends DecoderPlugin {
|
|
1632
|
-
name = "label-h1-flr";
|
|
2252
|
+
// lib/plugins/Label_H1_FLR.ts
|
|
2253
|
+
var Label_H1_FLR = class extends DecoderPlugin {
|
|
2254
|
+
name = "label-h1-flr";
|
|
2255
|
+
qualifiers() {
|
|
2256
|
+
return {
|
|
2257
|
+
labels: ["H1"],
|
|
2258
|
+
preambles: ["FLR", "#CFBFLR"]
|
|
2259
|
+
};
|
|
2260
|
+
}
|
|
2261
|
+
decode(message, options = {}) {
|
|
2262
|
+
let decodeResult = this.defaultResult();
|
|
2263
|
+
decodeResult.decoder.name = this.name;
|
|
2264
|
+
decodeResult.formatted.description = "Fault Log Report";
|
|
2265
|
+
decodeResult.message = message;
|
|
2266
|
+
const parts = message.text.split("/FR");
|
|
2267
|
+
if (parts.length > 1) {
|
|
2268
|
+
decodeResult.remaining.text = "";
|
|
2269
|
+
const fields = parts[0].split("/");
|
|
2270
|
+
for (let i = 1; i < fields.length; i++) {
|
|
2271
|
+
const field = fields[i];
|
|
2272
|
+
if (field.startsWith("PN")) {
|
|
2273
|
+
processUnknown(decodeResult, "/" + field);
|
|
2274
|
+
} else {
|
|
2275
|
+
processUnknown(decodeResult, "/" + field);
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
const data = parts[1].substring(0, 20);
|
|
2279
|
+
const msg = parts[1].substring(20);
|
|
2280
|
+
const datetime = data.substring(0, 12);
|
|
2281
|
+
const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
|
|
2282
|
+
processUnknown(decodeResult, data.substring(12));
|
|
2283
|
+
decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
|
|
2284
|
+
decodeResult.raw.fault_message = msg;
|
|
2285
|
+
decodeResult.formatted.items.push({
|
|
2286
|
+
type: "fault",
|
|
2287
|
+
code: "FR",
|
|
2288
|
+
label: "Fault Report",
|
|
2289
|
+
value: decodeResult.raw.fault_message
|
|
2290
|
+
});
|
|
2291
|
+
decodeResult.decoded = true;
|
|
2292
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
2293
|
+
} else {
|
|
2294
|
+
if (options.debug) {
|
|
2295
|
+
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2296
|
+
}
|
|
2297
|
+
decodeResult.remaining.text = message.text;
|
|
2298
|
+
decodeResult.decoded = false;
|
|
2299
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
2300
|
+
}
|
|
2301
|
+
return decodeResult;
|
|
2302
|
+
}
|
|
2303
|
+
};
|
|
2304
|
+
function processUnknown(decodeResult, value) {
|
|
2305
|
+
decodeResult.remaining.text += value;
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2308
|
+
// lib/plugins/Label_H1_OHMA.ts
|
|
2309
|
+
var zlib = __toESM(require("minizlib"));
|
|
2310
|
+
var Label_H1_OHMA = class extends DecoderPlugin {
|
|
2311
|
+
name = "label-h1-ohma";
|
|
2312
|
+
qualifiers() {
|
|
2313
|
+
return {
|
|
2314
|
+
labels: ["H1"],
|
|
2315
|
+
preambles: ["OHMA", "/RTNBOCR.OHMA", "#T1B/RTNBOCR.OHMA"]
|
|
2316
|
+
};
|
|
2317
|
+
}
|
|
2318
|
+
decode(message, options = {}) {
|
|
2319
|
+
let decodeResult = this.defaultResult();
|
|
2320
|
+
decodeResult.decoder.name = this.name;
|
|
2321
|
+
decodeResult.formatted.description = "OHMA Message";
|
|
2322
|
+
decodeResult.message = message;
|
|
2323
|
+
decodeResult.remaining.text = "";
|
|
2324
|
+
const data = message.text.split("OHMA")[1];
|
|
2325
|
+
try {
|
|
2326
|
+
const compressedBuffer = Buffer.from(data, "base64");
|
|
2327
|
+
const decompress = new zlib.Inflate({ windowBits: 15 });
|
|
2328
|
+
decompress.write(compressedBuffer);
|
|
2329
|
+
decompress.flush(zlib.constants.Z_SYNC_FLUSH);
|
|
2330
|
+
const result = decompress.read();
|
|
2331
|
+
const jsonText = result.toString();
|
|
2332
|
+
let formattedMsg;
|
|
2333
|
+
let jsonMessage;
|
|
2334
|
+
try {
|
|
2335
|
+
jsonMessage = JSON.parse(jsonText).message;
|
|
2336
|
+
} catch {
|
|
2337
|
+
jsonMessage = jsonText;
|
|
2338
|
+
}
|
|
2339
|
+
try {
|
|
2340
|
+
const ohmaMsg = JSON.parse(jsonMessage);
|
|
2341
|
+
formattedMsg = JSON.stringify(ohmaMsg, null, 2);
|
|
2342
|
+
} catch {
|
|
2343
|
+
formattedMsg = jsonMessage;
|
|
2344
|
+
}
|
|
2345
|
+
decodeResult.decoded = true;
|
|
2346
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
2347
|
+
decodeResult.raw.ohma = jsonText;
|
|
2348
|
+
decodeResult.formatted.items.push({
|
|
2349
|
+
type: "ohma",
|
|
2350
|
+
code: "OHMA",
|
|
2351
|
+
label: "OHMA Downlink",
|
|
2352
|
+
value: formattedMsg
|
|
2353
|
+
});
|
|
2354
|
+
} catch (e) {
|
|
2355
|
+
if (options.debug) {
|
|
2356
|
+
console.log(`Decoder: Unknown H1 OHMA message: ${message.text}`, e);
|
|
2357
|
+
}
|
|
2358
|
+
decodeResult.remaining.text += message.text;
|
|
2359
|
+
decodeResult.decoded = false;
|
|
2360
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
2361
|
+
}
|
|
2362
|
+
return decodeResult;
|
|
2363
|
+
}
|
|
2364
|
+
};
|
|
2365
|
+
|
|
2366
|
+
// lib/plugins/Label_H1_WRN.ts
|
|
2367
|
+
var Label_H1_WRN = class extends DecoderPlugin {
|
|
2368
|
+
name = "label-h1-wrn";
|
|
1633
2369
|
qualifiers() {
|
|
1634
2370
|
return {
|
|
1635
2371
|
labels: ["H1"],
|
|
1636
|
-
preambles: ["
|
|
2372
|
+
preambles: ["WRN", "#CFBWRN"]
|
|
1637
2373
|
};
|
|
1638
2374
|
}
|
|
1639
2375
|
decode(message, options = {}) {
|
|
1640
2376
|
let decodeResult = this.defaultResult();
|
|
1641
2377
|
decodeResult.decoder.name = this.name;
|
|
1642
|
-
decodeResult.formatted.description = "
|
|
2378
|
+
decodeResult.formatted.description = "Warning Message";
|
|
1643
2379
|
decodeResult.message = message;
|
|
1644
|
-
const parts = message.text.split("/
|
|
2380
|
+
const parts = message.text.split("/WN");
|
|
1645
2381
|
if (parts.length > 1) {
|
|
1646
2382
|
decodeResult.remaining.text = "";
|
|
1647
2383
|
const fields = parts[0].split("/");
|
|
1648
2384
|
for (let i = 1; i < fields.length; i++) {
|
|
1649
2385
|
const field = fields[i];
|
|
1650
2386
|
if (field.startsWith("PN")) {
|
|
1651
|
-
|
|
2387
|
+
processUnknown2(decodeResult, "/" + field);
|
|
1652
2388
|
} else {
|
|
1653
|
-
|
|
2389
|
+
processUnknown2(decodeResult, "/" + field);
|
|
1654
2390
|
}
|
|
1655
2391
|
}
|
|
1656
2392
|
const data = parts[1].substring(0, 20);
|
|
1657
2393
|
const msg = parts[1].substring(20);
|
|
1658
2394
|
const datetime = data.substring(0, 12);
|
|
1659
2395
|
const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
|
|
1660
|
-
|
|
2396
|
+
processUnknown2(decodeResult, data.substring(12));
|
|
1661
2397
|
decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
|
|
1662
|
-
decodeResult.raw.
|
|
2398
|
+
decodeResult.raw.warning_message = msg;
|
|
1663
2399
|
decodeResult.formatted.items.push({
|
|
1664
|
-
type: "
|
|
1665
|
-
code: "
|
|
1666
|
-
label: "
|
|
1667
|
-
value: decodeResult.raw.
|
|
2400
|
+
type: "warning",
|
|
2401
|
+
code: "WRN",
|
|
2402
|
+
label: "Warning Message",
|
|
2403
|
+
value: decodeResult.raw.warning_message
|
|
1668
2404
|
});
|
|
1669
2405
|
decodeResult.decoded = true;
|
|
1670
2406
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -1679,7 +2415,7 @@ var Label_H1_FLR = class extends DecoderPlugin {
|
|
|
1679
2415
|
return decodeResult;
|
|
1680
2416
|
}
|
|
1681
2417
|
};
|
|
1682
|
-
function
|
|
2418
|
+
function processUnknown2(decodeResult, value) {
|
|
1683
2419
|
decodeResult.remaining.text += value;
|
|
1684
2420
|
}
|
|
1685
2421
|
|
|
@@ -1845,11 +2581,10 @@ function addCompanyRoute(decodeResult, value) {
|
|
|
1845
2581
|
// lib/utils/h1_helper.ts
|
|
1846
2582
|
var H1Helper = class {
|
|
1847
2583
|
static decodeH1Message(decodeResult, message) {
|
|
1848
|
-
let allKnownFields = true;
|
|
1849
2584
|
const checksum = message.slice(-4);
|
|
1850
2585
|
const data = message.slice(0, message.length - 4);
|
|
1851
2586
|
const fields = data.split("/");
|
|
1852
|
-
|
|
2587
|
+
parseMessageType(decodeResult, fields[0]);
|
|
1853
2588
|
for (let i = 1; i < fields.length; ++i) {
|
|
1854
2589
|
if (fields[i].startsWith("FN")) {
|
|
1855
2590
|
decodeResult.raw.flight_number = fields[i].substring(2);
|
|
@@ -1868,32 +2603,22 @@ var H1Helper = class {
|
|
|
1868
2603
|
decodeResult.raw.message_timestamp = time;
|
|
1869
2604
|
} else if (fields[i].startsWith("PS")) {
|
|
1870
2605
|
const pos = processPS(decodeResult, fields[i].substring(2).split(","));
|
|
1871
|
-
allKnownFields == allKnownFields && pos;
|
|
1872
2606
|
} else if (fields[i].startsWith("DT")) {
|
|
1873
2607
|
const data2 = fields[i].substring(2).split(",");
|
|
1874
|
-
|
|
1875
|
-
allKnownFields = allKnownFields && dt;
|
|
2608
|
+
processDT(decodeResult, data2);
|
|
1876
2609
|
} else if (fields[i].startsWith("ID")) {
|
|
1877
2610
|
processIdentification(decodeResult, fields[i].substring(2).split(","));
|
|
1878
2611
|
} else if (fields[i].startsWith("LR")) {
|
|
1879
2612
|
const data2 = fields[i].substring(2).split(",");
|
|
1880
|
-
|
|
1881
|
-
allKnownFields = allKnownFields && lr;
|
|
2613
|
+
processLR(decodeResult, data2);
|
|
1882
2614
|
} else if (fields[i].startsWith("RI") || fields[i].startsWith("RF") || fields[i].startsWith("RP")) {
|
|
1883
|
-
|
|
1884
|
-
allKnownFields = allKnownFields && fp;
|
|
2615
|
+
FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
|
|
1885
2616
|
} else if (fields[i].startsWith("PR")) {
|
|
1886
|
-
allKnownFields = false;
|
|
1887
2617
|
decodeResult.remaining.text += "/" + fields[i];
|
|
1888
|
-
} else if (fields[i].startsWith("PS")) {
|
|
1889
|
-
allKnownFields = false;
|
|
1890
|
-
decodeResult.remaining.text += fields[i];
|
|
1891
2618
|
} else if (fields[i].startsWith("AF")) {
|
|
1892
|
-
|
|
1893
|
-
allKnownFields = allKnownFields && af;
|
|
2619
|
+
processAirField(decodeResult, fields[i].substring(2).split(","));
|
|
1894
2620
|
} else if (fields[i].startsWith("TD")) {
|
|
1895
|
-
|
|
1896
|
-
allKnownFields = allKnownFields && td;
|
|
2621
|
+
processTimeOfDeparture(decodeResult, fields[i].substring(2).split(","));
|
|
1897
2622
|
} else if (fields[i].startsWith("FX")) {
|
|
1898
2623
|
decodeResult.raw.free_text = fields[i].substring(2);
|
|
1899
2624
|
decodeResult.formatted.items.push({
|
|
@@ -1904,23 +2629,21 @@ var H1Helper = class {
|
|
|
1904
2629
|
});
|
|
1905
2630
|
} else {
|
|
1906
2631
|
decodeResult.remaining.text += "/" + fields[i];
|
|
1907
|
-
allKnownFields = false;
|
|
1908
2632
|
}
|
|
1909
2633
|
}
|
|
1910
2634
|
if (decodeResult.formatted.items.length > 0) {
|
|
1911
2635
|
ResultFormatter.checksum(decodeResult, checksum);
|
|
1912
2636
|
}
|
|
1913
|
-
return
|
|
2637
|
+
return true;
|
|
1914
2638
|
}
|
|
1915
2639
|
};
|
|
1916
2640
|
function processAirField(decodeResult, data) {
|
|
1917
2641
|
if (data.length === 2) {
|
|
1918
2642
|
ResultFormatter.departureAirport(decodeResult, data[0]);
|
|
1919
2643
|
ResultFormatter.arrivalAirport(decodeResult, data[1]);
|
|
1920
|
-
|
|
2644
|
+
} else {
|
|
2645
|
+
decodeResult.remaining.text += "AF/" + data.join(",");
|
|
1921
2646
|
}
|
|
1922
|
-
decodeResult.remaining.text += "AF/" + data.join(",");
|
|
1923
|
-
return false;
|
|
1924
2647
|
}
|
|
1925
2648
|
function processTimeOfDeparture(decodeResult, data) {
|
|
1926
2649
|
if (data.length === 2) {
|
|
@@ -1938,19 +2661,12 @@ function processTimeOfDeparture(decodeResult, data) {
|
|
|
1938
2661
|
label: "Estimated Departure Time",
|
|
1939
2662
|
value: `${data[1].substring(0, 2)}:${data[1].substring(2)}`
|
|
1940
2663
|
});
|
|
1941
|
-
|
|
2664
|
+
} else {
|
|
2665
|
+
decodeResult.remaining.text += "/TD" + data.join(",");
|
|
1942
2666
|
}
|
|
1943
|
-
decodeResult.remaining.text += "/TD" + data.join(",");
|
|
1944
|
-
return false;
|
|
1945
2667
|
}
|
|
1946
2668
|
function processIdentification(decodeResult, data) {
|
|
1947
|
-
|
|
1948
|
-
decodeResult.formatted.items.push({
|
|
1949
|
-
type: "tail",
|
|
1950
|
-
code: "TAIL",
|
|
1951
|
-
label: "Tail",
|
|
1952
|
-
value: decodeResult.raw.tail
|
|
1953
|
-
});
|
|
2669
|
+
ResultFormatter.tail(decodeResult, data[0]);
|
|
1954
2670
|
if (data.length > 1) {
|
|
1955
2671
|
decodeResult.raw.flight_number = data[1];
|
|
1956
2672
|
}
|
|
@@ -1959,7 +2675,6 @@ function processIdentification(decodeResult, data) {
|
|
|
1959
2675
|
}
|
|
1960
2676
|
}
|
|
1961
2677
|
function processDT(decodeResult, data) {
|
|
1962
|
-
let allKnownFields = true;
|
|
1963
2678
|
if (!decodeResult.raw.arrival_icao) {
|
|
1964
2679
|
ResultFormatter.arrivalAirport(decodeResult, data[0]);
|
|
1965
2680
|
} else if (decodeResult.raw.arrival_icao != data[0]) {
|
|
@@ -1972,19 +2687,16 @@ function processDT(decodeResult, data) {
|
|
|
1972
2687
|
ResultFormatter.currentFuel(decodeResult, Number(data[2]));
|
|
1973
2688
|
}
|
|
1974
2689
|
if (data.length > 3) {
|
|
1975
|
-
ResultFormatter.eta(decodeResult, data[3]);
|
|
2690
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[3]));
|
|
1976
2691
|
}
|
|
1977
2692
|
if (data.length > 4) {
|
|
1978
2693
|
ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
|
|
1979
2694
|
}
|
|
1980
2695
|
if (data.length > 5) {
|
|
1981
|
-
allKnownFields = false;
|
|
1982
2696
|
decodeResult.remaining.text += "," + data.slice(5).join(",");
|
|
1983
2697
|
}
|
|
1984
|
-
return allKnownFields;
|
|
1985
2698
|
}
|
|
1986
2699
|
function processLR(decodeResult, data) {
|
|
1987
|
-
let allKnownFields = true;
|
|
1988
2700
|
if (data.length === 19) {
|
|
1989
2701
|
ResultFormatter.unknown(decodeResult, data[1]);
|
|
1990
2702
|
ResultFormatter.flightNumber(decodeResult, data[2]);
|
|
@@ -1992,34 +2704,47 @@ function processLR(decodeResult, data) {
|
|
|
1992
2704
|
ResultFormatter.arrivalAirport(decodeResult, data[4]);
|
|
1993
2705
|
ResultFormatter.arrivalRunway(decodeResult, data[5]);
|
|
1994
2706
|
ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
|
|
1995
|
-
allKnownFields = false;
|
|
1996
2707
|
} else {
|
|
1997
|
-
|
|
2708
|
+
ResultFormatter.unknown(decodeResult, data.join(","));
|
|
1998
2709
|
}
|
|
1999
|
-
return allKnownFields;
|
|
2000
2710
|
}
|
|
2001
2711
|
function parseMessageType(decodeResult, messageType) {
|
|
2002
|
-
let decoded = true;
|
|
2003
2712
|
const parts = messageType.split("#");
|
|
2004
2713
|
if (parts.length == 1) {
|
|
2005
|
-
|
|
2006
|
-
|
|
2714
|
+
const type = parts[0].substring(0, 3);
|
|
2715
|
+
if (type === "POS" && parts[0].length !== 3) {
|
|
2716
|
+
processPosition2(decodeResult, parts[0].substring(3).split(","));
|
|
2007
2717
|
}
|
|
2008
|
-
return
|
|
2718
|
+
return processMessageType(decodeResult, type);
|
|
2009
2719
|
} else if (parts.length == 2) {
|
|
2010
2720
|
if (parts[0].length > 0) {
|
|
2011
2721
|
decodeResult.remaining.text += parts[0].substring(0, 3);
|
|
2012
2722
|
decodeResult.raw.flight_number = parts[0].substring(3);
|
|
2013
|
-
decodeResult.remaining.text += "#" + parts[1].substring(0, 3);
|
|
2723
|
+
decodeResult.remaining.text += "#" + (parts[1].length == 5 ? parts[1].substring(0, 2) : parts[1].substring(0, 3));
|
|
2014
2724
|
}
|
|
2015
|
-
|
|
2016
|
-
|
|
2725
|
+
const type = parts[1].length == 5 ? parts[1].substring(2, 5) : parts[1].substring(3, 6);
|
|
2726
|
+
if (parts[1].substring(3, 6) === "POS" && parts[1].length > 6) {
|
|
2727
|
+
processPosition2(decodeResult, parts[1].substring(6).split(","));
|
|
2017
2728
|
}
|
|
2018
|
-
decodeResult
|
|
2019
|
-
|
|
2729
|
+
processMessageType(decodeResult, type);
|
|
2730
|
+
} else {
|
|
2731
|
+
decodeResult.remaining.text += messageType;
|
|
2732
|
+
}
|
|
2733
|
+
}
|
|
2734
|
+
function processMessageType(decodeResult, type) {
|
|
2735
|
+
if (type === "FPN") {
|
|
2736
|
+
decodeResult.formatted.description = "Flight Plan";
|
|
2737
|
+
} else if (type === "FTX") {
|
|
2738
|
+
decodeResult.formatted.description = "Free Text";
|
|
2739
|
+
} else if (type === "INI") {
|
|
2740
|
+
decodeResult.formatted.description = "Flight Plan Initial Report";
|
|
2741
|
+
} else if (type === "POS") {
|
|
2742
|
+
decodeResult.formatted.description = "Position Report";
|
|
2743
|
+
} else if (type === "PRG") {
|
|
2744
|
+
decodeResult.formatted.description = "Progress Report";
|
|
2745
|
+
} else {
|
|
2746
|
+
decodeResult.formatted.description = "Unknown H1 Message";
|
|
2020
2747
|
}
|
|
2021
|
-
decodeResult.remaining.text += messageType;
|
|
2022
|
-
return false;
|
|
2023
2748
|
}
|
|
2024
2749
|
function processDC(decodeResult, data) {
|
|
2025
2750
|
decodeResult.raw.message_date = data[0];
|
|
@@ -2028,13 +2753,9 @@ function processDC(decodeResult, data) {
|
|
|
2028
2753
|
const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
|
|
2029
2754
|
const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
|
|
2030
2755
|
decodeResult.raw.message_timestamp = time;
|
|
2031
|
-
} else {
|
|
2032
|
-
return false;
|
|
2033
2756
|
}
|
|
2034
|
-
return true;
|
|
2035
2757
|
}
|
|
2036
2758
|
function processPS(decodeResult, data) {
|
|
2037
|
-
let allKnownFields = true;
|
|
2038
2759
|
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
|
|
2039
2760
|
if (position) {
|
|
2040
2761
|
decodeResult.raw.position = position;
|
|
@@ -2044,11 +2765,7 @@ function processPS(decodeResult, data) {
|
|
|
2044
2765
|
label: "Aircraft Position",
|
|
2045
2766
|
value: CoordinateUtils.coordinateString(position)
|
|
2046
2767
|
});
|
|
2047
|
-
} else {
|
|
2048
|
-
allKnownFields = false;
|
|
2049
2768
|
}
|
|
2050
|
-
console.log("PS data.length: ", data.length);
|
|
2051
|
-
console.log("PS data: ", data);
|
|
2052
2769
|
if (data.length === 9) {
|
|
2053
2770
|
processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
|
|
2054
2771
|
ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
|
|
@@ -2066,11 +2783,8 @@ function processPS(decodeResult, data) {
|
|
|
2066
2783
|
ResultFormatter.unknown(decodeResult, data[9]);
|
|
2067
2784
|
ResultFormatter.unknown(decodeResult, data.slice(11).join(","));
|
|
2068
2785
|
}
|
|
2069
|
-
allKnownFields = false;
|
|
2070
|
-
return allKnownFields;
|
|
2071
2786
|
}
|
|
2072
2787
|
function processPosition2(decodeResult, data) {
|
|
2073
|
-
let allKnownFields = true;
|
|
2074
2788
|
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
|
|
2075
2789
|
if (position) {
|
|
2076
2790
|
decodeResult.raw.position = position;
|
|
@@ -2080,11 +2794,7 @@ function processPosition2(decodeResult, data) {
|
|
|
2080
2794
|
label: "Aircraft Position",
|
|
2081
2795
|
value: CoordinateUtils.coordinateString(position)
|
|
2082
2796
|
});
|
|
2083
|
-
} else {
|
|
2084
|
-
allKnownFields = false;
|
|
2085
2797
|
}
|
|
2086
|
-
console.log("data.length: ", data.length);
|
|
2087
|
-
console.log("data: ", data);
|
|
2088
2798
|
if (data.length >= 10) {
|
|
2089
2799
|
ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
|
|
2090
2800
|
processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
|
|
@@ -2098,8 +2808,6 @@ function processPosition2(decodeResult, data) {
|
|
|
2098
2808
|
ResultFormatter.unknown(decodeResult, data[12]);
|
|
2099
2809
|
ResultFormatter.unknown(decodeResult, data[13]);
|
|
2100
2810
|
}
|
|
2101
|
-
allKnownFields = false;
|
|
2102
|
-
return allKnownFields;
|
|
2103
2811
|
}
|
|
2104
2812
|
function processRoute(decodeResult, last, time, next, eta, then, date) {
|
|
2105
2813
|
const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
|
|
@@ -2122,229 +2830,24 @@ function processRoute(decodeResult, last, time, next, eta, then, date) {
|
|
|
2122
2830
|
});
|
|
2123
2831
|
}
|
|
2124
2832
|
|
|
2125
|
-
// lib/plugins/
|
|
2126
|
-
var
|
|
2127
|
-
name = "label-h1
|
|
2833
|
+
// lib/plugins/Label_H1.ts
|
|
2834
|
+
var Label_H1 = class extends DecoderPlugin {
|
|
2835
|
+
name = "label-h1";
|
|
2128
2836
|
qualifiers() {
|
|
2129
2837
|
return {
|
|
2130
|
-
labels: ["H1"]
|
|
2131
|
-
preambles: ["FPN", "#M1BFPN"]
|
|
2838
|
+
labels: ["H1"]
|
|
2132
2839
|
};
|
|
2133
2840
|
}
|
|
2134
2841
|
decode(message, options = {}) {
|
|
2135
2842
|
let decodeResult = this.defaultResult();
|
|
2136
2843
|
decodeResult.decoder.name = this.name;
|
|
2137
|
-
decodeResult.formatted.description = "Flight Plan";
|
|
2138
2844
|
decodeResult.message = message;
|
|
2139
2845
|
decodeResult.remaining.text = "";
|
|
2140
2846
|
const msg = message.text.replace(/\n|\r/g, "");
|
|
2141
|
-
const
|
|
2142
|
-
decodeResult.decoded =
|
|
2143
|
-
decodeResult.decoder.decodeLevel =
|
|
2144
|
-
if (decodeResult.formatted.items.length === 0) {
|
|
2145
|
-
if (options?.debug) {
|
|
2146
|
-
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2147
|
-
}
|
|
2148
|
-
decodeResult.remaining.text = message.text;
|
|
2149
|
-
decodeResult.decoded = false;
|
|
2150
|
-
decodeResult.decoder.decodeLevel = "none";
|
|
2151
|
-
}
|
|
2152
|
-
return decodeResult;
|
|
2153
|
-
}
|
|
2154
|
-
};
|
|
2155
|
-
|
|
2156
|
-
// lib/plugins/Label_H1_FTX.ts
|
|
2157
|
-
var Label_H1_FTX = class extends DecoderPlugin {
|
|
2158
|
-
name = "label-h1-ftx";
|
|
2159
|
-
qualifiers() {
|
|
2160
|
-
return {
|
|
2161
|
-
labels: ["H1"],
|
|
2162
|
-
preambles: ["FTX", "- #MDFTX"]
|
|
2163
|
-
};
|
|
2164
|
-
}
|
|
2165
|
-
decode(message, options = {}) {
|
|
2166
|
-
let decodeResult = this.defaultResult();
|
|
2167
|
-
decodeResult.decoder.name = this.name;
|
|
2168
|
-
decodeResult.formatted.description = "Free Text";
|
|
2169
|
-
decodeResult.message = message;
|
|
2170
|
-
decodeResult.remaining.text = "";
|
|
2171
|
-
const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
|
|
2172
|
-
decodeResult.decoded = true;
|
|
2173
|
-
decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
|
|
2174
|
-
if (decodeResult.formatted.items.length === 0) {
|
|
2175
|
-
if (options?.debug) {
|
|
2176
|
-
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2177
|
-
}
|
|
2178
|
-
decodeResult.remaining.text = message.text;
|
|
2179
|
-
decodeResult.decoded = false;
|
|
2180
|
-
decodeResult.decoder.decodeLevel = "none";
|
|
2181
|
-
}
|
|
2182
|
-
return decodeResult;
|
|
2183
|
-
}
|
|
2184
|
-
};
|
|
2185
|
-
|
|
2186
|
-
// lib/plugins/Label_H1_INI.ts
|
|
2187
|
-
var Label_H1_INI = class extends DecoderPlugin {
|
|
2188
|
-
// eslint-disable-line camelcase
|
|
2189
|
-
name = "label-h1-ini";
|
|
2190
|
-
qualifiers() {
|
|
2191
|
-
return {
|
|
2192
|
-
labels: ["H1"],
|
|
2193
|
-
preambles: ["INI", "- #MDINI"]
|
|
2194
|
-
};
|
|
2195
|
-
}
|
|
2196
|
-
decode(message, options = {}) {
|
|
2197
|
-
const decodeResult = this.defaultResult();
|
|
2198
|
-
decodeResult.decoder.name = this.name;
|
|
2199
|
-
decodeResult.formatted.description = "Flight Plan Initial Report";
|
|
2200
|
-
decodeResult.message = message;
|
|
2201
|
-
decodeResult.remaining.text = "";
|
|
2202
|
-
const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
|
|
2203
|
-
decodeResult.decoded = true;
|
|
2204
|
-
decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
|
|
2205
|
-
if (decodeResult.formatted.items.length === 0) {
|
|
2206
|
-
if (options?.debug) {
|
|
2207
|
-
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2208
|
-
}
|
|
2209
|
-
decodeResult.remaining.text = message.text;
|
|
2210
|
-
decodeResult.decoded = false;
|
|
2211
|
-
decodeResult.decoder.decodeLevel = "none";
|
|
2212
|
-
}
|
|
2213
|
-
return decodeResult;
|
|
2214
|
-
}
|
|
2215
|
-
};
|
|
2216
|
-
|
|
2217
|
-
// lib/plugins/Label_H1_OHMA.ts
|
|
2218
|
-
var zlib = __toESM(require("minizlib"));
|
|
2219
|
-
var Label_H1_OHMA = class extends DecoderPlugin {
|
|
2220
|
-
name = "label-h1-ohma";
|
|
2221
|
-
qualifiers() {
|
|
2222
|
-
return {
|
|
2223
|
-
labels: ["H1"],
|
|
2224
|
-
preambles: ["OHMA", "/RTNBOCR.OHMA", "#T1B/RTNBOCR.OHMA"]
|
|
2225
|
-
};
|
|
2226
|
-
}
|
|
2227
|
-
decode(message, options = {}) {
|
|
2228
|
-
let decodeResult = this.defaultResult();
|
|
2229
|
-
decodeResult.decoder.name = this.name;
|
|
2230
|
-
decodeResult.formatted.description = "OHMA Message";
|
|
2231
|
-
decodeResult.message = message;
|
|
2232
|
-
decodeResult.remaining.text = "";
|
|
2233
|
-
const data = message.text.split("OHMA")[1];
|
|
2234
|
-
try {
|
|
2235
|
-
const compressedBuffer = Buffer.from(data, "base64");
|
|
2236
|
-
const decompress = new zlib.Inflate({ windowBits: 15 });
|
|
2237
|
-
decompress.write(compressedBuffer);
|
|
2238
|
-
decompress.flush(zlib.constants.Z_SYNC_FLUSH);
|
|
2239
|
-
const result = decompress.read();
|
|
2240
|
-
const jsonText = result.toString();
|
|
2241
|
-
let formattedMsg;
|
|
2242
|
-
let jsonMessage;
|
|
2243
|
-
try {
|
|
2244
|
-
jsonMessage = JSON.parse(jsonText).message;
|
|
2245
|
-
} catch {
|
|
2246
|
-
jsonMessage = jsonText;
|
|
2247
|
-
}
|
|
2248
|
-
try {
|
|
2249
|
-
const ohmaMsg = JSON.parse(jsonMessage);
|
|
2250
|
-
formattedMsg = JSON.stringify(ohmaMsg, null, 2);
|
|
2251
|
-
} catch {
|
|
2252
|
-
formattedMsg = jsonMessage;
|
|
2253
|
-
}
|
|
2254
|
-
decodeResult.decoded = true;
|
|
2255
|
-
decodeResult.decoder.decodeLevel = "full";
|
|
2256
|
-
decodeResult.raw.ohma = jsonText;
|
|
2257
|
-
decodeResult.formatted.items.push({
|
|
2258
|
-
type: "ohma",
|
|
2259
|
-
code: "OHMA",
|
|
2260
|
-
label: "OHMA Downlink",
|
|
2261
|
-
value: formattedMsg
|
|
2262
|
-
});
|
|
2263
|
-
} catch (e) {
|
|
2264
|
-
if (options.debug) {
|
|
2265
|
-
console.log(`Decoder: Unknown H1 OHMA message: ${message.text}`, e);
|
|
2266
|
-
}
|
|
2267
|
-
decodeResult.remaining.text += message.text;
|
|
2268
|
-
decodeResult.decoded = false;
|
|
2269
|
-
decodeResult.decoder.decodeLevel = "none";
|
|
2270
|
-
}
|
|
2271
|
-
return decodeResult;
|
|
2272
|
-
}
|
|
2273
|
-
};
|
|
2274
|
-
|
|
2275
|
-
// lib/plugins/Label_H1_POS.ts
|
|
2276
|
-
var Label_H1_POS = class extends DecoderPlugin {
|
|
2277
|
-
name = "label-h1-pos";
|
|
2278
|
-
qualifiers() {
|
|
2279
|
-
return {
|
|
2280
|
-
labels: ["H1", "4J"],
|
|
2281
|
-
preambles: ["POS", "#M1BPOS", "/.POS"]
|
|
2282
|
-
//TODO - support data before #
|
|
2283
|
-
};
|
|
2284
|
-
}
|
|
2285
|
-
decode(message, options = {}) {
|
|
2286
|
-
let decodeResult = this.defaultResult();
|
|
2287
|
-
decodeResult.decoder.name = this.name;
|
|
2288
|
-
decodeResult.formatted.description = "Position Report";
|
|
2289
|
-
decodeResult.message = message;
|
|
2290
|
-
decodeResult.remaining.text = "";
|
|
2291
|
-
const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
|
|
2292
|
-
decodeResult.decoded = true;
|
|
2293
|
-
decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
|
|
2847
|
+
const decoded = H1Helper.decodeH1Message(decodeResult, msg);
|
|
2848
|
+
decodeResult.decoded = decoded;
|
|
2849
|
+
decodeResult.decoder.decodeLevel = decodeResult.remaining.text.length === 0 ? "full" : "partial";
|
|
2294
2850
|
if (decodeResult.formatted.items.length === 0) {
|
|
2295
|
-
if (options?.debug) {
|
|
2296
|
-
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2297
|
-
}
|
|
2298
|
-
decodeResult.remaining.text = message.text;
|
|
2299
|
-
decodeResult.decoded = false;
|
|
2300
|
-
decodeResult.decoder.decodeLevel = "none";
|
|
2301
|
-
}
|
|
2302
|
-
return decodeResult;
|
|
2303
|
-
}
|
|
2304
|
-
};
|
|
2305
|
-
|
|
2306
|
-
// lib/plugins/Label_H1_WRN.ts
|
|
2307
|
-
var Label_H1_WRN = class extends DecoderPlugin {
|
|
2308
|
-
name = "label-h1-wrn";
|
|
2309
|
-
qualifiers() {
|
|
2310
|
-
return {
|
|
2311
|
-
labels: ["H1"],
|
|
2312
|
-
preambles: ["WRN", "#CFBWRN"]
|
|
2313
|
-
};
|
|
2314
|
-
}
|
|
2315
|
-
decode(message, options = {}) {
|
|
2316
|
-
let decodeResult = this.defaultResult();
|
|
2317
|
-
decodeResult.decoder.name = this.name;
|
|
2318
|
-
decodeResult.formatted.description = "Warning Message";
|
|
2319
|
-
decodeResult.message = message;
|
|
2320
|
-
const parts = message.text.split("/WN");
|
|
2321
|
-
if (parts.length > 1) {
|
|
2322
|
-
decodeResult.remaining.text = "";
|
|
2323
|
-
const fields = parts[0].split("/");
|
|
2324
|
-
for (let i = 1; i < fields.length; i++) {
|
|
2325
|
-
const field = fields[i];
|
|
2326
|
-
if (field.startsWith("PN")) {
|
|
2327
|
-
processUnknown2(decodeResult, "/" + field);
|
|
2328
|
-
} else {
|
|
2329
|
-
processUnknown2(decodeResult, "/" + field);
|
|
2330
|
-
}
|
|
2331
|
-
}
|
|
2332
|
-
const data = parts[1].substring(0, 20);
|
|
2333
|
-
const msg = parts[1].substring(20);
|
|
2334
|
-
const datetime = data.substring(0, 12);
|
|
2335
|
-
const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
|
|
2336
|
-
processUnknown2(decodeResult, data.substring(12));
|
|
2337
|
-
decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
|
|
2338
|
-
decodeResult.raw.warning_message = msg;
|
|
2339
|
-
decodeResult.formatted.items.push({
|
|
2340
|
-
type: "warning",
|
|
2341
|
-
code: "WRN",
|
|
2342
|
-
label: "Warning Message",
|
|
2343
|
-
value: decodeResult.raw.warning_message
|
|
2344
|
-
});
|
|
2345
|
-
decodeResult.decoded = true;
|
|
2346
|
-
decodeResult.decoder.decodeLevel = "partial";
|
|
2347
|
-
} else {
|
|
2348
2851
|
if (options.debug) {
|
|
2349
2852
|
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2350
2853
|
}
|
|
@@ -2355,9 +2858,6 @@ var Label_H1_WRN = class extends DecoderPlugin {
|
|
|
2355
2858
|
return decodeResult;
|
|
2356
2859
|
}
|
|
2357
2860
|
};
|
|
2358
|
-
function processUnknown2(decodeResult, value) {
|
|
2359
|
-
decodeResult.remaining.text += value;
|
|
2360
|
-
}
|
|
2361
2861
|
|
|
2362
2862
|
// lib/plugins/Label_HX.ts
|
|
2363
2863
|
var Label_HX = class extends DecoderPlugin {
|
|
@@ -2402,7 +2902,7 @@ var Label_HX = class extends DecoderPlugin {
|
|
|
2402
2902
|
});
|
|
2403
2903
|
}
|
|
2404
2904
|
if (decodeResult.decoded) {
|
|
2405
|
-
if (decodeResult.remaining.text
|
|
2905
|
+
if (!decodeResult.remaining.text)
|
|
2406
2906
|
decodeResult.decoder.decodeLevel = "full";
|
|
2407
2907
|
else
|
|
2408
2908
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -2557,7 +3057,7 @@ var Label_QR = class extends DecoderPlugin {
|
|
|
2557
3057
|
}
|
|
2558
3058
|
];
|
|
2559
3059
|
decodeResult.decoded = true;
|
|
2560
|
-
if (decodeResult.remaining.text
|
|
3060
|
+
if (!decodeResult.remaining.text)
|
|
2561
3061
|
decodeResult.decoder.decodeLevel = "full";
|
|
2562
3062
|
else
|
|
2563
3063
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -2602,7 +3102,7 @@ var Label_QP = class extends DecoderPlugin {
|
|
|
2602
3102
|
}
|
|
2603
3103
|
];
|
|
2604
3104
|
decodeResult.decoded = true;
|
|
2605
|
-
if (decodeResult.remaining.text
|
|
3105
|
+
if (!decodeResult.remaining.text)
|
|
2606
3106
|
decodeResult.decoder.decodeLevel = "full";
|
|
2607
3107
|
else
|
|
2608
3108
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -2647,7 +3147,7 @@ var Label_QS = class extends DecoderPlugin {
|
|
|
2647
3147
|
}
|
|
2648
3148
|
];
|
|
2649
3149
|
decodeResult.decoded = true;
|
|
2650
|
-
if (decodeResult.remaining.text
|
|
3150
|
+
if (!decodeResult.remaining.text)
|
|
2651
3151
|
decodeResult.decoder.decodeLevel = "full";
|
|
2652
3152
|
else
|
|
2653
3153
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -2709,7 +3209,7 @@ var Label_QQ = class extends DecoderPlugin {
|
|
|
2709
3209
|
});
|
|
2710
3210
|
}
|
|
2711
3211
|
decodeResult.decoded = true;
|
|
2712
|
-
if (decodeResult.remaining.text
|
|
3212
|
+
if (!decodeResult.remaining.text)
|
|
2713
3213
|
decodeResult.decoder.decodeLevel = "full";
|
|
2714
3214
|
else
|
|
2715
3215
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -3529,32 +4029,38 @@ var MessageDecoder = class {
|
|
|
3529
4029
|
this.plugins = [];
|
|
3530
4030
|
this.debug = false;
|
|
3531
4031
|
this.registerPlugin(new Label_ColonComma(this));
|
|
3532
|
-
this.registerPlugin(new
|
|
4032
|
+
this.registerPlugin(new Label_5Z_Slash(this));
|
|
3533
4033
|
this.registerPlugin(new Label_10_LDR(this));
|
|
3534
4034
|
this.registerPlugin(new Label_10_POS(this));
|
|
3535
4035
|
this.registerPlugin(new Label_10_Slash(this));
|
|
3536
4036
|
this.registerPlugin(new Label_12_N_Space(this));
|
|
4037
|
+
this.registerPlugin(new Label_13Through18_Slash(this));
|
|
3537
4038
|
this.registerPlugin(new Label_15(this));
|
|
3538
4039
|
this.registerPlugin(new Label_15_FST(this));
|
|
3539
4040
|
this.registerPlugin(new Label_16_N_Space(this));
|
|
3540
4041
|
this.registerPlugin(new Label_20_POS(this));
|
|
3541
4042
|
this.registerPlugin(new Label_21_POS(this));
|
|
4043
|
+
this.registerPlugin(new Label_24_Slash(this));
|
|
3542
4044
|
this.registerPlugin(new Label_30_Slash_EA(this));
|
|
3543
4045
|
this.registerPlugin(new Label_44_ETA(this));
|
|
3544
4046
|
this.registerPlugin(new Label_44_IN(this));
|
|
3545
4047
|
this.registerPlugin(new Label_44_OFF(this));
|
|
3546
4048
|
this.registerPlugin(new Label_44_ON(this));
|
|
3547
4049
|
this.registerPlugin(new Label_44_POS(this));
|
|
4050
|
+
this.registerPlugin(new Label_4A(this));
|
|
4051
|
+
this.registerPlugin(new Label_4A_01(this));
|
|
4052
|
+
this.registerPlugin(new Label_4A_DIS(this));
|
|
4053
|
+
this.registerPlugin(new Label_4A_DOOR(this));
|
|
4054
|
+
this.registerPlugin(new Label_4A_Slash_01(this));
|
|
4055
|
+
this.registerPlugin(new Label_4N(this));
|
|
3548
4056
|
this.registerPlugin(new Label_B6_Forwardslash(this));
|
|
3549
|
-
this.registerPlugin(new Label_H1_FPN(this));
|
|
3550
4057
|
this.registerPlugin(new Label_H1_FLR(this));
|
|
3551
|
-
this.registerPlugin(new Label_H1_FTX(this));
|
|
3552
|
-
this.registerPlugin(new Label_H1_INI(this));
|
|
3553
4058
|
this.registerPlugin(new Label_H1_OHMA(this));
|
|
3554
|
-
this.registerPlugin(new Label_H1_POS(this));
|
|
3555
4059
|
this.registerPlugin(new Label_H1_WRN(this));
|
|
4060
|
+
this.registerPlugin(new Label_H1(this));
|
|
3556
4061
|
this.registerPlugin(new Label_HX(this));
|
|
3557
4062
|
this.registerPlugin(new Label_80(this));
|
|
4063
|
+
this.registerPlugin(new Label_83(this));
|
|
3558
4064
|
this.registerPlugin(new Label_8E(this));
|
|
3559
4065
|
this.registerPlugin(new Label_1M_Slash(this));
|
|
3560
4066
|
this.registerPlugin(new Label_SQ(this));
|
|
@@ -3599,29 +4105,30 @@ var MessageDecoder = class {
|
|
|
3599
4105
|
console.log("Usable plugins");
|
|
3600
4106
|
console.log(usablePlugins);
|
|
3601
4107
|
}
|
|
3602
|
-
let result
|
|
3603
|
-
|
|
3604
|
-
|
|
4108
|
+
let result = {
|
|
4109
|
+
decoded: false,
|
|
4110
|
+
error: "No known decoder plugin for this message",
|
|
4111
|
+
decoder: {
|
|
4112
|
+
name: "none",
|
|
4113
|
+
type: "none",
|
|
4114
|
+
decodeLevel: "none"
|
|
4115
|
+
},
|
|
4116
|
+
message,
|
|
4117
|
+
remaining: {
|
|
4118
|
+
text: message.text
|
|
4119
|
+
},
|
|
4120
|
+
raw: {},
|
|
4121
|
+
formatted: {
|
|
4122
|
+
description: "Not Decoded",
|
|
4123
|
+
items: []
|
|
4124
|
+
}
|
|
4125
|
+
};
|
|
4126
|
+
for (let i = 0; i < usablePlugins.length; i++) {
|
|
4127
|
+
const plugin = usablePlugins[i];
|
|
3605
4128
|
result = plugin.decode(message);
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
error: "No known decoder plugin for this message",
|
|
3610
|
-
decoder: {
|
|
3611
|
-
name: "none",
|
|
3612
|
-
type: "none",
|
|
3613
|
-
decodeLevel: "none"
|
|
3614
|
-
},
|
|
3615
|
-
message,
|
|
3616
|
-
remaining: {
|
|
3617
|
-
text: message.text
|
|
3618
|
-
},
|
|
3619
|
-
raw: {},
|
|
3620
|
-
formatted: {
|
|
3621
|
-
description: "Not Decoded",
|
|
3622
|
-
items: []
|
|
3623
|
-
}
|
|
3624
|
-
};
|
|
4129
|
+
if (result.decoded) {
|
|
4130
|
+
break;
|
|
4131
|
+
}
|
|
3625
4132
|
}
|
|
3626
4133
|
if (options.debug) {
|
|
3627
4134
|
console.log("Result");
|