@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.mjs
CHANGED
|
@@ -12,6 +12,74 @@ var IcaoDecoder = class {
|
|
|
12
12
|
}
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
// lib/DateTimeUtils.ts
|
|
16
|
+
var DateTimeUtils = class {
|
|
17
|
+
// Expects a four digit UTC time string (HHMM)
|
|
18
|
+
static UTCToString(UTCString) {
|
|
19
|
+
let utcDate = /* @__PURE__ */ new Date();
|
|
20
|
+
utcDate.setUTCHours(+UTCString.substr(0, 2), +UTCString.substr(2, 2), 0);
|
|
21
|
+
return utcDate.toTimeString();
|
|
22
|
+
}
|
|
23
|
+
// Expects a six digit date string and a four digit UTC time string
|
|
24
|
+
// (DDMMYY) (HHMM)
|
|
25
|
+
static UTCDateTimeToString(dateString, timeString) {
|
|
26
|
+
let utcDate = /* @__PURE__ */ new Date();
|
|
27
|
+
utcDate.setUTCDate(+dateString.substr(0, 2));
|
|
28
|
+
utcDate.setUTCMonth(+dateString.substr(2, 2));
|
|
29
|
+
if (dateString.length === 6) {
|
|
30
|
+
utcDate.setUTCFullYear(2e3 + +dateString.substr(4, 2));
|
|
31
|
+
}
|
|
32
|
+
if (timeString.length === 6) {
|
|
33
|
+
utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), +timeString.substr(4, 2));
|
|
34
|
+
} else {
|
|
35
|
+
utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), 0);
|
|
36
|
+
}
|
|
37
|
+
return utcDate.toUTCString();
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
*
|
|
41
|
+
* @param time HHMMSS
|
|
42
|
+
* @returns seconds since midnight
|
|
43
|
+
*/
|
|
44
|
+
static convertHHMMSSToTod(time) {
|
|
45
|
+
const h = Number(time.substring(0, 2));
|
|
46
|
+
const m = Number(time.substring(2, 4));
|
|
47
|
+
const s = Number(time.substring(4, 6));
|
|
48
|
+
const tod = h * 3600 + m * 60 + s;
|
|
49
|
+
return tod;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
*
|
|
53
|
+
* @param time HHMMSS
|
|
54
|
+
* @param date MMDDYY or MMDDYYYY
|
|
55
|
+
* @returns seconds since epoch
|
|
56
|
+
*/
|
|
57
|
+
static convertDateTimeToEpoch(time, date) {
|
|
58
|
+
if (date.length === 6) {
|
|
59
|
+
date = date.substring(0, 4) + `20${date.substring(4, 6)}`;
|
|
60
|
+
}
|
|
61
|
+
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`;
|
|
62
|
+
const millis = Date.parse(timestamp);
|
|
63
|
+
return millis / 1e3;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Converts a timestamp to a string
|
|
67
|
+
*
|
|
68
|
+
* ISO-8601 format for 'epoch'
|
|
69
|
+
* HH:MM:SS for 'tod'
|
|
70
|
+
* @param time
|
|
71
|
+
* @param format
|
|
72
|
+
* @returns
|
|
73
|
+
*/
|
|
74
|
+
static timestampToString(time, format) {
|
|
75
|
+
const date = new Date(time * 1e3);
|
|
76
|
+
if (format == "tod") {
|
|
77
|
+
return date.toISOString().slice(11, 19);
|
|
78
|
+
}
|
|
79
|
+
return date.toISOString().slice(0, -5) + "Z";
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
15
83
|
// lib/DecoderPlugin.ts
|
|
16
84
|
var DecoderPlugin = class {
|
|
17
85
|
decoder;
|
|
@@ -117,10 +185,137 @@ var CoordinateUtils = class {
|
|
|
117
185
|
const lonDir = coords.longitude > 0 ? "E" : "W";
|
|
118
186
|
return `${Math.abs(coords.latitude).toFixed(3)} ${latDir}, ${Math.abs(coords.longitude).toFixed(3)} ${lonDir}`;
|
|
119
187
|
}
|
|
188
|
+
static getDirection(coord) {
|
|
189
|
+
if (coord.startsWith("N") || coord.startsWith("E")) {
|
|
190
|
+
return 1;
|
|
191
|
+
} else if (coord.startsWith("S") || coord.startsWith("W")) {
|
|
192
|
+
return -1;
|
|
193
|
+
}
|
|
194
|
+
return NaN;
|
|
195
|
+
}
|
|
196
|
+
static dmsToDecimalDegrees(degrees, minutes, seconds) {
|
|
197
|
+
return degrees + minutes / 60 + seconds / 3600;
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// lib/utils/route_utils.ts
|
|
202
|
+
var RouteUtils = class _RouteUtils {
|
|
203
|
+
static formatFlightState(state) {
|
|
204
|
+
switch (state) {
|
|
205
|
+
case "TO":
|
|
206
|
+
return "Takeoff";
|
|
207
|
+
case "IC":
|
|
208
|
+
return "Initial Climb";
|
|
209
|
+
case "CL":
|
|
210
|
+
return "Climb";
|
|
211
|
+
case "ER":
|
|
212
|
+
return "En Route";
|
|
213
|
+
case "DC":
|
|
214
|
+
return "Descent";
|
|
215
|
+
case "AP":
|
|
216
|
+
return "Approach";
|
|
217
|
+
default:
|
|
218
|
+
return `Unknown ${state}`;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
static routeToString(route) {
|
|
222
|
+
let str = "";
|
|
223
|
+
if (route.name) {
|
|
224
|
+
str += route.name;
|
|
225
|
+
}
|
|
226
|
+
if (route.runway) {
|
|
227
|
+
str += `(${route.runway})`;
|
|
228
|
+
}
|
|
229
|
+
if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
|
|
230
|
+
str += " starting at ";
|
|
231
|
+
} else if (str.length !== 0 && route.waypoints) {
|
|
232
|
+
str += ": ";
|
|
233
|
+
}
|
|
234
|
+
if (route.waypoints) {
|
|
235
|
+
str += _RouteUtils.waypointsToString(route.waypoints);
|
|
236
|
+
}
|
|
237
|
+
return str;
|
|
238
|
+
}
|
|
239
|
+
static waypointToString(waypoint) {
|
|
240
|
+
let s = waypoint.name;
|
|
241
|
+
if (waypoint.latitude && waypoint.longitude) {
|
|
242
|
+
s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
|
|
243
|
+
}
|
|
244
|
+
if (waypoint.offset) {
|
|
245
|
+
s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
|
|
246
|
+
}
|
|
247
|
+
if (waypoint.time && waypoint.timeFormat) {
|
|
248
|
+
s += `@${DateTimeUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
|
|
249
|
+
}
|
|
250
|
+
return s;
|
|
251
|
+
}
|
|
252
|
+
static getWaypoint(leg) {
|
|
253
|
+
const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
|
|
254
|
+
if (regex?.length == 4) {
|
|
255
|
+
return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
|
|
256
|
+
}
|
|
257
|
+
const waypoint = leg.split(",");
|
|
258
|
+
if (waypoint.length == 2) {
|
|
259
|
+
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
|
|
260
|
+
if (position) {
|
|
261
|
+
return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (leg.length == 13 || leg.length == 14) {
|
|
265
|
+
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
|
|
266
|
+
const name = waypoint.length == 2 ? waypoint[0] : "";
|
|
267
|
+
if (position) {
|
|
268
|
+
return { name, latitude: position.latitude, longitude: position.longitude };
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return { name: leg };
|
|
272
|
+
}
|
|
273
|
+
static waypointsToString(waypoints) {
|
|
274
|
+
let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
|
|
275
|
+
if (str.startsWith(" > ")) {
|
|
276
|
+
str = ">>" + str.slice(2);
|
|
277
|
+
}
|
|
278
|
+
return str;
|
|
279
|
+
}
|
|
120
280
|
};
|
|
121
281
|
|
|
122
282
|
// lib/utils/result_formatter.ts
|
|
123
283
|
var ResultFormatter = class {
|
|
284
|
+
static state_change(decodeResult, from, to) {
|
|
285
|
+
decodeResult.raw.state_change = {
|
|
286
|
+
from,
|
|
287
|
+
to
|
|
288
|
+
};
|
|
289
|
+
from = RouteUtils.formatFlightState(from);
|
|
290
|
+
to = RouteUtils.formatFlightState(to);
|
|
291
|
+
decodeResult.formatted.items.push({
|
|
292
|
+
type: "state_change",
|
|
293
|
+
code: "STATE_CHANGE",
|
|
294
|
+
label: "State Change",
|
|
295
|
+
value: `${from} -> ${to}`
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
static freetext(decodeResult, value) {
|
|
299
|
+
decodeResult.raw.freetext = value;
|
|
300
|
+
decodeResult.formatted.items.push({
|
|
301
|
+
type: "freetext",
|
|
302
|
+
code: "FREE_TEXT",
|
|
303
|
+
label: "Free Text",
|
|
304
|
+
value
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
static door_event(decodeResult, name, state) {
|
|
308
|
+
decodeResult.raw.door_event = {
|
|
309
|
+
door: name,
|
|
310
|
+
state
|
|
311
|
+
};
|
|
312
|
+
decodeResult.formatted.items.push({
|
|
313
|
+
type: "door_event",
|
|
314
|
+
code: "DOOR",
|
|
315
|
+
label: "Door Event",
|
|
316
|
+
value: `${name} ${state}`
|
|
317
|
+
});
|
|
318
|
+
}
|
|
124
319
|
static position(decodeResult, value) {
|
|
125
320
|
decodeResult.raw.position = value;
|
|
126
321
|
decodeResult.formatted.items.push({
|
|
@@ -141,16 +336,41 @@ var ResultFormatter = class {
|
|
|
141
336
|
}
|
|
142
337
|
static flightNumber(decodeResult, value) {
|
|
143
338
|
decodeResult.raw.flight_number = value;
|
|
339
|
+
decodeResult.formatted.items.push({
|
|
340
|
+
type: "flight_number",
|
|
341
|
+
code: "FLIGHT",
|
|
342
|
+
label: "Flight Number",
|
|
343
|
+
value: decodeResult.raw.flight_number
|
|
344
|
+
});
|
|
144
345
|
}
|
|
145
|
-
static
|
|
146
|
-
decodeResult.raw.
|
|
346
|
+
static callsign(decodeResult, value) {
|
|
347
|
+
decodeResult.raw.callsign = value;
|
|
147
348
|
decodeResult.formatted.items.push({
|
|
148
|
-
type: "
|
|
149
|
-
code: "
|
|
150
|
-
label: "
|
|
151
|
-
value: decodeResult.raw.
|
|
349
|
+
type: "callsign",
|
|
350
|
+
code: "CALLSIGN",
|
|
351
|
+
label: "Callsign",
|
|
352
|
+
value: decodeResult.raw.callsign
|
|
152
353
|
});
|
|
153
354
|
}
|
|
355
|
+
static departureAirport(decodeResult, value, type = "ICAO") {
|
|
356
|
+
if (type === "ICAO") {
|
|
357
|
+
decodeResult.raw.departure_icao = value;
|
|
358
|
+
decodeResult.formatted.items.push({
|
|
359
|
+
type: "icao",
|
|
360
|
+
code: "ORG",
|
|
361
|
+
label: "Origin",
|
|
362
|
+
value
|
|
363
|
+
});
|
|
364
|
+
} else {
|
|
365
|
+
decodeResult.raw.departure_iata = value;
|
|
366
|
+
decodeResult.formatted.items.push({
|
|
367
|
+
type: "iata",
|
|
368
|
+
code: "ORG",
|
|
369
|
+
label: "Origin",
|
|
370
|
+
value
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
}
|
|
154
374
|
static departureRunway(decodeResult, value) {
|
|
155
375
|
decodeResult.raw.departure_runway = value;
|
|
156
376
|
decodeResult.formatted.items.push({
|
|
@@ -160,24 +380,53 @@ var ResultFormatter = class {
|
|
|
160
380
|
value: decodeResult.raw.departure_runway
|
|
161
381
|
});
|
|
162
382
|
}
|
|
163
|
-
static arrivalAirport(decodeResult, value) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
383
|
+
static arrivalAirport(decodeResult, value, type = "ICAO") {
|
|
384
|
+
if (type === "ICAO") {
|
|
385
|
+
decodeResult.raw.arrival_icao = value;
|
|
386
|
+
decodeResult.formatted.items.push({
|
|
387
|
+
type: "icao",
|
|
388
|
+
code: "DST",
|
|
389
|
+
label: "Destination",
|
|
390
|
+
value
|
|
391
|
+
});
|
|
392
|
+
} else {
|
|
393
|
+
decodeResult.raw.arrival_iata = value;
|
|
394
|
+
decodeResult.formatted.items.push({
|
|
395
|
+
type: "iata",
|
|
396
|
+
code: "DST",
|
|
397
|
+
label: "Destination",
|
|
398
|
+
value
|
|
399
|
+
});
|
|
400
|
+
}
|
|
171
401
|
}
|
|
172
|
-
static
|
|
173
|
-
decodeResult.raw.
|
|
402
|
+
static alternateAirport(decodeResult, value) {
|
|
403
|
+
decodeResult.raw.alternate_icao = value;
|
|
174
404
|
decodeResult.formatted.items.push({
|
|
175
|
-
type: "
|
|
176
|
-
code: "
|
|
177
|
-
label: "
|
|
178
|
-
value:
|
|
405
|
+
type: "icao",
|
|
406
|
+
code: "ALT_DST",
|
|
407
|
+
label: "Alternate Destination",
|
|
408
|
+
value: decodeResult.raw.alternate_icao
|
|
179
409
|
});
|
|
180
410
|
}
|
|
411
|
+
static eta(decodeResult, time, type = "tod") {
|
|
412
|
+
if (type === "tod") {
|
|
413
|
+
decodeResult.raw.eta_time = time;
|
|
414
|
+
decodeResult.formatted.items.push({
|
|
415
|
+
type: "time_of_day",
|
|
416
|
+
code: "ETA",
|
|
417
|
+
label: "Estimated Time of Arrival",
|
|
418
|
+
value: DateTimeUtils.timestampToString(time, "tod")
|
|
419
|
+
});
|
|
420
|
+
} else {
|
|
421
|
+
decodeResult.raw.eta_date = time;
|
|
422
|
+
decodeResult.formatted.items.push({
|
|
423
|
+
type: "epoch",
|
|
424
|
+
code: "ETA",
|
|
425
|
+
label: "Estimated Time of Arrival",
|
|
426
|
+
value: DateTimeUtils.timestampToString(time, "epoch")
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
}
|
|
181
430
|
static arrivalRunway(decodeResult, value) {
|
|
182
431
|
decodeResult.raw.arrival_runway = value;
|
|
183
432
|
decodeResult.formatted.items.push({
|
|
@@ -187,6 +436,15 @@ var ResultFormatter = class {
|
|
|
187
436
|
value: decodeResult.raw.arrival_runway
|
|
188
437
|
});
|
|
189
438
|
}
|
|
439
|
+
static alternateRunway(decodeResult, value) {
|
|
440
|
+
decodeResult.raw.alternate_runway = value;
|
|
441
|
+
decodeResult.formatted.items.push({
|
|
442
|
+
type: "runway",
|
|
443
|
+
code: "ALT_ARWY",
|
|
444
|
+
label: "Alternate Runway",
|
|
445
|
+
value: decodeResult.raw.alternate_runway
|
|
446
|
+
});
|
|
447
|
+
}
|
|
190
448
|
static currentFuel(decodeResult, value) {
|
|
191
449
|
decodeResult.raw.fuel_on_board = value;
|
|
192
450
|
decodeResult.formatted.items.push({
|
|
@@ -220,16 +478,16 @@ var ResultFormatter = class {
|
|
|
220
478
|
type: "aircraft_groundspeed",
|
|
221
479
|
code: "GSPD",
|
|
222
480
|
label: "Aircraft Groundspeed",
|
|
223
|
-
value: `${decodeResult.raw.groundspeed}`
|
|
481
|
+
value: `${decodeResult.raw.groundspeed} knots`
|
|
224
482
|
});
|
|
225
483
|
}
|
|
226
484
|
static temperature(decodeResult, value) {
|
|
227
|
-
decodeResult.raw.outside_air_temperature = Number(value.
|
|
485
|
+
decodeResult.raw.outside_air_temperature = Number(value.replace("M", "-").replace("P", "+"));
|
|
228
486
|
decodeResult.formatted.items.push({
|
|
229
487
|
type: "outside_air_temperature",
|
|
230
488
|
code: "OATEMP",
|
|
231
489
|
label: "Outside Air Temperature (C)",
|
|
232
|
-
value: `${decodeResult.raw.outside_air_temperature}`
|
|
490
|
+
value: `${decodeResult.raw.outside_air_temperature} degrees`
|
|
233
491
|
});
|
|
234
492
|
}
|
|
235
493
|
static heading(decodeResult, value) {
|
|
@@ -241,14 +499,77 @@ var ResultFormatter = class {
|
|
|
241
499
|
value: `${decodeResult.raw.heading}`
|
|
242
500
|
});
|
|
243
501
|
}
|
|
502
|
+
static tail(decodeResult, value) {
|
|
503
|
+
decodeResult.raw.tail = value;
|
|
504
|
+
decodeResult.formatted.items.push({
|
|
505
|
+
type: "tail",
|
|
506
|
+
code: "TAIL",
|
|
507
|
+
label: "Tail",
|
|
508
|
+
value: decodeResult.raw.tail
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
static out(decodeResult, time) {
|
|
512
|
+
decodeResult.raw.out_time = time;
|
|
513
|
+
decodeResult.formatted.items.push({
|
|
514
|
+
type: "time_of_day",
|
|
515
|
+
code: "OUT",
|
|
516
|
+
label: "Out of Gate Time",
|
|
517
|
+
value: DateTimeUtils.timestampToString(time, "tod")
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
static off(decodeResult, time) {
|
|
521
|
+
decodeResult.raw.off_time = time;
|
|
522
|
+
decodeResult.formatted.items.push({
|
|
523
|
+
type: "time_of_day",
|
|
524
|
+
code: "OFF",
|
|
525
|
+
label: "Takeoff Time",
|
|
526
|
+
value: DateTimeUtils.timestampToString(time, "tod")
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
static on(decodeResult, time) {
|
|
530
|
+
decodeResult.raw.on_time = time;
|
|
531
|
+
decodeResult.formatted.items.push({
|
|
532
|
+
type: "time_of_day",
|
|
533
|
+
code: "ON",
|
|
534
|
+
label: "Landing Time",
|
|
535
|
+
value: DateTimeUtils.timestampToString(time, "tod")
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
static in(decodeResult, time) {
|
|
539
|
+
decodeResult.raw.in_time = time;
|
|
540
|
+
decodeResult.formatted.items.push({
|
|
541
|
+
type: "time_of_day",
|
|
542
|
+
code: "IN",
|
|
543
|
+
label: "In Gate Time",
|
|
544
|
+
value: DateTimeUtils.timestampToString(time, "tod")
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
static time_of_day(decodeResult, time) {
|
|
548
|
+
decodeResult.raw.time_of_day = time;
|
|
549
|
+
decodeResult.formatted.items.push({
|
|
550
|
+
type: "time_of_day",
|
|
551
|
+
code: "MSG_TOD",
|
|
552
|
+
label: "Message Timestamp",
|
|
553
|
+
value: DateTimeUtils.timestampToString(time, "tod")
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
static text(decodeResult, text2) {
|
|
557
|
+
decodeResult.raw.text = text2;
|
|
558
|
+
decodeResult.formatted.items.push({
|
|
559
|
+
type: "text",
|
|
560
|
+
code: "TEXT",
|
|
561
|
+
label: "Text Message",
|
|
562
|
+
value: text2
|
|
563
|
+
});
|
|
564
|
+
}
|
|
244
565
|
static unknown(decodeResult, value) {
|
|
245
566
|
decodeResult.remaining.text += "," + value;
|
|
246
567
|
}
|
|
247
568
|
};
|
|
248
569
|
|
|
249
|
-
// lib/plugins/
|
|
250
|
-
var
|
|
251
|
-
name = "label-5z";
|
|
570
|
+
// lib/plugins/Label_5Z_Slash.ts
|
|
571
|
+
var Label_5Z_Slash = class extends DecoderPlugin {
|
|
572
|
+
name = "label-5z-slash";
|
|
252
573
|
descriptions = {
|
|
253
574
|
B1: "Request Weight and Balance",
|
|
254
575
|
B3: "Request Departure Clearance",
|
|
@@ -266,6 +587,7 @@ var Label_5Z = class extends DecoderPlugin {
|
|
|
266
587
|
D6: "From-To + Date",
|
|
267
588
|
D7: "From-To + Alternate + Time",
|
|
268
589
|
EO: "In Range",
|
|
590
|
+
ET: "Expected Time",
|
|
269
591
|
PW: "Position Weather",
|
|
270
592
|
RL: "Request Release",
|
|
271
593
|
R3: "Request HOWGOZIT Message",
|
|
@@ -276,48 +598,82 @@ var Label_5Z = class extends DecoderPlugin {
|
|
|
276
598
|
};
|
|
277
599
|
qualifiers() {
|
|
278
600
|
return {
|
|
279
|
-
labels: ["5Z"]
|
|
601
|
+
labels: ["5Z"],
|
|
602
|
+
preambles: ["/"]
|
|
280
603
|
};
|
|
281
604
|
}
|
|
282
605
|
decode(message, options = {}) {
|
|
283
606
|
const decodeResult = this.defaultResult();
|
|
284
607
|
decodeResult.decoder.name = this.name;
|
|
285
608
|
decodeResult.formatted.description = "Airline Designated Downlink";
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
609
|
+
const lines = message.text.split("\r\n");
|
|
610
|
+
if (lines[0] === "/TXT") {
|
|
611
|
+
ResultFormatter.text(decodeResult, lines.slice(1).join("\r\n"));
|
|
612
|
+
decodeResult.decoded = true;
|
|
613
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
614
|
+
return decodeResult;
|
|
615
|
+
}
|
|
616
|
+
const data = lines[0].split("/");
|
|
617
|
+
const header = data[1].split(" ");
|
|
618
|
+
const type = header[0];
|
|
619
|
+
const typeDescription = this.descriptions[type];
|
|
620
|
+
if (typeDescription) {
|
|
292
621
|
decodeResult.raw.airline = "United Airlines";
|
|
293
622
|
decodeResult.formatted.items.push({
|
|
294
623
|
type: "airline",
|
|
624
|
+
code: "AIRLINE",
|
|
295
625
|
label: "Airline",
|
|
296
626
|
value: "United Airlines"
|
|
297
627
|
});
|
|
298
628
|
decodeResult.raw.message_type = type;
|
|
299
629
|
decodeResult.formatted.items.push({
|
|
300
630
|
type: "message_type",
|
|
631
|
+
code: "MSG_TYPE",
|
|
301
632
|
label: "Message Type",
|
|
302
633
|
value: `${typeDescription} (${type})`
|
|
303
634
|
});
|
|
304
|
-
if (type === "B3") {
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
635
|
+
if (type === "B3" && data[1] === "B3 TO DATA REQ ") {
|
|
636
|
+
const info = data[2].split(" ");
|
|
637
|
+
ResultFormatter.departureAirport(decodeResult, info[1]);
|
|
638
|
+
ResultFormatter.arrivalAirport(decodeResult, info[2]);
|
|
639
|
+
decodeResult.raw.day_of_month = Number(info[3]);
|
|
640
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
|
|
641
|
+
ResultFormatter.arrivalRunway(decodeResult, info[5].slice(1));
|
|
642
|
+
decodeResult.remaining.text = data.slice(3).join("/");
|
|
643
|
+
} else if (type === "B3") {
|
|
644
|
+
ResultFormatter.departureAirport(decodeResult, header[1].substring(0, 3), "IATA");
|
|
645
|
+
ResultFormatter.arrivalAirport(decodeResult, header[1].substring(3), "IATA");
|
|
646
|
+
decodeResult.raw.day_of_month = Number(header[2]);
|
|
647
|
+
ResultFormatter.arrivalRunway(decodeResult, header[3].slice(1));
|
|
648
|
+
if (header.length > 4) {
|
|
649
|
+
decodeResult.remaining.text = header.slice(4).join(" ");
|
|
315
650
|
}
|
|
651
|
+
} else if (type === "C3" && data[1] === "C3 GATE REQ ") {
|
|
652
|
+
const info = data[2].split(" ");
|
|
653
|
+
ResultFormatter.departureAirport(decodeResult, info[1]);
|
|
654
|
+
ResultFormatter.arrivalAirport(decodeResult, info[2]);
|
|
655
|
+
decodeResult.raw.day_of_month = Number(info[3]);
|
|
656
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
|
|
657
|
+
decodeResult.remaining.text = info.slice(5).join(" ");
|
|
658
|
+
} else if (type === "C3") {
|
|
659
|
+
ResultFormatter.departureAirport(decodeResult, header[1].substring(0, 3), "IATA");
|
|
660
|
+
ResultFormatter.arrivalAirport(decodeResult, header[1].substring(3), "IATA");
|
|
661
|
+
} else if (type === "ET") {
|
|
662
|
+
const airports = data[2].split(" ");
|
|
663
|
+
ResultFormatter.departureAirport(decodeResult, airports[1]);
|
|
664
|
+
ResultFormatter.arrivalAirport(decodeResult, airports[2]);
|
|
665
|
+
decodeResult.raw.day_of_month = Number(airports[3]);
|
|
666
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(airports[4]));
|
|
667
|
+
const estimates = data[3].split(" ");
|
|
668
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(estimates[1] + "00"));
|
|
669
|
+
decodeResult.remaining.text = estimates[2];
|
|
316
670
|
} else {
|
|
317
|
-
|
|
671
|
+
if (options.debug) {
|
|
672
|
+
console.log(`Decoder: Unkown 5Z RDC format: ${message.text}`);
|
|
673
|
+
}
|
|
318
674
|
}
|
|
319
675
|
decodeResult.decoded = true;
|
|
320
|
-
decodeResult.decoder.decodeLevel = "partial";
|
|
676
|
+
decodeResult.decoder.decodeLevel = decodeResult.remaining.text ? "partial" : "full";
|
|
321
677
|
} else {
|
|
322
678
|
if (options.debug) {
|
|
323
679
|
console.log(`Decoder: Unknown 5Z message: ${message.text}`);
|
|
@@ -347,7 +703,7 @@ var Label_10_LDR = class extends DecoderPlugin {
|
|
|
347
703
|
decodeResult.message = message;
|
|
348
704
|
const parts = message.text.split(",");
|
|
349
705
|
if (parts.length < 17) {
|
|
350
|
-
if (options
|
|
706
|
+
if (options.debug) {
|
|
351
707
|
console.log(`Decoder: Unknown 10 message: ${message.text}`);
|
|
352
708
|
}
|
|
353
709
|
decodeResult.remaining.text = message.text;
|
|
@@ -365,8 +721,13 @@ var Label_10_LDR = class extends DecoderPlugin {
|
|
|
365
721
|
ResultFormatter.altitude(decodeResult, Number(parts[7]));
|
|
366
722
|
ResultFormatter.departureAirport(decodeResult, parts[9]);
|
|
367
723
|
ResultFormatter.arrivalAirport(decodeResult, parts[10]);
|
|
724
|
+
ResultFormatter.alternateAirport(decodeResult, parts[11]);
|
|
368
725
|
ResultFormatter.arrivalRunway(decodeResult, parts[12].split("/")[0]);
|
|
369
|
-
|
|
726
|
+
const altRwy = [parts[13].split("/")[0], parts[14].split("/")[0]].filter((r) => r != "").join(",");
|
|
727
|
+
if (altRwy != "") {
|
|
728
|
+
ResultFormatter.alternateRunway(decodeResult, altRwy);
|
|
729
|
+
}
|
|
730
|
+
decodeResult.remaining.text = [...parts.slice(0, 5), ...parts.slice(15)].join(",");
|
|
370
731
|
decodeResult.decoded = true;
|
|
371
732
|
decodeResult.decoder.decodeLevel = "partial";
|
|
372
733
|
return decodeResult;
|
|
@@ -390,7 +751,7 @@ var Label_10_POS = class extends DecoderPlugin {
|
|
|
390
751
|
decodeResult.message = message;
|
|
391
752
|
const parts = message.text.split(",");
|
|
392
753
|
if (parts.length !== 12) {
|
|
393
|
-
if (options
|
|
754
|
+
if (options.debug) {
|
|
394
755
|
console.log(`Decoder: Unknown 10 message: ${message.text}`);
|
|
395
756
|
}
|
|
396
757
|
decodeResult.remaining.text = message.text;
|
|
@@ -413,153 +774,30 @@ var Label_10_POS = class extends DecoderPlugin {
|
|
|
413
774
|
}
|
|
414
775
|
};
|
|
415
776
|
|
|
416
|
-
// lib/
|
|
417
|
-
var
|
|
418
|
-
//
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
777
|
+
// lib/plugins/Label_10_Slash.ts
|
|
778
|
+
var Label_10_Slash = class extends DecoderPlugin {
|
|
779
|
+
// eslint-disable-line camelcase
|
|
780
|
+
name = "label-10-slash";
|
|
781
|
+
qualifiers() {
|
|
782
|
+
return {
|
|
783
|
+
labels: ["10"],
|
|
784
|
+
preambles: ["/"]
|
|
785
|
+
};
|
|
423
786
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
if (
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
return utcDate.toUTCString();
|
|
439
|
-
}
|
|
440
|
-
/**
|
|
441
|
-
*
|
|
442
|
-
* @param time HHMMSS
|
|
443
|
-
* @returns seconds since midnight
|
|
444
|
-
*/
|
|
445
|
-
static convertHHMMSSToTod(time) {
|
|
446
|
-
const h = Number(time.substring(0, 2));
|
|
447
|
-
const m = Number(time.substring(2, 4));
|
|
448
|
-
const s = Number(time.substring(4, 6));
|
|
449
|
-
const tod = h * 3600 + m * 60 + s;
|
|
450
|
-
return tod;
|
|
451
|
-
}
|
|
452
|
-
/**
|
|
453
|
-
*
|
|
454
|
-
* @param time HHMMSS
|
|
455
|
-
* @param date MMDDYY or MMDDYYYY
|
|
456
|
-
* @returns seconds since epoch
|
|
457
|
-
*/
|
|
458
|
-
static convertDateTimeToEpoch(time, date) {
|
|
459
|
-
if (date.length === 6) {
|
|
460
|
-
date = date.substring(0, 4) + `20${date.substring(4, 6)}`;
|
|
461
|
-
}
|
|
462
|
-
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`;
|
|
463
|
-
const millis = Date.parse(timestamp);
|
|
464
|
-
return millis / 1e3;
|
|
465
|
-
}
|
|
466
|
-
};
|
|
467
|
-
|
|
468
|
-
// lib/utils/route_utils.ts
|
|
469
|
-
var RouteUtils = class _RouteUtils {
|
|
470
|
-
static routeToString(route) {
|
|
471
|
-
let str = "";
|
|
472
|
-
if (route.name) {
|
|
473
|
-
str += route.name;
|
|
474
|
-
}
|
|
475
|
-
if (route.runway) {
|
|
476
|
-
str += `(${route.runway})`;
|
|
477
|
-
}
|
|
478
|
-
if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
|
|
479
|
-
str += " starting at ";
|
|
480
|
-
} else if (str.length !== 0 && route.waypoints) {
|
|
481
|
-
str += ": ";
|
|
482
|
-
}
|
|
483
|
-
if (route.waypoints) {
|
|
484
|
-
str += _RouteUtils.waypointsToString(route.waypoints);
|
|
485
|
-
}
|
|
486
|
-
return str;
|
|
487
|
-
}
|
|
488
|
-
static waypointToString(waypoint) {
|
|
489
|
-
let s = waypoint.name;
|
|
490
|
-
if (waypoint.latitude && waypoint.longitude) {
|
|
491
|
-
s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
|
|
492
|
-
}
|
|
493
|
-
if (waypoint.offset) {
|
|
494
|
-
s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
|
|
495
|
-
}
|
|
496
|
-
if (waypoint.time && waypoint.timeFormat) {
|
|
497
|
-
s += `@${_RouteUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
|
|
498
|
-
}
|
|
499
|
-
return s;
|
|
500
|
-
}
|
|
501
|
-
static getWaypoint(leg) {
|
|
502
|
-
const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
|
|
503
|
-
if (regex?.length == 4) {
|
|
504
|
-
return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
|
|
505
|
-
}
|
|
506
|
-
const waypoint = leg.split(",");
|
|
507
|
-
if (waypoint.length == 2) {
|
|
508
|
-
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
|
|
509
|
-
if (position) {
|
|
510
|
-
return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
if (leg.length == 13 || leg.length == 14) {
|
|
514
|
-
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
|
|
515
|
-
const name = waypoint.length == 2 ? waypoint[0] : "";
|
|
516
|
-
if (position) {
|
|
517
|
-
return { name, latitude: position.latitude, longitude: position.longitude };
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
return { name: leg };
|
|
521
|
-
}
|
|
522
|
-
// move out if we want public
|
|
523
|
-
static timestampToString(time, format) {
|
|
524
|
-
const date = new Date(time * 1e3);
|
|
525
|
-
if (format == "tod") {
|
|
526
|
-
return date.toISOString().slice(11, 19);
|
|
527
|
-
}
|
|
528
|
-
return date.toISOString().slice(0, -5) + "Z";
|
|
529
|
-
}
|
|
530
|
-
static waypointsToString(waypoints) {
|
|
531
|
-
let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
|
|
532
|
-
if (str.startsWith(" > ")) {
|
|
533
|
-
str = ">>" + str.slice(2);
|
|
534
|
-
}
|
|
535
|
-
return str;
|
|
536
|
-
}
|
|
537
|
-
};
|
|
538
|
-
|
|
539
|
-
// lib/plugins/Label_10_Slash.ts
|
|
540
|
-
var Label_10_Slash = class extends DecoderPlugin {
|
|
541
|
-
// eslint-disable-line camelcase
|
|
542
|
-
name = "label-10-slash";
|
|
543
|
-
qualifiers() {
|
|
544
|
-
return {
|
|
545
|
-
labels: ["10"],
|
|
546
|
-
preambles: ["/"]
|
|
547
|
-
};
|
|
548
|
-
}
|
|
549
|
-
decode(message, options = {}) {
|
|
550
|
-
const decodeResult = this.defaultResult();
|
|
551
|
-
decodeResult.decoder.name = this.name;
|
|
552
|
-
decodeResult.formatted.description = "Position Report";
|
|
553
|
-
decodeResult.message = message;
|
|
554
|
-
const parts = message.text.split("/");
|
|
555
|
-
if (parts.length < 17) {
|
|
556
|
-
if (options?.debug) {
|
|
557
|
-
console.log(`Decoder: Unknown 10 message: ${message.text}`);
|
|
558
|
-
}
|
|
559
|
-
decodeResult.remaining.text = message.text;
|
|
560
|
-
decodeResult.decoded = false;
|
|
561
|
-
decodeResult.decoder.decodeLevel = "none";
|
|
562
|
-
return decodeResult;
|
|
787
|
+
decode(message, options = {}) {
|
|
788
|
+
const decodeResult = this.defaultResult();
|
|
789
|
+
decodeResult.decoder.name = this.name;
|
|
790
|
+
decodeResult.formatted.description = "Position Report";
|
|
791
|
+
decodeResult.message = message;
|
|
792
|
+
const parts = message.text.split("/");
|
|
793
|
+
if (parts.length < 17) {
|
|
794
|
+
if (options.debug) {
|
|
795
|
+
console.log(`Decoder: Unknown 10 message: ${message.text}`);
|
|
796
|
+
}
|
|
797
|
+
decodeResult.remaining.text = message.text;
|
|
798
|
+
decodeResult.decoded = false;
|
|
799
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
800
|
+
return decodeResult;
|
|
563
801
|
}
|
|
564
802
|
const lat = parts[1];
|
|
565
803
|
const lon = parts[2];
|
|
@@ -571,7 +809,7 @@ var Label_10_Slash = class extends DecoderPlugin {
|
|
|
571
809
|
ResultFormatter.heading(decodeResult, Number(parts[5]));
|
|
572
810
|
ResultFormatter.altitude(decodeResult, 100 * Number(parts[6]));
|
|
573
811
|
ResultFormatter.arrivalAirport(decodeResult, parts[7]);
|
|
574
|
-
ResultFormatter.eta(decodeResult, parts[8] + "00");
|
|
812
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[8] + "00"));
|
|
575
813
|
const waypoints = [{
|
|
576
814
|
name: parts[11]
|
|
577
815
|
}, {
|
|
@@ -648,6 +886,97 @@ var Label_12_N_Space = class extends DecoderPlugin {
|
|
|
648
886
|
}
|
|
649
887
|
};
|
|
650
888
|
|
|
889
|
+
// lib/plugins/Label_13Through18_Slash.ts
|
|
890
|
+
var Label_13Through18_Slash = class extends DecoderPlugin {
|
|
891
|
+
// eslint-disable-line camelcase
|
|
892
|
+
name = "label-13-18-slash";
|
|
893
|
+
qualifiers() {
|
|
894
|
+
return {
|
|
895
|
+
labels: ["13", "14", "15", "16", "17", "18"],
|
|
896
|
+
preambles: ["/"]
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
decode(message, options = {}) {
|
|
900
|
+
const decodeResult = this.defaultResult();
|
|
901
|
+
decodeResult.decoder.name = this.name;
|
|
902
|
+
decodeResult.message = message;
|
|
903
|
+
const lines = message.text.split("\r\n");
|
|
904
|
+
const parts = lines[0].split("/");
|
|
905
|
+
const labelNumber = Number(parts[1].substring(0, 2));
|
|
906
|
+
decodeResult.formatted.description = getMsgType(labelNumber);
|
|
907
|
+
if (labelNumber !== 18 && parts.length !== 4 || labelNumber === 18 && parts.length !== 7) {
|
|
908
|
+
if (options?.debug) {
|
|
909
|
+
console.log(`Decoder: Unknown OOOI message: ${message.text}`);
|
|
910
|
+
}
|
|
911
|
+
decodeResult.remaining.text = message.text;
|
|
912
|
+
decodeResult.decoded = false;
|
|
913
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
914
|
+
return decodeResult;
|
|
915
|
+
}
|
|
916
|
+
decodeResult.remaining.text = "";
|
|
917
|
+
const data = parts[2].split(" ");
|
|
918
|
+
ResultFormatter.departureAirport(decodeResult, data[1]);
|
|
919
|
+
ResultFormatter.arrivalAirport(decodeResult, data[2]);
|
|
920
|
+
decodeResult.raw.day_of_month = Number(data[3]);
|
|
921
|
+
const time = DateTimeUtils.convertHHMMSSToTod(data[4]);
|
|
922
|
+
if (labelNumber === 13) {
|
|
923
|
+
ResultFormatter.out(decodeResult, time);
|
|
924
|
+
} else if (labelNumber === 14) {
|
|
925
|
+
ResultFormatter.off(decodeResult, time);
|
|
926
|
+
} else if (labelNumber === 15) {
|
|
927
|
+
ResultFormatter.on(decodeResult, time);
|
|
928
|
+
} else if (labelNumber === 16) {
|
|
929
|
+
ResultFormatter.in(decodeResult, time);
|
|
930
|
+
}
|
|
931
|
+
if (parts.length === 7) {
|
|
932
|
+
decodeResult.remaining.text += parts.slice(4).join("/");
|
|
933
|
+
}
|
|
934
|
+
for (let i = 1; i < lines.length; i++) {
|
|
935
|
+
if (lines[i].startsWith("/LOC")) {
|
|
936
|
+
const location = lines[i].substring(5).split(",");
|
|
937
|
+
let position;
|
|
938
|
+
if (location[0].startsWith("+") || location[0].startsWith("-")) {
|
|
939
|
+
position = { latitude: Number(location[0]), longitude: Number(location[1]) };
|
|
940
|
+
} else {
|
|
941
|
+
position = {
|
|
942
|
+
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))),
|
|
943
|
+
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)))
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
if (!isNaN(position.latitude) && !isNaN(position.longitude)) {
|
|
947
|
+
ResultFormatter.position(decodeResult, position);
|
|
948
|
+
}
|
|
949
|
+
} else {
|
|
950
|
+
decodeResult.remaining.text += "\r\n" + lines[i];
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
decodeResult.decoded = true;
|
|
954
|
+
decodeResult.decoder.decodeLevel = decodeResult.remaining.text ? "partial" : "full";
|
|
955
|
+
return decodeResult;
|
|
956
|
+
}
|
|
957
|
+
};
|
|
958
|
+
function getMsgType(labelNumber) {
|
|
959
|
+
if (labelNumber === 13) {
|
|
960
|
+
return "Out of Gate Report";
|
|
961
|
+
}
|
|
962
|
+
if (labelNumber === 14) {
|
|
963
|
+
return "Takeoff Report";
|
|
964
|
+
}
|
|
965
|
+
if (labelNumber === 15) {
|
|
966
|
+
return "On Ground Report";
|
|
967
|
+
}
|
|
968
|
+
if (labelNumber === 16) {
|
|
969
|
+
return "In Gate Report";
|
|
970
|
+
}
|
|
971
|
+
if (labelNumber === 17) {
|
|
972
|
+
return "Post Report";
|
|
973
|
+
}
|
|
974
|
+
if (labelNumber === 18) {
|
|
975
|
+
return "Post Times Report";
|
|
976
|
+
}
|
|
977
|
+
return "Unknown";
|
|
978
|
+
}
|
|
979
|
+
|
|
651
980
|
// lib/plugins/Label_15.ts
|
|
652
981
|
var Label_15 = class extends DecoderPlugin {
|
|
653
982
|
name = "label-5z";
|
|
@@ -814,28 +1143,12 @@ var Label_1M_Slash = class extends DecoderPlugin {
|
|
|
814
1143
|
console.log(results);
|
|
815
1144
|
}
|
|
816
1145
|
decodeResult.raw.flight_number = results[0];
|
|
817
|
-
decodeResult
|
|
818
|
-
decodeResult
|
|
819
|
-
decodeResult
|
|
820
|
-
decodeResult
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
code: "ETA",
|
|
824
|
-
label: "Estimated Time of Arrival",
|
|
825
|
-
value: DateTimeUtils.UTCDateTimeToString(results[2], results[7])
|
|
826
|
-
});
|
|
827
|
-
decodeResult.formatted.items.push({
|
|
828
|
-
type: "destination",
|
|
829
|
-
code: "DST",
|
|
830
|
-
label: "Destination",
|
|
831
|
-
value: decodeResult.raw.arrival_icao
|
|
832
|
-
});
|
|
833
|
-
decodeResult.formatted.items.push({
|
|
834
|
-
type: "origin",
|
|
835
|
-
code: "ORG",
|
|
836
|
-
label: "Origin",
|
|
837
|
-
value: decodeResult.raw.departure_icao
|
|
838
|
-
});
|
|
1146
|
+
ResultFormatter.departureAirport(decodeResult, results[3]);
|
|
1147
|
+
ResultFormatter.arrivalAirport(decodeResult, results[4]);
|
|
1148
|
+
ResultFormatter.alternateAirport(decodeResult, results[5]);
|
|
1149
|
+
ResultFormatter.arrivalRunway(decodeResult, results[8].replace(results[4], ""));
|
|
1150
|
+
const yymmdd = results[2];
|
|
1151
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertDateTimeToEpoch(results[7] + "00", yymmdd.substring(2, 4) + yymmdd.substring(4, 6) + yymmdd.substring(0, 2)), "epoch");
|
|
839
1152
|
}
|
|
840
1153
|
decodeResult.decoded = true;
|
|
841
1154
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -859,11 +1172,11 @@ var Label_20_POS = class extends DecoderPlugin {
|
|
|
859
1172
|
decodeResult.message = message;
|
|
860
1173
|
decodeResult.raw.preamble = message.text.substring(0, 3);
|
|
861
1174
|
const content = message.text.substring(3);
|
|
862
|
-
console.log("Content: " + content);
|
|
863
1175
|
const fields = content.split(",");
|
|
864
|
-
console.log("Field Count: " + fields.length);
|
|
865
1176
|
if (fields.length == 11) {
|
|
866
|
-
|
|
1177
|
+
if (options.debug) {
|
|
1178
|
+
console.log(`DEBUG: ${this.name}: Variation 1 detected`);
|
|
1179
|
+
}
|
|
867
1180
|
const rawCoords = fields[0];
|
|
868
1181
|
decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
|
|
869
1182
|
if (decodeResult.raw.position) {
|
|
@@ -877,7 +1190,9 @@ var Label_20_POS = class extends DecoderPlugin {
|
|
|
877
1190
|
decodeResult.decoded = true;
|
|
878
1191
|
decodeResult.decoder.decodeLevel = "full";
|
|
879
1192
|
} else if (fields.length == 5) {
|
|
880
|
-
|
|
1193
|
+
if (options.debug) {
|
|
1194
|
+
console.log(`DEBUG: ${this.name}: Variation 2 detected`);
|
|
1195
|
+
}
|
|
881
1196
|
const rawCoords = fields[0];
|
|
882
1197
|
decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
|
|
883
1198
|
if (decodeResult.raw.position) {
|
|
@@ -891,7 +1206,9 @@ var Label_20_POS = class extends DecoderPlugin {
|
|
|
891
1206
|
decodeResult.decoded = true;
|
|
892
1207
|
decodeResult.decoder.decodeLevel = "full";
|
|
893
1208
|
} else {
|
|
894
|
-
|
|
1209
|
+
if (options.debug) {
|
|
1210
|
+
console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
|
|
1211
|
+
}
|
|
895
1212
|
decodeResult.decoded = false;
|
|
896
1213
|
decodeResult.decoder.decodeLevel = "none";
|
|
897
1214
|
}
|
|
@@ -915,25 +1232,25 @@ var Label_21_POS = class extends DecoderPlugin {
|
|
|
915
1232
|
decodeResult.message = message;
|
|
916
1233
|
decodeResult.raw.preamble = message.text.substring(0, 3);
|
|
917
1234
|
const content = message.text.substring(3);
|
|
918
|
-
console.log("Content: " + content);
|
|
919
1235
|
const fields = content.split(",");
|
|
920
|
-
console.log("Field Count: " + fields.length);
|
|
921
1236
|
if (fields.length == 9) {
|
|
922
1237
|
processPosition(decodeResult, fields[0].trim());
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
1238
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2]));
|
|
1239
|
+
ResultFormatter.altitude(decodeResult, Number(fields[3]));
|
|
1240
|
+
ResultFormatter.temperature(decodeResult, fields[6].replace(/ /g, ""));
|
|
1241
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[7]));
|
|
1242
|
+
ResultFormatter.arrivalAirport(decodeResult, fields[8]);
|
|
926
1243
|
decodeResult.remaining.text = [
|
|
927
1244
|
fields[1],
|
|
928
|
-
fields[2],
|
|
929
1245
|
fields[4],
|
|
930
|
-
fields[5]
|
|
931
|
-
fields[7]
|
|
1246
|
+
fields[5]
|
|
932
1247
|
].join(",");
|
|
933
1248
|
decodeResult.decoded = true;
|
|
934
1249
|
decodeResult.decoder.decodeLevel = "partial";
|
|
935
1250
|
} else {
|
|
936
|
-
|
|
1251
|
+
if (options.debug) {
|
|
1252
|
+
console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
|
|
1253
|
+
}
|
|
937
1254
|
decodeResult.decoded = false;
|
|
938
1255
|
decodeResult.decoder.decodeLevel = "none";
|
|
939
1256
|
}
|
|
@@ -942,7 +1259,7 @@ var Label_21_POS = class extends DecoderPlugin {
|
|
|
942
1259
|
};
|
|
943
1260
|
function processPosition(decodeResult, value) {
|
|
944
1261
|
if (value.length !== 16 && value[0] !== "N" && value[0] !== "S" && value[8] !== "W" && value[8] !== "E") {
|
|
945
|
-
return
|
|
1262
|
+
return;
|
|
946
1263
|
}
|
|
947
1264
|
const latDir = value[0] === "N" ? 1 : -1;
|
|
948
1265
|
const lonDir = value[8] === "E" ? 1 : -1;
|
|
@@ -950,45 +1267,52 @@ function processPosition(decodeResult, value) {
|
|
|
950
1267
|
latitude: latDir * Number(value.substring(1, 7)),
|
|
951
1268
|
longitude: lonDir * Number(value.substring(9, 15))
|
|
952
1269
|
};
|
|
953
|
-
|
|
954
|
-
decodeResult.raw.position = position;
|
|
955
|
-
decodeResult.formatted.items.push({
|
|
956
|
-
type: "aircraft_position",
|
|
957
|
-
code: "POS",
|
|
958
|
-
label: "Aircraft Position",
|
|
959
|
-
value: CoordinateUtils.coordinateString(position)
|
|
960
|
-
});
|
|
961
|
-
}
|
|
962
|
-
return !!position;
|
|
963
|
-
}
|
|
964
|
-
function processAlt(decodeResult, value) {
|
|
965
|
-
decodeResult.raw.altitude = Number(value);
|
|
966
|
-
decodeResult.formatted.items.push({
|
|
967
|
-
type: "altitude",
|
|
968
|
-
code: "ALT",
|
|
969
|
-
label: "Altitude",
|
|
970
|
-
value: `${decodeResult.raw.altitude} feet`
|
|
971
|
-
});
|
|
972
|
-
}
|
|
973
|
-
function processTemp(decodeResult, value) {
|
|
974
|
-
decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
|
|
975
|
-
decodeResult.formatted.items.push({
|
|
976
|
-
type: "outside_air_temperature",
|
|
977
|
-
code: "OATEMP",
|
|
978
|
-
label: "Outside Air Temperature (C)",
|
|
979
|
-
value: `${decodeResult.raw.outside_air_temperature}`
|
|
980
|
-
});
|
|
981
|
-
}
|
|
982
|
-
function processArrvApt(decodeResult, value) {
|
|
983
|
-
decodeResult.raw.arrival_icao = value;
|
|
984
|
-
decodeResult.formatted.items.push({
|
|
985
|
-
type: "destination",
|
|
986
|
-
code: "DST",
|
|
987
|
-
label: "Destination",
|
|
988
|
-
value: decodeResult.raw.arrival_icao
|
|
989
|
-
});
|
|
1270
|
+
ResultFormatter.position(decodeResult, position);
|
|
990
1271
|
}
|
|
991
1272
|
|
|
1273
|
+
// lib/plugins/Label_24_Slash.ts
|
|
1274
|
+
var Label_24_Slash = class extends DecoderPlugin {
|
|
1275
|
+
name = "label-24-slash";
|
|
1276
|
+
qualifiers() {
|
|
1277
|
+
return {
|
|
1278
|
+
labels: ["24"],
|
|
1279
|
+
preambles: ["/"]
|
|
1280
|
+
};
|
|
1281
|
+
}
|
|
1282
|
+
decode(message, options = {}) {
|
|
1283
|
+
const decodeResult = this.defaultResult();
|
|
1284
|
+
decodeResult.decoder.name = this.name;
|
|
1285
|
+
decodeResult.formatted.description = "Position Report";
|
|
1286
|
+
decodeResult.message = message;
|
|
1287
|
+
const fields = message.text.split("/");
|
|
1288
|
+
if (fields.length == 10 && fields[0] == "" && fields[9] == "") {
|
|
1289
|
+
const mmddyy = fields[1].substring(4, 6) + fields[1].substring(2, 4) + fields[1].substring(0, 2);
|
|
1290
|
+
const hhmmss = fields[2] + "00";
|
|
1291
|
+
decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(hhmmss, mmddyy);
|
|
1292
|
+
ResultFormatter.flightNumber(decodeResult, fields[3]);
|
|
1293
|
+
ResultFormatter.altitude(decodeResult, Number(fields[4]));
|
|
1294
|
+
const lat = fields[5];
|
|
1295
|
+
const lon = fields[6];
|
|
1296
|
+
const position = {
|
|
1297
|
+
latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1)),
|
|
1298
|
+
longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1))
|
|
1299
|
+
};
|
|
1300
|
+
ResultFormatter.position(decodeResult, position);
|
|
1301
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[8] + "00"));
|
|
1302
|
+
decodeResult.remaining.text = fields[7];
|
|
1303
|
+
decodeResult.decoded = true;
|
|
1304
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1305
|
+
} else {
|
|
1306
|
+
if (options.debug) {
|
|
1307
|
+
console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}. Message: ${message.text}`);
|
|
1308
|
+
}
|
|
1309
|
+
decodeResult.decoded = false;
|
|
1310
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1311
|
+
}
|
|
1312
|
+
return decodeResult;
|
|
1313
|
+
}
|
|
1314
|
+
};
|
|
1315
|
+
|
|
992
1316
|
// lib/plugins/Label_30_Slash_EA.ts
|
|
993
1317
|
var Label_30_Slash_EA = class extends DecoderPlugin {
|
|
994
1318
|
name = "label-30-slash-ea";
|
|
@@ -1010,20 +1334,9 @@ var Label_30_Slash_EA = class extends DecoderPlugin {
|
|
|
1010
1334
|
console.log(results);
|
|
1011
1335
|
}
|
|
1012
1336
|
}
|
|
1013
|
-
decodeResult.
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
label: "Estimated Time of Arrival",
|
|
1017
|
-
value: DateTimeUtils.UTCToString(results[0].substr(2, 4))
|
|
1018
|
-
});
|
|
1019
|
-
if (results[1].substr(0, 2) === "DS") {
|
|
1020
|
-
decodeResult.raw.arrival_icao = results[1].substr(2, 4);
|
|
1021
|
-
decodeResult.formatted.items.push({
|
|
1022
|
-
type: "destination",
|
|
1023
|
-
code: "DST",
|
|
1024
|
-
label: "Destination",
|
|
1025
|
-
value: decodeResult.raw.arrival_icao
|
|
1026
|
-
});
|
|
1337
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results[0].substr(2, 4) + "00"));
|
|
1338
|
+
if (results[1].substring(0, 2) === "DS") {
|
|
1339
|
+
ResultFormatter.arrivalAirport(decodeResult, results[1].substring(2, 6));
|
|
1027
1340
|
decodeResult.remaining.text = "/".concat(results[2]);
|
|
1028
1341
|
} else {
|
|
1029
1342
|
decodeResult.remaining.text = "/".concat(results[1], "/", results[2]);
|
|
@@ -1315,23 +1628,296 @@ var Label_44_POS = class extends DecoderPlugin {
|
|
|
1315
1628
|
}
|
|
1316
1629
|
};
|
|
1317
1630
|
|
|
1318
|
-
// lib/plugins/
|
|
1319
|
-
var
|
|
1320
|
-
name = "label-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1631
|
+
// lib/plugins/Label_4A.ts
|
|
1632
|
+
var Label_4A = class extends DecoderPlugin {
|
|
1633
|
+
name = "label-4a";
|
|
1634
|
+
qualifiers() {
|
|
1635
|
+
return {
|
|
1636
|
+
labels: ["4A"]
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1639
|
+
decode(message, options = {}) {
|
|
1640
|
+
const decodeResult = this.defaultResult();
|
|
1641
|
+
decodeResult.decoder.name = this.name;
|
|
1642
|
+
decodeResult.message = message;
|
|
1643
|
+
decodeResult.formatted.description = "Latest New Format";
|
|
1644
|
+
let text2 = message.text;
|
|
1645
|
+
if (text2.match(/^M\d{2}A\w{6}/)) {
|
|
1646
|
+
ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
|
|
1647
|
+
text2 = text2.substring(10);
|
|
1648
|
+
}
|
|
1649
|
+
decodeResult.decoded = true;
|
|
1650
|
+
const fields = text2.split(",");
|
|
1651
|
+
if (fields.length === 11) {
|
|
1652
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[0]));
|
|
1653
|
+
ResultFormatter.tail(decodeResult, fields[2].replace(".", ""));
|
|
1654
|
+
if (fields[3])
|
|
1655
|
+
ResultFormatter.callsign(decodeResult, fields[3]);
|
|
1656
|
+
ResultFormatter.departureAirport(decodeResult, fields[4]);
|
|
1657
|
+
ResultFormatter.arrivalAirport(decodeResult, fields[5]);
|
|
1658
|
+
ResultFormatter.altitude(decodeResult, text2.substring(48, 51) * 100);
|
|
1659
|
+
decodeResult.remaining.text = fields.slice(8).join(",");
|
|
1660
|
+
} else if (fields.length === 6) {
|
|
1661
|
+
if (fields[0].match(/^[NS]/)) {
|
|
1662
|
+
ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(fields[0].substring(0, 13)));
|
|
1663
|
+
let wp1 = {
|
|
1664
|
+
name: fields[0].substring(13).trim(),
|
|
1665
|
+
time: DateTimeUtils.convertHHMMSSToTod(fields[1].substring(0, 6)),
|
|
1666
|
+
timeFormat: "tod"
|
|
1667
|
+
};
|
|
1668
|
+
ResultFormatter.altitude(decodeResult, fields[1].substring(6, 9) * 100);
|
|
1669
|
+
let wp2 = {
|
|
1670
|
+
name: fields[1].substring(9).trim(),
|
|
1671
|
+
time: DateTimeUtils.convertHHMMSSToTod(fields[2]),
|
|
1672
|
+
timeFormat: "tod"
|
|
1673
|
+
};
|
|
1674
|
+
decodeResult.raw.route = { waypoints: [wp1, wp2] };
|
|
1675
|
+
decodeResult.formatted.items.push({
|
|
1676
|
+
type: "aircraft_route",
|
|
1677
|
+
code: "ROUTE",
|
|
1678
|
+
label: "Aircraft Route",
|
|
1679
|
+
value: RouteUtils.routeToString(decodeResult.raw.route)
|
|
1680
|
+
});
|
|
1681
|
+
ResultFormatter.temperature(decodeResult, fields[3]);
|
|
1682
|
+
decodeResult.remaining.text = fields.slice(4).join(",");
|
|
1683
|
+
} else {
|
|
1684
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[0]));
|
|
1685
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1]));
|
|
1686
|
+
decodeResult.remaining.text = fields[2];
|
|
1687
|
+
ResultFormatter.altitude(decodeResult, fields[3]);
|
|
1688
|
+
ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates((fields[4] + fields[5]).replace(/[ \.]/g, "")));
|
|
1689
|
+
}
|
|
1690
|
+
} else {
|
|
1691
|
+
decodeResult.decoded = false;
|
|
1692
|
+
decodeResult.remaining.text = text2;
|
|
1693
|
+
}
|
|
1694
|
+
if (decodeResult.decoded) {
|
|
1695
|
+
if (!decodeResult.remaining.text)
|
|
1696
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
1697
|
+
else
|
|
1698
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1699
|
+
} else {
|
|
1700
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1701
|
+
}
|
|
1702
|
+
return decodeResult;
|
|
1703
|
+
}
|
|
1704
|
+
};
|
|
1705
|
+
|
|
1706
|
+
// lib/plugins/Label_4A_01.ts
|
|
1707
|
+
var Label_4A_01 = class extends DecoderPlugin {
|
|
1708
|
+
name = "label-4a-01";
|
|
1709
|
+
qualifiers() {
|
|
1710
|
+
return {
|
|
1711
|
+
labels: ["4A"],
|
|
1712
|
+
preambles: ["01"]
|
|
1713
|
+
};
|
|
1714
|
+
}
|
|
1715
|
+
decode(message, options = {}) {
|
|
1716
|
+
const decodeResult = this.defaultResult();
|
|
1717
|
+
decodeResult.decoder.name = this.name;
|
|
1718
|
+
decodeResult.message = message;
|
|
1719
|
+
decodeResult.formatted.description = "Latest New Format";
|
|
1720
|
+
decodeResult.decoded = true;
|
|
1721
|
+
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)/);
|
|
1722
|
+
if (rgx) {
|
|
1723
|
+
ResultFormatter.state_change(decodeResult, rgx[1], rgx[2]);
|
|
1724
|
+
ResultFormatter.callsign(decodeResult, rgx[3]);
|
|
1725
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(rgx[4] + "00"));
|
|
1726
|
+
ResultFormatter.departureAirport(decodeResult, rgx[5]);
|
|
1727
|
+
ResultFormatter.arrivalAirport(decodeResult, rgx[6]);
|
|
1728
|
+
ResultFormatter.altitude(decodeResult, Number(rgx[7].replace(/ /g, "")));
|
|
1729
|
+
decodeResult.remaining.text = rgx[8];
|
|
1730
|
+
ResultFormatter.temperature(decodeResult, rgx[9].replace(/ /g, ""));
|
|
1731
|
+
} else {
|
|
1732
|
+
decodeResult.decoded = false;
|
|
1733
|
+
decodeResult.remaining.text = message.text;
|
|
1734
|
+
}
|
|
1735
|
+
if (decodeResult.decoded) {
|
|
1736
|
+
if (!decodeResult.remaining.text)
|
|
1737
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
1738
|
+
else
|
|
1739
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1740
|
+
} else {
|
|
1741
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1742
|
+
}
|
|
1743
|
+
return decodeResult;
|
|
1744
|
+
}
|
|
1745
|
+
};
|
|
1746
|
+
|
|
1747
|
+
// lib/plugins/Label_4A_DIS.ts
|
|
1748
|
+
var Label_4A_DIS = class extends DecoderPlugin {
|
|
1749
|
+
name = "label-4a-dis";
|
|
1750
|
+
qualifiers() {
|
|
1751
|
+
return {
|
|
1752
|
+
labels: ["4A"],
|
|
1753
|
+
preambles: ["DIS"]
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1756
|
+
decode(message, options = {}) {
|
|
1757
|
+
const decodeResult = this.defaultResult();
|
|
1758
|
+
decodeResult.decoder.name = this.name;
|
|
1759
|
+
decodeResult.message = message;
|
|
1760
|
+
decodeResult.formatted.description = "Latest New Format";
|
|
1761
|
+
decodeResult.decoded = true;
|
|
1762
|
+
const fields = message.text.split(",");
|
|
1763
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(2) + "00"));
|
|
1764
|
+
ResultFormatter.callsign(decodeResult, fields[2]);
|
|
1765
|
+
ResultFormatter.freetext(decodeResult, fields.slice(3).join(""));
|
|
1766
|
+
if (decodeResult.decoded) {
|
|
1767
|
+
if (!decodeResult.remaining.text)
|
|
1768
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
1769
|
+
else
|
|
1770
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1771
|
+
} else {
|
|
1772
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1773
|
+
}
|
|
1774
|
+
return decodeResult;
|
|
1775
|
+
}
|
|
1776
|
+
};
|
|
1777
|
+
|
|
1778
|
+
// lib/plugins/Label_4A_DOOR.ts
|
|
1779
|
+
var Label_4A_DOOR = class extends DecoderPlugin {
|
|
1780
|
+
name = "label-4a-door";
|
|
1781
|
+
qualifiers() {
|
|
1782
|
+
return {
|
|
1783
|
+
labels: ["4A"],
|
|
1784
|
+
preambles: ["DOOR"]
|
|
1785
|
+
};
|
|
1786
|
+
}
|
|
1787
|
+
decode(message, options = {}) {
|
|
1788
|
+
const decodeResult = this.defaultResult();
|
|
1789
|
+
decodeResult.decoder.name = this.name;
|
|
1790
|
+
decodeResult.message = message;
|
|
1791
|
+
decodeResult.formatted.description = "Latest New Format";
|
|
1792
|
+
decodeResult.decoded = true;
|
|
1793
|
+
const fields = message.text.split(" ");
|
|
1794
|
+
if (fields.length === 3) {
|
|
1795
|
+
ResultFormatter.door_event(decodeResult, fields[0].split("/")[1], fields[1]);
|
|
1796
|
+
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2] + "00"));
|
|
1797
|
+
} else {
|
|
1798
|
+
decodeResult.decoded = false;
|
|
1799
|
+
decodeResult.remaining.text = text;
|
|
1800
|
+
}
|
|
1801
|
+
if (decodeResult.decoded) {
|
|
1802
|
+
if (!decodeResult.remaining.text)
|
|
1803
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
1804
|
+
else
|
|
1805
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1806
|
+
} else {
|
|
1807
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1808
|
+
}
|
|
1809
|
+
return decodeResult;
|
|
1810
|
+
}
|
|
1811
|
+
};
|
|
1812
|
+
|
|
1813
|
+
// lib/plugins/Label_4A_Slash_01.ts
|
|
1814
|
+
var Label_4A_Slash_01 = class extends DecoderPlugin {
|
|
1815
|
+
name = "label-4a-slash-01";
|
|
1816
|
+
qualifiers() {
|
|
1817
|
+
return {
|
|
1818
|
+
labels: ["4A"],
|
|
1819
|
+
preambles: ["/01"]
|
|
1820
|
+
};
|
|
1821
|
+
}
|
|
1822
|
+
decode(message, options = {}) {
|
|
1823
|
+
const decodeResult = this.defaultResult();
|
|
1824
|
+
decodeResult.decoder.name = this.name;
|
|
1825
|
+
decodeResult.message = message;
|
|
1826
|
+
decodeResult.formatted.description = "Latest New Format";
|
|
1827
|
+
decodeResult.decoded = true;
|
|
1828
|
+
if (message.text.length === 5 && message.text.substring(0, 4) === "/01-") {
|
|
1829
|
+
decodeResult.remaining.text = message.text.substring(4);
|
|
1830
|
+
} else {
|
|
1831
|
+
decodeResult.decoded = false;
|
|
1832
|
+
decodeResult.remaining.text = message.text;
|
|
1833
|
+
}
|
|
1834
|
+
if (decodeResult.decoded) {
|
|
1835
|
+
if (!decodeResult.remaining.text)
|
|
1836
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
1837
|
+
else
|
|
1838
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1839
|
+
} else {
|
|
1840
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1841
|
+
}
|
|
1842
|
+
return decodeResult;
|
|
1843
|
+
}
|
|
1844
|
+
};
|
|
1845
|
+
|
|
1846
|
+
// lib/plugins/Label_4N.ts
|
|
1847
|
+
var Label_4N = class extends DecoderPlugin {
|
|
1848
|
+
name = "label-4n";
|
|
1849
|
+
qualifiers() {
|
|
1850
|
+
return {
|
|
1851
|
+
labels: ["4N"]
|
|
1852
|
+
};
|
|
1853
|
+
}
|
|
1854
|
+
decode(message, options = {}) {
|
|
1855
|
+
const decodeResult = this.defaultResult();
|
|
1856
|
+
decodeResult.decoder.name = this.name;
|
|
1857
|
+
decodeResult.message = message;
|
|
1858
|
+
decodeResult.formatted.description = "Airline Defined";
|
|
1859
|
+
let text2 = message.text;
|
|
1860
|
+
if (text2.match(/^M\d{2}A\w{6}/)) {
|
|
1861
|
+
ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
|
|
1862
|
+
text2 = text2.substring(10);
|
|
1863
|
+
}
|
|
1864
|
+
decodeResult.decoded = true;
|
|
1865
|
+
const fields = text2.split(",");
|
|
1866
|
+
if (text2.length === 51) {
|
|
1867
|
+
decodeResult.raw.day_of_month = text2.substring(0, 2);
|
|
1868
|
+
ResultFormatter.departureAirport(decodeResult, text2.substring(8, 11));
|
|
1869
|
+
ResultFormatter.arrivalAirport(decodeResult, text2.substring(13, 16));
|
|
1870
|
+
ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text2.substring(30, 45).replace(/^(.)0/, "$1")));
|
|
1871
|
+
ResultFormatter.altitude(decodeResult, text2.substring(48, 51) * 100);
|
|
1872
|
+
decodeResult.remaining.text = [text2.substring(2, 4), text2.substring(19, 29)].join(" ");
|
|
1873
|
+
} else if (fields.length === 33) {
|
|
1874
|
+
decodeResult.raw.date = fields[3];
|
|
1875
|
+
if (fields[1] === "B") {
|
|
1876
|
+
ResultFormatter.position(decodeResult, { latitude: Number(fields[4]), longitude: Number(fields[5]) });
|
|
1877
|
+
ResultFormatter.altitude(decodeResult, fields[6]);
|
|
1878
|
+
}
|
|
1879
|
+
ResultFormatter.departureAirport(decodeResult, fields[8]);
|
|
1880
|
+
ResultFormatter.arrivalAirport(decodeResult, fields[9]);
|
|
1881
|
+
ResultFormatter.alternateAirport(decodeResult, fields[10]);
|
|
1882
|
+
ResultFormatter.arrivalRunway(decodeResult, fields[11].split("/")[0]);
|
|
1883
|
+
if (fields[12].length > 1) {
|
|
1884
|
+
ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
|
|
1885
|
+
}
|
|
1886
|
+
ResultFormatter.checksum(decodeResult, fields[32]);
|
|
1887
|
+
decodeResult.remaining.text = [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != "").join(",");
|
|
1888
|
+
} else {
|
|
1889
|
+
decodeResult.decoded = false;
|
|
1890
|
+
decodeResult.remaining.text = text2;
|
|
1891
|
+
}
|
|
1892
|
+
if (decodeResult.decoded) {
|
|
1893
|
+
if (!decodeResult.remaining.text)
|
|
1894
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
1895
|
+
else
|
|
1896
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
1897
|
+
} else {
|
|
1898
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1899
|
+
}
|
|
1900
|
+
return decodeResult;
|
|
1901
|
+
}
|
|
1902
|
+
};
|
|
1903
|
+
|
|
1904
|
+
// lib/plugins/Label_80.ts
|
|
1905
|
+
var Label_80 = class extends DecoderPlugin {
|
|
1906
|
+
name = "label-80";
|
|
1907
|
+
descriptions = {
|
|
1908
|
+
ALT: "Altitude",
|
|
1909
|
+
DWND: "Wind Direction",
|
|
1910
|
+
ETA: "Estimated Time of Arrival",
|
|
1911
|
+
FOB: "Fuel on Board",
|
|
1912
|
+
FL: "Flight Level",
|
|
1913
|
+
HDG: "Heading",
|
|
1914
|
+
MCH: "Aircraft Speed",
|
|
1915
|
+
NWYP: "Next Waypoint",
|
|
1916
|
+
POS: "Aircraft Position",
|
|
1917
|
+
SAT: "Static Air Temperature",
|
|
1918
|
+
SWND: "Wind Speed",
|
|
1919
|
+
TAS: "True Airspeed",
|
|
1920
|
+
WYP: "Waypoint"
|
|
1335
1921
|
};
|
|
1336
1922
|
qualifiers() {
|
|
1337
1923
|
return {
|
|
@@ -1346,27 +1932,15 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1346
1932
|
const parts = message.text.split("\n");
|
|
1347
1933
|
let posRptRegex = /^3N01 POSRPT \d\d\d\d\/\d\d (?<orig>\w+)\/(?<dest>\w+) \.(?<tail>[\w-]+)(\/(?<agate>.+) (?<sta>\w+:\w+))*/;
|
|
1348
1934
|
let results = parts[0].match(posRptRegex);
|
|
1935
|
+
if (!results?.groups) {
|
|
1936
|
+
decodeResult.decoded = false;
|
|
1937
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1938
|
+
return decodeResult;
|
|
1939
|
+
}
|
|
1349
1940
|
if (results && results.length > 0) {
|
|
1350
|
-
decodeResult
|
|
1351
|
-
decodeResult.
|
|
1352
|
-
|
|
1353
|
-
code: "ORG",
|
|
1354
|
-
label: "Origin",
|
|
1355
|
-
value: `${results.groups.orig}`
|
|
1356
|
-
});
|
|
1357
|
-
decodeResult.raw.destination = results.groups.dest;
|
|
1358
|
-
decodeResult.formatted.items.push({
|
|
1359
|
-
type: "destination",
|
|
1360
|
-
code: "DST",
|
|
1361
|
-
label: "Destination",
|
|
1362
|
-
value: `${results.groups.dest}`
|
|
1363
|
-
});
|
|
1364
|
-
decodeResult.raw.tail = results.groups.tail;
|
|
1365
|
-
decodeResult.formatted.items.push({
|
|
1366
|
-
type: "tail",
|
|
1367
|
-
label: "Tail",
|
|
1368
|
-
value: `${results.groups.tail}`
|
|
1369
|
-
});
|
|
1941
|
+
ResultFormatter.departureAirport(decodeResult, results.groups.orig);
|
|
1942
|
+
ResultFormatter.arrivalAirport(decodeResult, results.groups.dest);
|
|
1943
|
+
ResultFormatter.tail(decodeResult, results.groups.tail);
|
|
1370
1944
|
if (results.groups.agate) {
|
|
1371
1945
|
decodeResult.raw.arrival_gate = results.groups.agate;
|
|
1372
1946
|
decodeResult.formatted.items.push({
|
|
@@ -1388,15 +1962,9 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1388
1962
|
for (const part of remainingParts) {
|
|
1389
1963
|
const matches = part.matchAll(posRptRegex);
|
|
1390
1964
|
for (const match of matches) {
|
|
1391
|
-
switch (match.groups
|
|
1965
|
+
switch (match.groups?.field) {
|
|
1392
1966
|
case "ALT": {
|
|
1393
|
-
|
|
1394
|
-
decodeResult.formatted.items.push({
|
|
1395
|
-
type: "altitude",
|
|
1396
|
-
code: "ALT",
|
|
1397
|
-
label: this.descriptions[match.groups.field],
|
|
1398
|
-
value: `${decodeResult.raw.altitude} feet`
|
|
1399
|
-
});
|
|
1967
|
+
ResultFormatter.altitude(decodeResult, Number(match.groups.value));
|
|
1400
1968
|
break;
|
|
1401
1969
|
}
|
|
1402
1970
|
case "DWND": {
|
|
@@ -1410,9 +1978,8 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1410
1978
|
break;
|
|
1411
1979
|
}
|
|
1412
1980
|
case "FL": {
|
|
1413
|
-
const flight_level = match.groups.value;
|
|
1414
|
-
|
|
1415
|
-
ResultFormatter.altitude(decodeResult, decodeResult.raw.altitude);
|
|
1981
|
+
const flight_level = Number(match.groups.value);
|
|
1982
|
+
ResultFormatter.altitude(decodeResult, flight_level * 100);
|
|
1416
1983
|
break;
|
|
1417
1984
|
}
|
|
1418
1985
|
case "FOB": {
|
|
@@ -1436,7 +2003,7 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1436
2003
|
break;
|
|
1437
2004
|
}
|
|
1438
2005
|
case "MCH": {
|
|
1439
|
-
decodeResult.raw.mach = match.groups.value / 1e3;
|
|
2006
|
+
decodeResult.raw.mach = Number(match.groups.value) / 1e3;
|
|
1440
2007
|
decodeResult.formatted.items.push({
|
|
1441
2008
|
type: "mach",
|
|
1442
2009
|
code: "MCH",
|
|
@@ -1458,20 +2025,13 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1458
2025
|
case "POS": {
|
|
1459
2026
|
const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
|
|
1460
2027
|
const posResult = match.groups.value.match(posRegex);
|
|
1461
|
-
const lat = Number(posResult
|
|
1462
|
-
const lon = Number(posResult
|
|
1463
|
-
const
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
latitude,
|
|
1467
|
-
longitude
|
|
2028
|
+
const lat = Number(posResult?.groups?.lat) * (posResult?.groups?.lngd === "S" ? -1 : 1);
|
|
2029
|
+
const lon = Number(posResult?.groups?.lng) * (posResult?.groups?.lngd === "W" ? -1 : 1);
|
|
2030
|
+
const position = {
|
|
2031
|
+
latitude: Number.isInteger(lat) ? lat / 1e3 : lat / 100,
|
|
2032
|
+
longitude: Number.isInteger(lon) ? lon / 1e3 : lon / 100
|
|
1468
2033
|
};
|
|
1469
|
-
|
|
1470
|
-
type: "position",
|
|
1471
|
-
code: "POS",
|
|
1472
|
-
label: "Position",
|
|
1473
|
-
value: CoordinateUtils.coordinateString(decodeResult.raw.position)
|
|
1474
|
-
});
|
|
2034
|
+
ResultFormatter.position(decodeResult, position);
|
|
1475
2035
|
break;
|
|
1476
2036
|
}
|
|
1477
2037
|
case "SWND": {
|
|
@@ -1485,7 +2045,7 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1485
2045
|
break;
|
|
1486
2046
|
}
|
|
1487
2047
|
default: {
|
|
1488
|
-
if (match.groups
|
|
2048
|
+
if (match.groups?.field != void 0) {
|
|
1489
2049
|
const description = this.descriptions[match.groups.field] ? this.descriptions[match.groups.field] : "Unknown";
|
|
1490
2050
|
decodeResult.formatted.items.push({
|
|
1491
2051
|
type: match.groups.field,
|
|
@@ -1499,7 +2059,80 @@ var Label_80 = class extends DecoderPlugin {
|
|
|
1499
2059
|
}
|
|
1500
2060
|
}
|
|
1501
2061
|
decodeResult.decoded = true;
|
|
1502
|
-
decodeResult.decodeLevel = "partial";
|
|
2062
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
2063
|
+
}
|
|
2064
|
+
return decodeResult;
|
|
2065
|
+
}
|
|
2066
|
+
};
|
|
2067
|
+
|
|
2068
|
+
// lib/plugins/Label_83.ts
|
|
2069
|
+
var Label_83 = class extends DecoderPlugin {
|
|
2070
|
+
name = "label-83";
|
|
2071
|
+
qualifiers() {
|
|
2072
|
+
return {
|
|
2073
|
+
labels: ["83"]
|
|
2074
|
+
};
|
|
2075
|
+
}
|
|
2076
|
+
decode(message, options = {}) {
|
|
2077
|
+
const decodeResult = this.defaultResult();
|
|
2078
|
+
decodeResult.decoder.name = this.name;
|
|
2079
|
+
decodeResult.message = message;
|
|
2080
|
+
decodeResult.formatted.description = "Airline Defined";
|
|
2081
|
+
let text2 = message.text;
|
|
2082
|
+
if (text2.match(/^M\d{2}A\w{6}/)) {
|
|
2083
|
+
ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
|
|
2084
|
+
text2 = text2.substring(10);
|
|
2085
|
+
}
|
|
2086
|
+
decodeResult.decoded = true;
|
|
2087
|
+
if (text2.substring(0, 10) === "4DH3 ETAT2") {
|
|
2088
|
+
const fields = text2.split(/\s+/);
|
|
2089
|
+
if (fields[2].length > 5) {
|
|
2090
|
+
decodeResult.raw.day_of_month = fields[2].substring(5);
|
|
2091
|
+
}
|
|
2092
|
+
decodeResult.remaining.text = fields[2].substring(0, 4);
|
|
2093
|
+
const subfields = fields[3].split("/");
|
|
2094
|
+
ResultFormatter.departureAirport(decodeResult, subfields[0]);
|
|
2095
|
+
ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
|
|
2096
|
+
ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
|
|
2097
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[6] + "00"));
|
|
2098
|
+
} else if (text2.substring(0, 5) === "001PR") {
|
|
2099
|
+
decodeResult.raw.day_of_month = text2.substring(5, 7);
|
|
2100
|
+
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text2.substring(13, 28).replace(/\./g, ""));
|
|
2101
|
+
if (position) {
|
|
2102
|
+
ResultFormatter.position(decodeResult, position);
|
|
2103
|
+
}
|
|
2104
|
+
ResultFormatter.altitude(decodeResult, Number(text2.substring(28, 33)));
|
|
2105
|
+
decodeResult.remaining.text = text2.substring(33);
|
|
2106
|
+
} else {
|
|
2107
|
+
const fields = text2.replace(/\s/g, "").split(",");
|
|
2108
|
+
if (fields.length === 9) {
|
|
2109
|
+
ResultFormatter.departureAirport(decodeResult, fields[0]);
|
|
2110
|
+
ResultFormatter.arrivalAirport(decodeResult, fields[1]);
|
|
2111
|
+
decodeResult.raw.day_of_month = fields[2].substring(0, 2);
|
|
2112
|
+
decodeResult.raw.time = fields[2].substring(2);
|
|
2113
|
+
ResultFormatter.position(
|
|
2114
|
+
decodeResult,
|
|
2115
|
+
{
|
|
2116
|
+
latitude: Number(fields[3].replace(/\s/g, "")),
|
|
2117
|
+
longitude: Number(fields[4].replace(/\s/g, ""))
|
|
2118
|
+
}
|
|
2119
|
+
);
|
|
2120
|
+
ResultFormatter.altitude(decodeResult, Number(fields[5]));
|
|
2121
|
+
ResultFormatter.groundspeed(decodeResult, fields[6]);
|
|
2122
|
+
ResultFormatter.heading(decodeResult, fields[7]);
|
|
2123
|
+
decodeResult.remaining.text = fields[8];
|
|
2124
|
+
} else {
|
|
2125
|
+
decodeResult.decoded = false;
|
|
2126
|
+
decodeResult.remaining.text = message.text;
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
if (decodeResult.decoded) {
|
|
2130
|
+
if (!decodeResult.remaining.text)
|
|
2131
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
2132
|
+
else
|
|
2133
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
2134
|
+
} else {
|
|
2135
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
1503
2136
|
}
|
|
1504
2137
|
return decodeResult;
|
|
1505
2138
|
}
|
|
@@ -1525,19 +2158,8 @@ var Label_8E = class extends DecoderPlugin {
|
|
|
1525
2158
|
console.log(`Label 8E ETA: groups`);
|
|
1526
2159
|
console.log(results.groups);
|
|
1527
2160
|
}
|
|
1528
|
-
decodeResult.
|
|
1529
|
-
|
|
1530
|
-
code: "ETA",
|
|
1531
|
-
label: "Estimated Time of Arrival",
|
|
1532
|
-
value: DateTimeUtils.UTCToString(results.groups.arrival_eta)
|
|
1533
|
-
});
|
|
1534
|
-
decodeResult.raw.arrival_icao = results.groups.arrival_icao;
|
|
1535
|
-
decodeResult.formatted.items.push({
|
|
1536
|
-
type: "destination",
|
|
1537
|
-
code: "DST",
|
|
1538
|
-
label: "Destination",
|
|
1539
|
-
value: decodeResult.raw.arrival_icao
|
|
1540
|
-
});
|
|
2161
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta + "00"));
|
|
2162
|
+
ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
|
|
1541
2163
|
}
|
|
1542
2164
|
decodeResult.decoded = true;
|
|
1543
2165
|
decodeResult.decoder.decodeLevel = "full";
|
|
@@ -1590,44 +2212,158 @@ var Label_ColonComma = class extends DecoderPlugin {
|
|
|
1590
2212
|
}
|
|
1591
2213
|
};
|
|
1592
2214
|
|
|
1593
|
-
// lib/plugins/Label_H1_FLR.ts
|
|
1594
|
-
var Label_H1_FLR = class extends DecoderPlugin {
|
|
1595
|
-
name = "label-h1-flr";
|
|
2215
|
+
// lib/plugins/Label_H1_FLR.ts
|
|
2216
|
+
var Label_H1_FLR = class extends DecoderPlugin {
|
|
2217
|
+
name = "label-h1-flr";
|
|
2218
|
+
qualifiers() {
|
|
2219
|
+
return {
|
|
2220
|
+
labels: ["H1"],
|
|
2221
|
+
preambles: ["FLR", "#CFBFLR"]
|
|
2222
|
+
};
|
|
2223
|
+
}
|
|
2224
|
+
decode(message, options = {}) {
|
|
2225
|
+
let decodeResult = this.defaultResult();
|
|
2226
|
+
decodeResult.decoder.name = this.name;
|
|
2227
|
+
decodeResult.formatted.description = "Fault Log Report";
|
|
2228
|
+
decodeResult.message = message;
|
|
2229
|
+
const parts = message.text.split("/FR");
|
|
2230
|
+
if (parts.length > 1) {
|
|
2231
|
+
decodeResult.remaining.text = "";
|
|
2232
|
+
const fields = parts[0].split("/");
|
|
2233
|
+
for (let i = 1; i < fields.length; i++) {
|
|
2234
|
+
const field = fields[i];
|
|
2235
|
+
if (field.startsWith("PN")) {
|
|
2236
|
+
processUnknown(decodeResult, "/" + field);
|
|
2237
|
+
} else {
|
|
2238
|
+
processUnknown(decodeResult, "/" + field);
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
const data = parts[1].substring(0, 20);
|
|
2242
|
+
const msg = parts[1].substring(20);
|
|
2243
|
+
const datetime = data.substring(0, 12);
|
|
2244
|
+
const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
|
|
2245
|
+
processUnknown(decodeResult, data.substring(12));
|
|
2246
|
+
decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
|
|
2247
|
+
decodeResult.raw.fault_message = msg;
|
|
2248
|
+
decodeResult.formatted.items.push({
|
|
2249
|
+
type: "fault",
|
|
2250
|
+
code: "FR",
|
|
2251
|
+
label: "Fault Report",
|
|
2252
|
+
value: decodeResult.raw.fault_message
|
|
2253
|
+
});
|
|
2254
|
+
decodeResult.decoded = true;
|
|
2255
|
+
decodeResult.decoder.decodeLevel = "partial";
|
|
2256
|
+
} else {
|
|
2257
|
+
if (options.debug) {
|
|
2258
|
+
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2259
|
+
}
|
|
2260
|
+
decodeResult.remaining.text = message.text;
|
|
2261
|
+
decodeResult.decoded = false;
|
|
2262
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
2263
|
+
}
|
|
2264
|
+
return decodeResult;
|
|
2265
|
+
}
|
|
2266
|
+
};
|
|
2267
|
+
function processUnknown(decodeResult, value) {
|
|
2268
|
+
decodeResult.remaining.text += value;
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
// lib/plugins/Label_H1_OHMA.ts
|
|
2272
|
+
import * as zlib from "minizlib";
|
|
2273
|
+
var Label_H1_OHMA = class extends DecoderPlugin {
|
|
2274
|
+
name = "label-h1-ohma";
|
|
2275
|
+
qualifiers() {
|
|
2276
|
+
return {
|
|
2277
|
+
labels: ["H1"],
|
|
2278
|
+
preambles: ["OHMA", "/RTNBOCR.OHMA", "#T1B/RTNBOCR.OHMA"]
|
|
2279
|
+
};
|
|
2280
|
+
}
|
|
2281
|
+
decode(message, options = {}) {
|
|
2282
|
+
let decodeResult = this.defaultResult();
|
|
2283
|
+
decodeResult.decoder.name = this.name;
|
|
2284
|
+
decodeResult.formatted.description = "OHMA Message";
|
|
2285
|
+
decodeResult.message = message;
|
|
2286
|
+
decodeResult.remaining.text = "";
|
|
2287
|
+
const data = message.text.split("OHMA")[1];
|
|
2288
|
+
try {
|
|
2289
|
+
const compressedBuffer = Buffer.from(data, "base64");
|
|
2290
|
+
const decompress = new zlib.Inflate({ windowBits: 15 });
|
|
2291
|
+
decompress.write(compressedBuffer);
|
|
2292
|
+
decompress.flush(zlib.constants.Z_SYNC_FLUSH);
|
|
2293
|
+
const result = decompress.read();
|
|
2294
|
+
const jsonText = result.toString();
|
|
2295
|
+
let formattedMsg;
|
|
2296
|
+
let jsonMessage;
|
|
2297
|
+
try {
|
|
2298
|
+
jsonMessage = JSON.parse(jsonText).message;
|
|
2299
|
+
} catch {
|
|
2300
|
+
jsonMessage = jsonText;
|
|
2301
|
+
}
|
|
2302
|
+
try {
|
|
2303
|
+
const ohmaMsg = JSON.parse(jsonMessage);
|
|
2304
|
+
formattedMsg = JSON.stringify(ohmaMsg, null, 2);
|
|
2305
|
+
} catch {
|
|
2306
|
+
formattedMsg = jsonMessage;
|
|
2307
|
+
}
|
|
2308
|
+
decodeResult.decoded = true;
|
|
2309
|
+
decodeResult.decoder.decodeLevel = "full";
|
|
2310
|
+
decodeResult.raw.ohma = jsonText;
|
|
2311
|
+
decodeResult.formatted.items.push({
|
|
2312
|
+
type: "ohma",
|
|
2313
|
+
code: "OHMA",
|
|
2314
|
+
label: "OHMA Downlink",
|
|
2315
|
+
value: formattedMsg
|
|
2316
|
+
});
|
|
2317
|
+
} catch (e) {
|
|
2318
|
+
if (options.debug) {
|
|
2319
|
+
console.log(`Decoder: Unknown H1 OHMA message: ${message.text}`, e);
|
|
2320
|
+
}
|
|
2321
|
+
decodeResult.remaining.text += message.text;
|
|
2322
|
+
decodeResult.decoded = false;
|
|
2323
|
+
decodeResult.decoder.decodeLevel = "none";
|
|
2324
|
+
}
|
|
2325
|
+
return decodeResult;
|
|
2326
|
+
}
|
|
2327
|
+
};
|
|
2328
|
+
|
|
2329
|
+
// lib/plugins/Label_H1_WRN.ts
|
|
2330
|
+
var Label_H1_WRN = class extends DecoderPlugin {
|
|
2331
|
+
name = "label-h1-wrn";
|
|
1596
2332
|
qualifiers() {
|
|
1597
2333
|
return {
|
|
1598
2334
|
labels: ["H1"],
|
|
1599
|
-
preambles: ["
|
|
2335
|
+
preambles: ["WRN", "#CFBWRN"]
|
|
1600
2336
|
};
|
|
1601
2337
|
}
|
|
1602
2338
|
decode(message, options = {}) {
|
|
1603
2339
|
let decodeResult = this.defaultResult();
|
|
1604
2340
|
decodeResult.decoder.name = this.name;
|
|
1605
|
-
decodeResult.formatted.description = "
|
|
2341
|
+
decodeResult.formatted.description = "Warning Message";
|
|
1606
2342
|
decodeResult.message = message;
|
|
1607
|
-
const parts = message.text.split("/
|
|
2343
|
+
const parts = message.text.split("/WN");
|
|
1608
2344
|
if (parts.length > 1) {
|
|
1609
2345
|
decodeResult.remaining.text = "";
|
|
1610
2346
|
const fields = parts[0].split("/");
|
|
1611
2347
|
for (let i = 1; i < fields.length; i++) {
|
|
1612
2348
|
const field = fields[i];
|
|
1613
2349
|
if (field.startsWith("PN")) {
|
|
1614
|
-
|
|
2350
|
+
processUnknown2(decodeResult, "/" + field);
|
|
1615
2351
|
} else {
|
|
1616
|
-
|
|
2352
|
+
processUnknown2(decodeResult, "/" + field);
|
|
1617
2353
|
}
|
|
1618
2354
|
}
|
|
1619
2355
|
const data = parts[1].substring(0, 20);
|
|
1620
2356
|
const msg = parts[1].substring(20);
|
|
1621
2357
|
const datetime = data.substring(0, 12);
|
|
1622
2358
|
const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
|
|
1623
|
-
|
|
2359
|
+
processUnknown2(decodeResult, data.substring(12));
|
|
1624
2360
|
decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
|
|
1625
|
-
decodeResult.raw.
|
|
2361
|
+
decodeResult.raw.warning_message = msg;
|
|
1626
2362
|
decodeResult.formatted.items.push({
|
|
1627
|
-
type: "
|
|
1628
|
-
code: "
|
|
1629
|
-
label: "
|
|
1630
|
-
value: decodeResult.raw.
|
|
2363
|
+
type: "warning",
|
|
2364
|
+
code: "WRN",
|
|
2365
|
+
label: "Warning Message",
|
|
2366
|
+
value: decodeResult.raw.warning_message
|
|
1631
2367
|
});
|
|
1632
2368
|
decodeResult.decoded = true;
|
|
1633
2369
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -1642,7 +2378,7 @@ var Label_H1_FLR = class extends DecoderPlugin {
|
|
|
1642
2378
|
return decodeResult;
|
|
1643
2379
|
}
|
|
1644
2380
|
};
|
|
1645
|
-
function
|
|
2381
|
+
function processUnknown2(decodeResult, value) {
|
|
1646
2382
|
decodeResult.remaining.text += value;
|
|
1647
2383
|
}
|
|
1648
2384
|
|
|
@@ -1808,11 +2544,10 @@ function addCompanyRoute(decodeResult, value) {
|
|
|
1808
2544
|
// lib/utils/h1_helper.ts
|
|
1809
2545
|
var H1Helper = class {
|
|
1810
2546
|
static decodeH1Message(decodeResult, message) {
|
|
1811
|
-
let allKnownFields = true;
|
|
1812
2547
|
const checksum = message.slice(-4);
|
|
1813
2548
|
const data = message.slice(0, message.length - 4);
|
|
1814
2549
|
const fields = data.split("/");
|
|
1815
|
-
|
|
2550
|
+
parseMessageType(decodeResult, fields[0]);
|
|
1816
2551
|
for (let i = 1; i < fields.length; ++i) {
|
|
1817
2552
|
if (fields[i].startsWith("FN")) {
|
|
1818
2553
|
decodeResult.raw.flight_number = fields[i].substring(2);
|
|
@@ -1831,32 +2566,22 @@ var H1Helper = class {
|
|
|
1831
2566
|
decodeResult.raw.message_timestamp = time;
|
|
1832
2567
|
} else if (fields[i].startsWith("PS")) {
|
|
1833
2568
|
const pos = processPS(decodeResult, fields[i].substring(2).split(","));
|
|
1834
|
-
allKnownFields == allKnownFields && pos;
|
|
1835
2569
|
} else if (fields[i].startsWith("DT")) {
|
|
1836
2570
|
const data2 = fields[i].substring(2).split(",");
|
|
1837
|
-
|
|
1838
|
-
allKnownFields = allKnownFields && dt;
|
|
2571
|
+
processDT(decodeResult, data2);
|
|
1839
2572
|
} else if (fields[i].startsWith("ID")) {
|
|
1840
2573
|
processIdentification(decodeResult, fields[i].substring(2).split(","));
|
|
1841
2574
|
} else if (fields[i].startsWith("LR")) {
|
|
1842
2575
|
const data2 = fields[i].substring(2).split(",");
|
|
1843
|
-
|
|
1844
|
-
allKnownFields = allKnownFields && lr;
|
|
2576
|
+
processLR(decodeResult, data2);
|
|
1845
2577
|
} else if (fields[i].startsWith("RI") || fields[i].startsWith("RF") || fields[i].startsWith("RP")) {
|
|
1846
|
-
|
|
1847
|
-
allKnownFields = allKnownFields && fp;
|
|
2578
|
+
FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
|
|
1848
2579
|
} else if (fields[i].startsWith("PR")) {
|
|
1849
|
-
allKnownFields = false;
|
|
1850
2580
|
decodeResult.remaining.text += "/" + fields[i];
|
|
1851
|
-
} else if (fields[i].startsWith("PS")) {
|
|
1852
|
-
allKnownFields = false;
|
|
1853
|
-
decodeResult.remaining.text += fields[i];
|
|
1854
2581
|
} else if (fields[i].startsWith("AF")) {
|
|
1855
|
-
|
|
1856
|
-
allKnownFields = allKnownFields && af;
|
|
2582
|
+
processAirField(decodeResult, fields[i].substring(2).split(","));
|
|
1857
2583
|
} else if (fields[i].startsWith("TD")) {
|
|
1858
|
-
|
|
1859
|
-
allKnownFields = allKnownFields && td;
|
|
2584
|
+
processTimeOfDeparture(decodeResult, fields[i].substring(2).split(","));
|
|
1860
2585
|
} else if (fields[i].startsWith("FX")) {
|
|
1861
2586
|
decodeResult.raw.free_text = fields[i].substring(2);
|
|
1862
2587
|
decodeResult.formatted.items.push({
|
|
@@ -1867,23 +2592,21 @@ var H1Helper = class {
|
|
|
1867
2592
|
});
|
|
1868
2593
|
} else {
|
|
1869
2594
|
decodeResult.remaining.text += "/" + fields[i];
|
|
1870
|
-
allKnownFields = false;
|
|
1871
2595
|
}
|
|
1872
2596
|
}
|
|
1873
2597
|
if (decodeResult.formatted.items.length > 0) {
|
|
1874
2598
|
ResultFormatter.checksum(decodeResult, checksum);
|
|
1875
2599
|
}
|
|
1876
|
-
return
|
|
2600
|
+
return true;
|
|
1877
2601
|
}
|
|
1878
2602
|
};
|
|
1879
2603
|
function processAirField(decodeResult, data) {
|
|
1880
2604
|
if (data.length === 2) {
|
|
1881
2605
|
ResultFormatter.departureAirport(decodeResult, data[0]);
|
|
1882
2606
|
ResultFormatter.arrivalAirport(decodeResult, data[1]);
|
|
1883
|
-
|
|
2607
|
+
} else {
|
|
2608
|
+
decodeResult.remaining.text += "AF/" + data.join(",");
|
|
1884
2609
|
}
|
|
1885
|
-
decodeResult.remaining.text += "AF/" + data.join(",");
|
|
1886
|
-
return false;
|
|
1887
2610
|
}
|
|
1888
2611
|
function processTimeOfDeparture(decodeResult, data) {
|
|
1889
2612
|
if (data.length === 2) {
|
|
@@ -1901,19 +2624,12 @@ function processTimeOfDeparture(decodeResult, data) {
|
|
|
1901
2624
|
label: "Estimated Departure Time",
|
|
1902
2625
|
value: `${data[1].substring(0, 2)}:${data[1].substring(2)}`
|
|
1903
2626
|
});
|
|
1904
|
-
|
|
2627
|
+
} else {
|
|
2628
|
+
decodeResult.remaining.text += "/TD" + data.join(",");
|
|
1905
2629
|
}
|
|
1906
|
-
decodeResult.remaining.text += "/TD" + data.join(",");
|
|
1907
|
-
return false;
|
|
1908
2630
|
}
|
|
1909
2631
|
function processIdentification(decodeResult, data) {
|
|
1910
|
-
|
|
1911
|
-
decodeResult.formatted.items.push({
|
|
1912
|
-
type: "tail",
|
|
1913
|
-
code: "TAIL",
|
|
1914
|
-
label: "Tail",
|
|
1915
|
-
value: decodeResult.raw.tail
|
|
1916
|
-
});
|
|
2632
|
+
ResultFormatter.tail(decodeResult, data[0]);
|
|
1917
2633
|
if (data.length > 1) {
|
|
1918
2634
|
decodeResult.raw.flight_number = data[1];
|
|
1919
2635
|
}
|
|
@@ -1922,7 +2638,6 @@ function processIdentification(decodeResult, data) {
|
|
|
1922
2638
|
}
|
|
1923
2639
|
}
|
|
1924
2640
|
function processDT(decodeResult, data) {
|
|
1925
|
-
let allKnownFields = true;
|
|
1926
2641
|
if (!decodeResult.raw.arrival_icao) {
|
|
1927
2642
|
ResultFormatter.arrivalAirport(decodeResult, data[0]);
|
|
1928
2643
|
} else if (decodeResult.raw.arrival_icao != data[0]) {
|
|
@@ -1935,19 +2650,16 @@ function processDT(decodeResult, data) {
|
|
|
1935
2650
|
ResultFormatter.currentFuel(decodeResult, Number(data[2]));
|
|
1936
2651
|
}
|
|
1937
2652
|
if (data.length > 3) {
|
|
1938
|
-
ResultFormatter.eta(decodeResult, data[3]);
|
|
2653
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[3]));
|
|
1939
2654
|
}
|
|
1940
2655
|
if (data.length > 4) {
|
|
1941
2656
|
ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
|
|
1942
2657
|
}
|
|
1943
2658
|
if (data.length > 5) {
|
|
1944
|
-
allKnownFields = false;
|
|
1945
2659
|
decodeResult.remaining.text += "," + data.slice(5).join(",");
|
|
1946
2660
|
}
|
|
1947
|
-
return allKnownFields;
|
|
1948
2661
|
}
|
|
1949
2662
|
function processLR(decodeResult, data) {
|
|
1950
|
-
let allKnownFields = true;
|
|
1951
2663
|
if (data.length === 19) {
|
|
1952
2664
|
ResultFormatter.unknown(decodeResult, data[1]);
|
|
1953
2665
|
ResultFormatter.flightNumber(decodeResult, data[2]);
|
|
@@ -1955,34 +2667,47 @@ function processLR(decodeResult, data) {
|
|
|
1955
2667
|
ResultFormatter.arrivalAirport(decodeResult, data[4]);
|
|
1956
2668
|
ResultFormatter.arrivalRunway(decodeResult, data[5]);
|
|
1957
2669
|
ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
|
|
1958
|
-
allKnownFields = false;
|
|
1959
2670
|
} else {
|
|
1960
|
-
|
|
2671
|
+
ResultFormatter.unknown(decodeResult, data.join(","));
|
|
1961
2672
|
}
|
|
1962
|
-
return allKnownFields;
|
|
1963
2673
|
}
|
|
1964
2674
|
function parseMessageType(decodeResult, messageType) {
|
|
1965
|
-
let decoded = true;
|
|
1966
2675
|
const parts = messageType.split("#");
|
|
1967
2676
|
if (parts.length == 1) {
|
|
1968
|
-
|
|
1969
|
-
|
|
2677
|
+
const type = parts[0].substring(0, 3);
|
|
2678
|
+
if (type === "POS" && parts[0].length !== 3) {
|
|
2679
|
+
processPosition2(decodeResult, parts[0].substring(3).split(","));
|
|
1970
2680
|
}
|
|
1971
|
-
return
|
|
2681
|
+
return processMessageType(decodeResult, type);
|
|
1972
2682
|
} else if (parts.length == 2) {
|
|
1973
2683
|
if (parts[0].length > 0) {
|
|
1974
2684
|
decodeResult.remaining.text += parts[0].substring(0, 3);
|
|
1975
2685
|
decodeResult.raw.flight_number = parts[0].substring(3);
|
|
1976
|
-
decodeResult.remaining.text += "#" + parts[1].substring(0, 3);
|
|
2686
|
+
decodeResult.remaining.text += "#" + (parts[1].length == 5 ? parts[1].substring(0, 2) : parts[1].substring(0, 3));
|
|
1977
2687
|
}
|
|
1978
|
-
|
|
1979
|
-
|
|
2688
|
+
const type = parts[1].length == 5 ? parts[1].substring(2, 5) : parts[1].substring(3, 6);
|
|
2689
|
+
if (parts[1].substring(3, 6) === "POS" && parts[1].length > 6) {
|
|
2690
|
+
processPosition2(decodeResult, parts[1].substring(6).split(","));
|
|
1980
2691
|
}
|
|
1981
|
-
decodeResult
|
|
1982
|
-
|
|
2692
|
+
processMessageType(decodeResult, type);
|
|
2693
|
+
} else {
|
|
2694
|
+
decodeResult.remaining.text += messageType;
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
function processMessageType(decodeResult, type) {
|
|
2698
|
+
if (type === "FPN") {
|
|
2699
|
+
decodeResult.formatted.description = "Flight Plan";
|
|
2700
|
+
} else if (type === "FTX") {
|
|
2701
|
+
decodeResult.formatted.description = "Free Text";
|
|
2702
|
+
} else if (type === "INI") {
|
|
2703
|
+
decodeResult.formatted.description = "Flight Plan Initial Report";
|
|
2704
|
+
} else if (type === "POS") {
|
|
2705
|
+
decodeResult.formatted.description = "Position Report";
|
|
2706
|
+
} else if (type === "PRG") {
|
|
2707
|
+
decodeResult.formatted.description = "Progress Report";
|
|
2708
|
+
} else {
|
|
2709
|
+
decodeResult.formatted.description = "Unknown H1 Message";
|
|
1983
2710
|
}
|
|
1984
|
-
decodeResult.remaining.text += messageType;
|
|
1985
|
-
return false;
|
|
1986
2711
|
}
|
|
1987
2712
|
function processDC(decodeResult, data) {
|
|
1988
2713
|
decodeResult.raw.message_date = data[0];
|
|
@@ -1991,13 +2716,9 @@ function processDC(decodeResult, data) {
|
|
|
1991
2716
|
const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
|
|
1992
2717
|
const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
|
|
1993
2718
|
decodeResult.raw.message_timestamp = time;
|
|
1994
|
-
} else {
|
|
1995
|
-
return false;
|
|
1996
2719
|
}
|
|
1997
|
-
return true;
|
|
1998
2720
|
}
|
|
1999
2721
|
function processPS(decodeResult, data) {
|
|
2000
|
-
let allKnownFields = true;
|
|
2001
2722
|
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
|
|
2002
2723
|
if (position) {
|
|
2003
2724
|
decodeResult.raw.position = position;
|
|
@@ -2007,11 +2728,7 @@ function processPS(decodeResult, data) {
|
|
|
2007
2728
|
label: "Aircraft Position",
|
|
2008
2729
|
value: CoordinateUtils.coordinateString(position)
|
|
2009
2730
|
});
|
|
2010
|
-
} else {
|
|
2011
|
-
allKnownFields = false;
|
|
2012
2731
|
}
|
|
2013
|
-
console.log("PS data.length: ", data.length);
|
|
2014
|
-
console.log("PS data: ", data);
|
|
2015
2732
|
if (data.length === 9) {
|
|
2016
2733
|
processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
|
|
2017
2734
|
ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
|
|
@@ -2029,11 +2746,8 @@ function processPS(decodeResult, data) {
|
|
|
2029
2746
|
ResultFormatter.unknown(decodeResult, data[9]);
|
|
2030
2747
|
ResultFormatter.unknown(decodeResult, data.slice(11).join(","));
|
|
2031
2748
|
}
|
|
2032
|
-
allKnownFields = false;
|
|
2033
|
-
return allKnownFields;
|
|
2034
2749
|
}
|
|
2035
2750
|
function processPosition2(decodeResult, data) {
|
|
2036
|
-
let allKnownFields = true;
|
|
2037
2751
|
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
|
|
2038
2752
|
if (position) {
|
|
2039
2753
|
decodeResult.raw.position = position;
|
|
@@ -2043,11 +2757,7 @@ function processPosition2(decodeResult, data) {
|
|
|
2043
2757
|
label: "Aircraft Position",
|
|
2044
2758
|
value: CoordinateUtils.coordinateString(position)
|
|
2045
2759
|
});
|
|
2046
|
-
} else {
|
|
2047
|
-
allKnownFields = false;
|
|
2048
2760
|
}
|
|
2049
|
-
console.log("data.length: ", data.length);
|
|
2050
|
-
console.log("data: ", data);
|
|
2051
2761
|
if (data.length >= 10) {
|
|
2052
2762
|
ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
|
|
2053
2763
|
processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
|
|
@@ -2061,8 +2771,6 @@ function processPosition2(decodeResult, data) {
|
|
|
2061
2771
|
ResultFormatter.unknown(decodeResult, data[12]);
|
|
2062
2772
|
ResultFormatter.unknown(decodeResult, data[13]);
|
|
2063
2773
|
}
|
|
2064
|
-
allKnownFields = false;
|
|
2065
|
-
return allKnownFields;
|
|
2066
2774
|
}
|
|
2067
2775
|
function processRoute(decodeResult, last, time, next, eta, then, date) {
|
|
2068
2776
|
const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
|
|
@@ -2085,229 +2793,24 @@ function processRoute(decodeResult, last, time, next, eta, then, date) {
|
|
|
2085
2793
|
});
|
|
2086
2794
|
}
|
|
2087
2795
|
|
|
2088
|
-
// lib/plugins/
|
|
2089
|
-
var
|
|
2090
|
-
name = "label-h1
|
|
2796
|
+
// lib/plugins/Label_H1.ts
|
|
2797
|
+
var Label_H1 = class extends DecoderPlugin {
|
|
2798
|
+
name = "label-h1";
|
|
2091
2799
|
qualifiers() {
|
|
2092
2800
|
return {
|
|
2093
|
-
labels: ["H1"]
|
|
2094
|
-
preambles: ["FPN", "#M1BFPN"]
|
|
2801
|
+
labels: ["H1"]
|
|
2095
2802
|
};
|
|
2096
2803
|
}
|
|
2097
2804
|
decode(message, options = {}) {
|
|
2098
2805
|
let decodeResult = this.defaultResult();
|
|
2099
2806
|
decodeResult.decoder.name = this.name;
|
|
2100
|
-
decodeResult.formatted.description = "Flight Plan";
|
|
2101
2807
|
decodeResult.message = message;
|
|
2102
2808
|
decodeResult.remaining.text = "";
|
|
2103
2809
|
const msg = message.text.replace(/\n|\r/g, "");
|
|
2104
|
-
const
|
|
2105
|
-
decodeResult.decoded =
|
|
2106
|
-
decodeResult.decoder.decodeLevel =
|
|
2107
|
-
if (decodeResult.formatted.items.length === 0) {
|
|
2108
|
-
if (options?.debug) {
|
|
2109
|
-
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2110
|
-
}
|
|
2111
|
-
decodeResult.remaining.text = message.text;
|
|
2112
|
-
decodeResult.decoded = false;
|
|
2113
|
-
decodeResult.decoder.decodeLevel = "none";
|
|
2114
|
-
}
|
|
2115
|
-
return decodeResult;
|
|
2116
|
-
}
|
|
2117
|
-
};
|
|
2118
|
-
|
|
2119
|
-
// lib/plugins/Label_H1_FTX.ts
|
|
2120
|
-
var Label_H1_FTX = class extends DecoderPlugin {
|
|
2121
|
-
name = "label-h1-ftx";
|
|
2122
|
-
qualifiers() {
|
|
2123
|
-
return {
|
|
2124
|
-
labels: ["H1"],
|
|
2125
|
-
preambles: ["FTX", "- #MDFTX"]
|
|
2126
|
-
};
|
|
2127
|
-
}
|
|
2128
|
-
decode(message, options = {}) {
|
|
2129
|
-
let decodeResult = this.defaultResult();
|
|
2130
|
-
decodeResult.decoder.name = this.name;
|
|
2131
|
-
decodeResult.formatted.description = "Free Text";
|
|
2132
|
-
decodeResult.message = message;
|
|
2133
|
-
decodeResult.remaining.text = "";
|
|
2134
|
-
const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
|
|
2135
|
-
decodeResult.decoded = true;
|
|
2136
|
-
decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
|
|
2137
|
-
if (decodeResult.formatted.items.length === 0) {
|
|
2138
|
-
if (options?.debug) {
|
|
2139
|
-
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2140
|
-
}
|
|
2141
|
-
decodeResult.remaining.text = message.text;
|
|
2142
|
-
decodeResult.decoded = false;
|
|
2143
|
-
decodeResult.decoder.decodeLevel = "none";
|
|
2144
|
-
}
|
|
2145
|
-
return decodeResult;
|
|
2146
|
-
}
|
|
2147
|
-
};
|
|
2148
|
-
|
|
2149
|
-
// lib/plugins/Label_H1_INI.ts
|
|
2150
|
-
var Label_H1_INI = class extends DecoderPlugin {
|
|
2151
|
-
// eslint-disable-line camelcase
|
|
2152
|
-
name = "label-h1-ini";
|
|
2153
|
-
qualifiers() {
|
|
2154
|
-
return {
|
|
2155
|
-
labels: ["H1"],
|
|
2156
|
-
preambles: ["INI", "- #MDINI"]
|
|
2157
|
-
};
|
|
2158
|
-
}
|
|
2159
|
-
decode(message, options = {}) {
|
|
2160
|
-
const decodeResult = this.defaultResult();
|
|
2161
|
-
decodeResult.decoder.name = this.name;
|
|
2162
|
-
decodeResult.formatted.description = "Flight Plan Initial Report";
|
|
2163
|
-
decodeResult.message = message;
|
|
2164
|
-
decodeResult.remaining.text = "";
|
|
2165
|
-
const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
|
|
2166
|
-
decodeResult.decoded = true;
|
|
2167
|
-
decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
|
|
2168
|
-
if (decodeResult.formatted.items.length === 0) {
|
|
2169
|
-
if (options?.debug) {
|
|
2170
|
-
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2171
|
-
}
|
|
2172
|
-
decodeResult.remaining.text = message.text;
|
|
2173
|
-
decodeResult.decoded = false;
|
|
2174
|
-
decodeResult.decoder.decodeLevel = "none";
|
|
2175
|
-
}
|
|
2176
|
-
return decodeResult;
|
|
2177
|
-
}
|
|
2178
|
-
};
|
|
2179
|
-
|
|
2180
|
-
// lib/plugins/Label_H1_OHMA.ts
|
|
2181
|
-
import * as zlib from "minizlib";
|
|
2182
|
-
var Label_H1_OHMA = class extends DecoderPlugin {
|
|
2183
|
-
name = "label-h1-ohma";
|
|
2184
|
-
qualifiers() {
|
|
2185
|
-
return {
|
|
2186
|
-
labels: ["H1"],
|
|
2187
|
-
preambles: ["OHMA", "/RTNBOCR.OHMA", "#T1B/RTNBOCR.OHMA"]
|
|
2188
|
-
};
|
|
2189
|
-
}
|
|
2190
|
-
decode(message, options = {}) {
|
|
2191
|
-
let decodeResult = this.defaultResult();
|
|
2192
|
-
decodeResult.decoder.name = this.name;
|
|
2193
|
-
decodeResult.formatted.description = "OHMA Message";
|
|
2194
|
-
decodeResult.message = message;
|
|
2195
|
-
decodeResult.remaining.text = "";
|
|
2196
|
-
const data = message.text.split("OHMA")[1];
|
|
2197
|
-
try {
|
|
2198
|
-
const compressedBuffer = Buffer.from(data, "base64");
|
|
2199
|
-
const decompress = new zlib.Inflate({ windowBits: 15 });
|
|
2200
|
-
decompress.write(compressedBuffer);
|
|
2201
|
-
decompress.flush(zlib.constants.Z_SYNC_FLUSH);
|
|
2202
|
-
const result = decompress.read();
|
|
2203
|
-
const jsonText = result.toString();
|
|
2204
|
-
let formattedMsg;
|
|
2205
|
-
let jsonMessage;
|
|
2206
|
-
try {
|
|
2207
|
-
jsonMessage = JSON.parse(jsonText).message;
|
|
2208
|
-
} catch {
|
|
2209
|
-
jsonMessage = jsonText;
|
|
2210
|
-
}
|
|
2211
|
-
try {
|
|
2212
|
-
const ohmaMsg = JSON.parse(jsonMessage);
|
|
2213
|
-
formattedMsg = JSON.stringify(ohmaMsg, null, 2);
|
|
2214
|
-
} catch {
|
|
2215
|
-
formattedMsg = jsonMessage;
|
|
2216
|
-
}
|
|
2217
|
-
decodeResult.decoded = true;
|
|
2218
|
-
decodeResult.decoder.decodeLevel = "full";
|
|
2219
|
-
decodeResult.raw.ohma = jsonText;
|
|
2220
|
-
decodeResult.formatted.items.push({
|
|
2221
|
-
type: "ohma",
|
|
2222
|
-
code: "OHMA",
|
|
2223
|
-
label: "OHMA Downlink",
|
|
2224
|
-
value: formattedMsg
|
|
2225
|
-
});
|
|
2226
|
-
} catch (e) {
|
|
2227
|
-
if (options.debug) {
|
|
2228
|
-
console.log(`Decoder: Unknown H1 OHMA message: ${message.text}`, e);
|
|
2229
|
-
}
|
|
2230
|
-
decodeResult.remaining.text += message.text;
|
|
2231
|
-
decodeResult.decoded = false;
|
|
2232
|
-
decodeResult.decoder.decodeLevel = "none";
|
|
2233
|
-
}
|
|
2234
|
-
return decodeResult;
|
|
2235
|
-
}
|
|
2236
|
-
};
|
|
2237
|
-
|
|
2238
|
-
// lib/plugins/Label_H1_POS.ts
|
|
2239
|
-
var Label_H1_POS = class extends DecoderPlugin {
|
|
2240
|
-
name = "label-h1-pos";
|
|
2241
|
-
qualifiers() {
|
|
2242
|
-
return {
|
|
2243
|
-
labels: ["H1", "4J"],
|
|
2244
|
-
preambles: ["POS", "#M1BPOS", "/.POS"]
|
|
2245
|
-
//TODO - support data before #
|
|
2246
|
-
};
|
|
2247
|
-
}
|
|
2248
|
-
decode(message, options = {}) {
|
|
2249
|
-
let decodeResult = this.defaultResult();
|
|
2250
|
-
decodeResult.decoder.name = this.name;
|
|
2251
|
-
decodeResult.formatted.description = "Position Report";
|
|
2252
|
-
decodeResult.message = message;
|
|
2253
|
-
decodeResult.remaining.text = "";
|
|
2254
|
-
const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
|
|
2255
|
-
decodeResult.decoded = true;
|
|
2256
|
-
decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
|
|
2810
|
+
const decoded = H1Helper.decodeH1Message(decodeResult, msg);
|
|
2811
|
+
decodeResult.decoded = decoded;
|
|
2812
|
+
decodeResult.decoder.decodeLevel = decodeResult.remaining.text.length === 0 ? "full" : "partial";
|
|
2257
2813
|
if (decodeResult.formatted.items.length === 0) {
|
|
2258
|
-
if (options?.debug) {
|
|
2259
|
-
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2260
|
-
}
|
|
2261
|
-
decodeResult.remaining.text = message.text;
|
|
2262
|
-
decodeResult.decoded = false;
|
|
2263
|
-
decodeResult.decoder.decodeLevel = "none";
|
|
2264
|
-
}
|
|
2265
|
-
return decodeResult;
|
|
2266
|
-
}
|
|
2267
|
-
};
|
|
2268
|
-
|
|
2269
|
-
// lib/plugins/Label_H1_WRN.ts
|
|
2270
|
-
var Label_H1_WRN = class extends DecoderPlugin {
|
|
2271
|
-
name = "label-h1-wrn";
|
|
2272
|
-
qualifiers() {
|
|
2273
|
-
return {
|
|
2274
|
-
labels: ["H1"],
|
|
2275
|
-
preambles: ["WRN", "#CFBWRN"]
|
|
2276
|
-
};
|
|
2277
|
-
}
|
|
2278
|
-
decode(message, options = {}) {
|
|
2279
|
-
let decodeResult = this.defaultResult();
|
|
2280
|
-
decodeResult.decoder.name = this.name;
|
|
2281
|
-
decodeResult.formatted.description = "Warning Message";
|
|
2282
|
-
decodeResult.message = message;
|
|
2283
|
-
const parts = message.text.split("/WN");
|
|
2284
|
-
if (parts.length > 1) {
|
|
2285
|
-
decodeResult.remaining.text = "";
|
|
2286
|
-
const fields = parts[0].split("/");
|
|
2287
|
-
for (let i = 1; i < fields.length; i++) {
|
|
2288
|
-
const field = fields[i];
|
|
2289
|
-
if (field.startsWith("PN")) {
|
|
2290
|
-
processUnknown2(decodeResult, "/" + field);
|
|
2291
|
-
} else {
|
|
2292
|
-
processUnknown2(decodeResult, "/" + field);
|
|
2293
|
-
}
|
|
2294
|
-
}
|
|
2295
|
-
const data = parts[1].substring(0, 20);
|
|
2296
|
-
const msg = parts[1].substring(20);
|
|
2297
|
-
const datetime = data.substring(0, 12);
|
|
2298
|
-
const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
|
|
2299
|
-
processUnknown2(decodeResult, data.substring(12));
|
|
2300
|
-
decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
|
|
2301
|
-
decodeResult.raw.warning_message = msg;
|
|
2302
|
-
decodeResult.formatted.items.push({
|
|
2303
|
-
type: "warning",
|
|
2304
|
-
code: "WRN",
|
|
2305
|
-
label: "Warning Message",
|
|
2306
|
-
value: decodeResult.raw.warning_message
|
|
2307
|
-
});
|
|
2308
|
-
decodeResult.decoded = true;
|
|
2309
|
-
decodeResult.decoder.decodeLevel = "partial";
|
|
2310
|
-
} else {
|
|
2311
2814
|
if (options.debug) {
|
|
2312
2815
|
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2313
2816
|
}
|
|
@@ -2318,9 +2821,6 @@ var Label_H1_WRN = class extends DecoderPlugin {
|
|
|
2318
2821
|
return decodeResult;
|
|
2319
2822
|
}
|
|
2320
2823
|
};
|
|
2321
|
-
function processUnknown2(decodeResult, value) {
|
|
2322
|
-
decodeResult.remaining.text += value;
|
|
2323
|
-
}
|
|
2324
2824
|
|
|
2325
2825
|
// lib/plugins/Label_HX.ts
|
|
2326
2826
|
var Label_HX = class extends DecoderPlugin {
|
|
@@ -2365,7 +2865,7 @@ var Label_HX = class extends DecoderPlugin {
|
|
|
2365
2865
|
});
|
|
2366
2866
|
}
|
|
2367
2867
|
if (decodeResult.decoded) {
|
|
2368
|
-
if (decodeResult.remaining.text
|
|
2868
|
+
if (!decodeResult.remaining.text)
|
|
2369
2869
|
decodeResult.decoder.decodeLevel = "full";
|
|
2370
2870
|
else
|
|
2371
2871
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -2520,7 +3020,7 @@ var Label_QR = class extends DecoderPlugin {
|
|
|
2520
3020
|
}
|
|
2521
3021
|
];
|
|
2522
3022
|
decodeResult.decoded = true;
|
|
2523
|
-
if (decodeResult.remaining.text
|
|
3023
|
+
if (!decodeResult.remaining.text)
|
|
2524
3024
|
decodeResult.decoder.decodeLevel = "full";
|
|
2525
3025
|
else
|
|
2526
3026
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -2565,7 +3065,7 @@ var Label_QP = class extends DecoderPlugin {
|
|
|
2565
3065
|
}
|
|
2566
3066
|
];
|
|
2567
3067
|
decodeResult.decoded = true;
|
|
2568
|
-
if (decodeResult.remaining.text
|
|
3068
|
+
if (!decodeResult.remaining.text)
|
|
2569
3069
|
decodeResult.decoder.decodeLevel = "full";
|
|
2570
3070
|
else
|
|
2571
3071
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -2610,7 +3110,7 @@ var Label_QS = class extends DecoderPlugin {
|
|
|
2610
3110
|
}
|
|
2611
3111
|
];
|
|
2612
3112
|
decodeResult.decoded = true;
|
|
2613
|
-
if (decodeResult.remaining.text
|
|
3113
|
+
if (!decodeResult.remaining.text)
|
|
2614
3114
|
decodeResult.decoder.decodeLevel = "full";
|
|
2615
3115
|
else
|
|
2616
3116
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -2672,7 +3172,7 @@ var Label_QQ = class extends DecoderPlugin {
|
|
|
2672
3172
|
});
|
|
2673
3173
|
}
|
|
2674
3174
|
decodeResult.decoded = true;
|
|
2675
|
-
if (decodeResult.remaining.text
|
|
3175
|
+
if (!decodeResult.remaining.text)
|
|
2676
3176
|
decodeResult.decoder.decodeLevel = "full";
|
|
2677
3177
|
else
|
|
2678
3178
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -3492,32 +3992,38 @@ var MessageDecoder = class {
|
|
|
3492
3992
|
this.plugins = [];
|
|
3493
3993
|
this.debug = false;
|
|
3494
3994
|
this.registerPlugin(new Label_ColonComma(this));
|
|
3495
|
-
this.registerPlugin(new
|
|
3995
|
+
this.registerPlugin(new Label_5Z_Slash(this));
|
|
3496
3996
|
this.registerPlugin(new Label_10_LDR(this));
|
|
3497
3997
|
this.registerPlugin(new Label_10_POS(this));
|
|
3498
3998
|
this.registerPlugin(new Label_10_Slash(this));
|
|
3499
3999
|
this.registerPlugin(new Label_12_N_Space(this));
|
|
4000
|
+
this.registerPlugin(new Label_13Through18_Slash(this));
|
|
3500
4001
|
this.registerPlugin(new Label_15(this));
|
|
3501
4002
|
this.registerPlugin(new Label_15_FST(this));
|
|
3502
4003
|
this.registerPlugin(new Label_16_N_Space(this));
|
|
3503
4004
|
this.registerPlugin(new Label_20_POS(this));
|
|
3504
4005
|
this.registerPlugin(new Label_21_POS(this));
|
|
4006
|
+
this.registerPlugin(new Label_24_Slash(this));
|
|
3505
4007
|
this.registerPlugin(new Label_30_Slash_EA(this));
|
|
3506
4008
|
this.registerPlugin(new Label_44_ETA(this));
|
|
3507
4009
|
this.registerPlugin(new Label_44_IN(this));
|
|
3508
4010
|
this.registerPlugin(new Label_44_OFF(this));
|
|
3509
4011
|
this.registerPlugin(new Label_44_ON(this));
|
|
3510
4012
|
this.registerPlugin(new Label_44_POS(this));
|
|
4013
|
+
this.registerPlugin(new Label_4A(this));
|
|
4014
|
+
this.registerPlugin(new Label_4A_01(this));
|
|
4015
|
+
this.registerPlugin(new Label_4A_DIS(this));
|
|
4016
|
+
this.registerPlugin(new Label_4A_DOOR(this));
|
|
4017
|
+
this.registerPlugin(new Label_4A_Slash_01(this));
|
|
4018
|
+
this.registerPlugin(new Label_4N(this));
|
|
3511
4019
|
this.registerPlugin(new Label_B6_Forwardslash(this));
|
|
3512
|
-
this.registerPlugin(new Label_H1_FPN(this));
|
|
3513
4020
|
this.registerPlugin(new Label_H1_FLR(this));
|
|
3514
|
-
this.registerPlugin(new Label_H1_FTX(this));
|
|
3515
|
-
this.registerPlugin(new Label_H1_INI(this));
|
|
3516
4021
|
this.registerPlugin(new Label_H1_OHMA(this));
|
|
3517
|
-
this.registerPlugin(new Label_H1_POS(this));
|
|
3518
4022
|
this.registerPlugin(new Label_H1_WRN(this));
|
|
4023
|
+
this.registerPlugin(new Label_H1(this));
|
|
3519
4024
|
this.registerPlugin(new Label_HX(this));
|
|
3520
4025
|
this.registerPlugin(new Label_80(this));
|
|
4026
|
+
this.registerPlugin(new Label_83(this));
|
|
3521
4027
|
this.registerPlugin(new Label_8E(this));
|
|
3522
4028
|
this.registerPlugin(new Label_1M_Slash(this));
|
|
3523
4029
|
this.registerPlugin(new Label_SQ(this));
|
|
@@ -3562,29 +4068,30 @@ var MessageDecoder = class {
|
|
|
3562
4068
|
console.log("Usable plugins");
|
|
3563
4069
|
console.log(usablePlugins);
|
|
3564
4070
|
}
|
|
3565
|
-
let result
|
|
3566
|
-
|
|
3567
|
-
|
|
4071
|
+
let result = {
|
|
4072
|
+
decoded: false,
|
|
4073
|
+
error: "No known decoder plugin for this message",
|
|
4074
|
+
decoder: {
|
|
4075
|
+
name: "none",
|
|
4076
|
+
type: "none",
|
|
4077
|
+
decodeLevel: "none"
|
|
4078
|
+
},
|
|
4079
|
+
message,
|
|
4080
|
+
remaining: {
|
|
4081
|
+
text: message.text
|
|
4082
|
+
},
|
|
4083
|
+
raw: {},
|
|
4084
|
+
formatted: {
|
|
4085
|
+
description: "Not Decoded",
|
|
4086
|
+
items: []
|
|
4087
|
+
}
|
|
4088
|
+
};
|
|
4089
|
+
for (let i = 0; i < usablePlugins.length; i++) {
|
|
4090
|
+
const plugin = usablePlugins[i];
|
|
3568
4091
|
result = plugin.decode(message);
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
error: "No known decoder plugin for this message",
|
|
3573
|
-
decoder: {
|
|
3574
|
-
name: "none",
|
|
3575
|
-
type: "none",
|
|
3576
|
-
decodeLevel: "none"
|
|
3577
|
-
},
|
|
3578
|
-
message,
|
|
3579
|
-
remaining: {
|
|
3580
|
-
text: message.text
|
|
3581
|
-
},
|
|
3582
|
-
raw: {},
|
|
3583
|
-
formatted: {
|
|
3584
|
-
description: "Not Decoded",
|
|
3585
|
-
items: []
|
|
3586
|
-
}
|
|
3587
|
-
};
|
|
4092
|
+
if (result.decoded) {
|
|
4093
|
+
break;
|
|
4094
|
+
}
|
|
3588
4095
|
}
|
|
3589
4096
|
if (options.debug) {
|
|
3590
4097
|
console.log("Result");
|