@airframes/acars-decoder 1.6.11 → 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 +860 -627
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +860 -627
- 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;
|
|
@@ -130,8 +198,124 @@ var CoordinateUtils = class {
|
|
|
130
198
|
}
|
|
131
199
|
};
|
|
132
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
|
+
}
|
|
280
|
+
};
|
|
281
|
+
|
|
133
282
|
// lib/utils/result_formatter.ts
|
|
134
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
|
+
}
|
|
135
319
|
static position(decodeResult, value) {
|
|
136
320
|
decodeResult.raw.position = value;
|
|
137
321
|
decodeResult.formatted.items.push({
|
|
@@ -152,16 +336,41 @@ var ResultFormatter = class {
|
|
|
152
336
|
}
|
|
153
337
|
static flightNumber(decodeResult, value) {
|
|
154
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
|
+
});
|
|
155
345
|
}
|
|
156
|
-
static
|
|
157
|
-
decodeResult.raw.
|
|
346
|
+
static callsign(decodeResult, value) {
|
|
347
|
+
decodeResult.raw.callsign = value;
|
|
158
348
|
decodeResult.formatted.items.push({
|
|
159
|
-
type: "
|
|
160
|
-
code: "
|
|
161
|
-
label: "
|
|
162
|
-
value: decodeResult.raw.
|
|
349
|
+
type: "callsign",
|
|
350
|
+
code: "CALLSIGN",
|
|
351
|
+
label: "Callsign",
|
|
352
|
+
value: decodeResult.raw.callsign
|
|
163
353
|
});
|
|
164
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
|
+
}
|
|
165
374
|
static departureRunway(decodeResult, value) {
|
|
166
375
|
decodeResult.raw.departure_runway = value;
|
|
167
376
|
decodeResult.formatted.items.push({
|
|
@@ -171,33 +380,52 @@ var ResultFormatter = class {
|
|
|
171
380
|
value: decodeResult.raw.departure_runway
|
|
172
381
|
});
|
|
173
382
|
}
|
|
174
|
-
static arrivalAirport(decodeResult, value) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
+
}
|
|
182
401
|
}
|
|
183
402
|
static alternateAirport(decodeResult, value) {
|
|
184
403
|
decodeResult.raw.alternate_icao = value;
|
|
185
404
|
decodeResult.formatted.items.push({
|
|
186
|
-
type: "
|
|
405
|
+
type: "icao",
|
|
187
406
|
code: "ALT_DST",
|
|
188
407
|
label: "Alternate Destination",
|
|
189
408
|
value: decodeResult.raw.alternate_icao
|
|
190
409
|
});
|
|
191
410
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
+
}
|
|
201
429
|
}
|
|
202
430
|
static arrivalRunway(decodeResult, value) {
|
|
203
431
|
decodeResult.raw.arrival_runway = value;
|
|
@@ -254,12 +482,12 @@ var ResultFormatter = class {
|
|
|
254
482
|
});
|
|
255
483
|
}
|
|
256
484
|
static temperature(decodeResult, value) {
|
|
257
|
-
decodeResult.raw.outside_air_temperature = Number(value.
|
|
485
|
+
decodeResult.raw.outside_air_temperature = Number(value.replace("M", "-").replace("P", "+"));
|
|
258
486
|
decodeResult.formatted.items.push({
|
|
259
487
|
type: "outside_air_temperature",
|
|
260
488
|
code: "OATEMP",
|
|
261
489
|
label: "Outside Air Temperature (C)",
|
|
262
|
-
value: `${decodeResult.raw.outside_air_temperature}`
|
|
490
|
+
value: `${decodeResult.raw.outside_air_temperature} degrees`
|
|
263
491
|
});
|
|
264
492
|
}
|
|
265
493
|
static heading(decodeResult, value) {
|
|
@@ -282,42 +510,56 @@ var ResultFormatter = class {
|
|
|
282
510
|
}
|
|
283
511
|
static out(decodeResult, time) {
|
|
284
512
|
decodeResult.raw.out_time = time;
|
|
285
|
-
const date = new Date(time * 1e3);
|
|
286
513
|
decodeResult.formatted.items.push({
|
|
287
514
|
type: "time_of_day",
|
|
288
515
|
code: "OUT",
|
|
289
516
|
label: "Out of Gate Time",
|
|
290
|
-
value:
|
|
517
|
+
value: DateTimeUtils.timestampToString(time, "tod")
|
|
291
518
|
});
|
|
292
519
|
}
|
|
293
520
|
static off(decodeResult, time) {
|
|
294
521
|
decodeResult.raw.off_time = time;
|
|
295
|
-
const date = new Date(time * 1e3);
|
|
296
522
|
decodeResult.formatted.items.push({
|
|
297
523
|
type: "time_of_day",
|
|
298
524
|
code: "OFF",
|
|
299
525
|
label: "Takeoff Time",
|
|
300
|
-
value:
|
|
526
|
+
value: DateTimeUtils.timestampToString(time, "tod")
|
|
301
527
|
});
|
|
302
528
|
}
|
|
303
529
|
static on(decodeResult, time) {
|
|
304
530
|
decodeResult.raw.on_time = time;
|
|
305
|
-
const date = new Date(time * 1e3);
|
|
306
531
|
decodeResult.formatted.items.push({
|
|
307
532
|
type: "time_of_day",
|
|
308
533
|
code: "ON",
|
|
309
534
|
label: "Landing Time",
|
|
310
|
-
value:
|
|
535
|
+
value: DateTimeUtils.timestampToString(time, "tod")
|
|
311
536
|
});
|
|
312
537
|
}
|
|
313
538
|
static in(decodeResult, time) {
|
|
314
539
|
decodeResult.raw.in_time = time;
|
|
315
|
-
const date = new Date(time * 1e3);
|
|
316
540
|
decodeResult.formatted.items.push({
|
|
317
541
|
type: "time_of_day",
|
|
318
542
|
code: "IN",
|
|
319
543
|
label: "In Gate Time",
|
|
320
|
-
value:
|
|
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
|
|
321
563
|
});
|
|
322
564
|
}
|
|
323
565
|
static unknown(decodeResult, value) {
|
|
@@ -325,9 +567,9 @@ var ResultFormatter = class {
|
|
|
325
567
|
}
|
|
326
568
|
};
|
|
327
569
|
|
|
328
|
-
// lib/plugins/
|
|
329
|
-
var
|
|
330
|
-
name = "label-5z";
|
|
570
|
+
// lib/plugins/Label_5Z_Slash.ts
|
|
571
|
+
var Label_5Z_Slash = class extends DecoderPlugin {
|
|
572
|
+
name = "label-5z-slash";
|
|
331
573
|
descriptions = {
|
|
332
574
|
B1: "Request Weight and Balance",
|
|
333
575
|
B3: "Request Departure Clearance",
|
|
@@ -345,6 +587,7 @@ var Label_5Z = class extends DecoderPlugin {
|
|
|
345
587
|
D6: "From-To + Date",
|
|
346
588
|
D7: "From-To + Alternate + Time",
|
|
347
589
|
EO: "In Range",
|
|
590
|
+
ET: "Expected Time",
|
|
348
591
|
PW: "Position Weather",
|
|
349
592
|
RL: "Request Release",
|
|
350
593
|
R3: "Request HOWGOZIT Message",
|
|
@@ -355,48 +598,82 @@ var Label_5Z = class extends DecoderPlugin {
|
|
|
355
598
|
};
|
|
356
599
|
qualifiers() {
|
|
357
600
|
return {
|
|
358
|
-
labels: ["5Z"]
|
|
601
|
+
labels: ["5Z"],
|
|
602
|
+
preambles: ["/"]
|
|
359
603
|
};
|
|
360
604
|
}
|
|
361
605
|
decode(message, options = {}) {
|
|
362
606
|
const decodeResult = this.defaultResult();
|
|
363
607
|
decodeResult.decoder.name = this.name;
|
|
364
608
|
decodeResult.formatted.description = "Airline Designated Downlink";
|
|
365
|
-
const
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
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) {
|
|
371
621
|
decodeResult.raw.airline = "United Airlines";
|
|
372
622
|
decodeResult.formatted.items.push({
|
|
373
623
|
type: "airline",
|
|
624
|
+
code: "AIRLINE",
|
|
374
625
|
label: "Airline",
|
|
375
626
|
value: "United Airlines"
|
|
376
627
|
});
|
|
377
628
|
decodeResult.raw.message_type = type;
|
|
378
629
|
decodeResult.formatted.items.push({
|
|
379
630
|
type: "message_type",
|
|
631
|
+
code: "MSG_TYPE",
|
|
380
632
|
label: "Message Type",
|
|
381
633
|
value: `${typeDescription} (${type})`
|
|
382
634
|
});
|
|
383
|
-
if (type === "B3") {
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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(" ");
|
|
394
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];
|
|
395
670
|
} else {
|
|
396
|
-
|
|
671
|
+
if (options.debug) {
|
|
672
|
+
console.log(`Decoder: Unkown 5Z RDC format: ${message.text}`);
|
|
673
|
+
}
|
|
397
674
|
}
|
|
398
675
|
decodeResult.decoded = true;
|
|
399
|
-
decodeResult.decoder.decodeLevel = "partial";
|
|
676
|
+
decodeResult.decoder.decodeLevel = decodeResult.remaining.text ? "partial" : "full";
|
|
400
677
|
} else {
|
|
401
678
|
if (options.debug) {
|
|
402
679
|
console.log(`Decoder: Unknown 5Z message: ${message.text}`);
|
|
@@ -497,129 +774,6 @@ var Label_10_POS = class extends DecoderPlugin {
|
|
|
497
774
|
}
|
|
498
775
|
};
|
|
499
776
|
|
|
500
|
-
// lib/DateTimeUtils.ts
|
|
501
|
-
var DateTimeUtils = class {
|
|
502
|
-
// Expects a four digit UTC time string (HHMM)
|
|
503
|
-
static UTCToString(UTCString) {
|
|
504
|
-
let utcDate = /* @__PURE__ */ new Date();
|
|
505
|
-
utcDate.setUTCHours(+UTCString.substr(0, 2), +UTCString.substr(2, 2), 0);
|
|
506
|
-
return utcDate.toTimeString();
|
|
507
|
-
}
|
|
508
|
-
// Expects a six digit date string and a four digit UTC time string
|
|
509
|
-
// (DDMMYY) (HHMM)
|
|
510
|
-
static UTCDateTimeToString(dateString, timeString) {
|
|
511
|
-
let utcDate = /* @__PURE__ */ new Date();
|
|
512
|
-
utcDate.setUTCDate(+dateString.substr(0, 2));
|
|
513
|
-
utcDate.setUTCMonth(+dateString.substr(2, 2));
|
|
514
|
-
if (dateString.length === 6) {
|
|
515
|
-
utcDate.setUTCFullYear(2e3 + +dateString.substr(4, 2));
|
|
516
|
-
}
|
|
517
|
-
if (timeString.length === 6) {
|
|
518
|
-
utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), +timeString.substr(4, 2));
|
|
519
|
-
} else {
|
|
520
|
-
utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), 0);
|
|
521
|
-
}
|
|
522
|
-
return utcDate.toUTCString();
|
|
523
|
-
}
|
|
524
|
-
/**
|
|
525
|
-
*
|
|
526
|
-
* @param time HHMMSS
|
|
527
|
-
* @returns seconds since midnight
|
|
528
|
-
*/
|
|
529
|
-
static convertHHMMSSToTod(time) {
|
|
530
|
-
const h = Number(time.substring(0, 2));
|
|
531
|
-
const m = Number(time.substring(2, 4));
|
|
532
|
-
const s = Number(time.substring(4, 6));
|
|
533
|
-
const tod = h * 3600 + m * 60 + s;
|
|
534
|
-
return tod;
|
|
535
|
-
}
|
|
536
|
-
/**
|
|
537
|
-
*
|
|
538
|
-
* @param time HHMMSS
|
|
539
|
-
* @param date MMDDYY or MMDDYYYY
|
|
540
|
-
* @returns seconds since epoch
|
|
541
|
-
*/
|
|
542
|
-
static convertDateTimeToEpoch(time, date) {
|
|
543
|
-
if (date.length === 6) {
|
|
544
|
-
date = date.substring(0, 4) + `20${date.substring(4, 6)}`;
|
|
545
|
-
}
|
|
546
|
-
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`;
|
|
547
|
-
const millis = Date.parse(timestamp);
|
|
548
|
-
return millis / 1e3;
|
|
549
|
-
}
|
|
550
|
-
};
|
|
551
|
-
|
|
552
|
-
// lib/utils/route_utils.ts
|
|
553
|
-
var RouteUtils = class _RouteUtils {
|
|
554
|
-
static routeToString(route) {
|
|
555
|
-
let str = "";
|
|
556
|
-
if (route.name) {
|
|
557
|
-
str += route.name;
|
|
558
|
-
}
|
|
559
|
-
if (route.runway) {
|
|
560
|
-
str += `(${route.runway})`;
|
|
561
|
-
}
|
|
562
|
-
if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
|
|
563
|
-
str += " starting at ";
|
|
564
|
-
} else if (str.length !== 0 && route.waypoints) {
|
|
565
|
-
str += ": ";
|
|
566
|
-
}
|
|
567
|
-
if (route.waypoints) {
|
|
568
|
-
str += _RouteUtils.waypointsToString(route.waypoints);
|
|
569
|
-
}
|
|
570
|
-
return str;
|
|
571
|
-
}
|
|
572
|
-
static waypointToString(waypoint) {
|
|
573
|
-
let s = waypoint.name;
|
|
574
|
-
if (waypoint.latitude && waypoint.longitude) {
|
|
575
|
-
s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
|
|
576
|
-
}
|
|
577
|
-
if (waypoint.offset) {
|
|
578
|
-
s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
|
|
579
|
-
}
|
|
580
|
-
if (waypoint.time && waypoint.timeFormat) {
|
|
581
|
-
s += `@${_RouteUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
|
|
582
|
-
}
|
|
583
|
-
return s;
|
|
584
|
-
}
|
|
585
|
-
static getWaypoint(leg) {
|
|
586
|
-
const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
|
|
587
|
-
if (regex?.length == 4) {
|
|
588
|
-
return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
|
|
589
|
-
}
|
|
590
|
-
const waypoint = leg.split(",");
|
|
591
|
-
if (waypoint.length == 2) {
|
|
592
|
-
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
|
|
593
|
-
if (position) {
|
|
594
|
-
return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
if (leg.length == 13 || leg.length == 14) {
|
|
598
|
-
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
|
|
599
|
-
const name = waypoint.length == 2 ? waypoint[0] : "";
|
|
600
|
-
if (position) {
|
|
601
|
-
return { name, latitude: position.latitude, longitude: position.longitude };
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
return { name: leg };
|
|
605
|
-
}
|
|
606
|
-
// move out if we want public
|
|
607
|
-
static timestampToString(time, format) {
|
|
608
|
-
const date = new Date(time * 1e3);
|
|
609
|
-
if (format == "tod") {
|
|
610
|
-
return date.toISOString().slice(11, 19);
|
|
611
|
-
}
|
|
612
|
-
return date.toISOString().slice(0, -5) + "Z";
|
|
613
|
-
}
|
|
614
|
-
static waypointsToString(waypoints) {
|
|
615
|
-
let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
|
|
616
|
-
if (str.startsWith(" > ")) {
|
|
617
|
-
str = ">>" + str.slice(2);
|
|
618
|
-
}
|
|
619
|
-
return str;
|
|
620
|
-
}
|
|
621
|
-
};
|
|
622
|
-
|
|
623
777
|
// lib/plugins/Label_10_Slash.ts
|
|
624
778
|
var Label_10_Slash = class extends DecoderPlugin {
|
|
625
779
|
// eslint-disable-line camelcase
|
|
@@ -655,7 +809,7 @@ var Label_10_Slash = class extends DecoderPlugin {
|
|
|
655
809
|
ResultFormatter.heading(decodeResult, Number(parts[5]));
|
|
656
810
|
ResultFormatter.altitude(decodeResult, 100 * Number(parts[6]));
|
|
657
811
|
ResultFormatter.arrivalAirport(decodeResult, parts[7]);
|
|
658
|
-
ResultFormatter.eta(decodeResult, parts[8] + "00");
|
|
812
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[8] + "00"));
|
|
659
813
|
const waypoints = [{
|
|
660
814
|
name: parts[11]
|
|
661
815
|
}, {
|
|
@@ -989,28 +1143,12 @@ var Label_1M_Slash = class extends DecoderPlugin {
|
|
|
989
1143
|
console.log(results);
|
|
990
1144
|
}
|
|
991
1145
|
decodeResult.raw.flight_number = results[0];
|
|
992
|
-
decodeResult
|
|
993
|
-
decodeResult
|
|
994
|
-
decodeResult
|
|
995
|
-
decodeResult
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
code: "ETA",
|
|
999
|
-
label: "Estimated Time of Arrival",
|
|
1000
|
-
value: DateTimeUtils.UTCDateTimeToString(results[2], results[7])
|
|
1001
|
-
});
|
|
1002
|
-
decodeResult.formatted.items.push({
|
|
1003
|
-
type: "destination",
|
|
1004
|
-
code: "DST",
|
|
1005
|
-
label: "Destination",
|
|
1006
|
-
value: decodeResult.raw.arrival_icao
|
|
1007
|
-
});
|
|
1008
|
-
decodeResult.formatted.items.push({
|
|
1009
|
-
type: "origin",
|
|
1010
|
-
code: "ORG",
|
|
1011
|
-
label: "Origin",
|
|
1012
|
-
value: decodeResult.raw.departure_icao
|
|
1013
|
-
});
|
|
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");
|
|
1014
1152
|
}
|
|
1015
1153
|
decodeResult.decoded = true;
|
|
1016
1154
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -1097,15 +1235,15 @@ var Label_21_POS = class extends DecoderPlugin {
|
|
|
1097
1235
|
const fields = content.split(",");
|
|
1098
1236
|
if (fields.length == 9) {
|
|
1099
1237
|
processPosition(decodeResult, fields[0].trim());
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
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]);
|
|
1103
1243
|
decodeResult.remaining.text = [
|
|
1104
1244
|
fields[1],
|
|
1105
|
-
fields[2],
|
|
1106
1245
|
fields[4],
|
|
1107
|
-
fields[5]
|
|
1108
|
-
fields[7]
|
|
1246
|
+
fields[5]
|
|
1109
1247
|
].join(",");
|
|
1110
1248
|
decodeResult.decoded = true;
|
|
1111
1249
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -1121,7 +1259,7 @@ var Label_21_POS = class extends DecoderPlugin {
|
|
|
1121
1259
|
};
|
|
1122
1260
|
function processPosition(decodeResult, value) {
|
|
1123
1261
|
if (value.length !== 16 && value[0] !== "N" && value[0] !== "S" && value[8] !== "W" && value[8] !== "E") {
|
|
1124
|
-
return
|
|
1262
|
+
return;
|
|
1125
1263
|
}
|
|
1126
1264
|
const latDir = value[0] === "N" ? 1 : -1;
|
|
1127
1265
|
const lonDir = value[8] === "E" ? 1 : -1;
|
|
@@ -1129,45 +1267,52 @@ function processPosition(decodeResult, value) {
|
|
|
1129
1267
|
latitude: latDir * Number(value.substring(1, 7)),
|
|
1130
1268
|
longitude: lonDir * Number(value.substring(9, 15))
|
|
1131
1269
|
};
|
|
1132
|
-
|
|
1133
|
-
decodeResult.raw.position = position;
|
|
1134
|
-
decodeResult.formatted.items.push({
|
|
1135
|
-
type: "aircraft_position",
|
|
1136
|
-
code: "POS",
|
|
1137
|
-
label: "Aircraft Position",
|
|
1138
|
-
value: CoordinateUtils.coordinateString(position)
|
|
1139
|
-
});
|
|
1140
|
-
}
|
|
1141
|
-
return !!position;
|
|
1142
|
-
}
|
|
1143
|
-
function processAlt(decodeResult, value) {
|
|
1144
|
-
decodeResult.raw.altitude = Number(value);
|
|
1145
|
-
decodeResult.formatted.items.push({
|
|
1146
|
-
type: "altitude",
|
|
1147
|
-
code: "ALT",
|
|
1148
|
-
label: "Altitude",
|
|
1149
|
-
value: `${decodeResult.raw.altitude} feet`
|
|
1150
|
-
});
|
|
1151
|
-
}
|
|
1152
|
-
function processTemp(decodeResult, value) {
|
|
1153
|
-
decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
|
|
1154
|
-
decodeResult.formatted.items.push({
|
|
1155
|
-
type: "outside_air_temperature",
|
|
1156
|
-
code: "OATEMP",
|
|
1157
|
-
label: "Outside Air Temperature (C)",
|
|
1158
|
-
value: `${decodeResult.raw.outside_air_temperature}`
|
|
1159
|
-
});
|
|
1160
|
-
}
|
|
1161
|
-
function processArrvApt(decodeResult, value) {
|
|
1162
|
-
decodeResult.raw.arrival_icao = value;
|
|
1163
|
-
decodeResult.formatted.items.push({
|
|
1164
|
-
type: "destination",
|
|
1165
|
-
code: "DST",
|
|
1166
|
-
label: "Destination",
|
|
1167
|
-
value: decodeResult.raw.arrival_icao
|
|
1168
|
-
});
|
|
1270
|
+
ResultFormatter.position(decodeResult, position);
|
|
1169
1271
|
}
|
|
1170
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
|
+
|
|
1171
1316
|
// lib/plugins/Label_30_Slash_EA.ts
|
|
1172
1317
|
var Label_30_Slash_EA = class extends DecoderPlugin {
|
|
1173
1318
|
name = "label-30-slash-ea";
|
|
@@ -1182,27 +1327,16 @@ var Label_30_Slash_EA = class extends DecoderPlugin {
|
|
|
1182
1327
|
decodeResult.decoder.name = this.name;
|
|
1183
1328
|
decodeResult.formatted.description = "ETA Report";
|
|
1184
1329
|
decodeResult.message = message;
|
|
1185
|
-
const results = message.text.split(/\n|\//).slice(1);
|
|
1186
|
-
if (results) {
|
|
1187
|
-
if (options.debug) {
|
|
1188
|
-
console.log(`Label 30 EA: results`);
|
|
1189
|
-
console.log(results);
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
decodeResult.
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
label: "Estimated Time of Arrival",
|
|
1196
|
-
value: DateTimeUtils.UTCToString(results[0].substr(2, 4))
|
|
1197
|
-
});
|
|
1198
|
-
if (results[1].substr(0, 2) === "DS") {
|
|
1199
|
-
decodeResult.raw.arrival_icao = results[1].substr(2, 4);
|
|
1200
|
-
decodeResult.formatted.items.push({
|
|
1201
|
-
type: "destination",
|
|
1202
|
-
code: "DST",
|
|
1203
|
-
label: "Destination",
|
|
1204
|
-
value: decodeResult.raw.arrival_icao
|
|
1205
|
-
});
|
|
1330
|
+
const results = message.text.split(/\n|\//).slice(1);
|
|
1331
|
+
if (results) {
|
|
1332
|
+
if (options.debug) {
|
|
1333
|
+
console.log(`Label 30 EA: results`);
|
|
1334
|
+
console.log(results);
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
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));
|
|
1206
1340
|
decodeResult.remaining.text = "/".concat(results[2]);
|
|
1207
1341
|
} else {
|
|
1208
1342
|
decodeResult.remaining.text = "/".concat(results[1], "/", results[2]);
|
|
@@ -1494,6 +1628,221 @@ var Label_44_POS = class extends DecoderPlugin {
|
|
|
1494
1628
|
}
|
|
1495
1629
|
};
|
|
1496
1630
|
|
|
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
|
+
|
|
1497
1846
|
// lib/plugins/Label_4N.ts
|
|
1498
1847
|
var Label_4N = class extends DecoderPlugin {
|
|
1499
1848
|
name = "label-4n";
|
|
@@ -1507,20 +1856,20 @@ var Label_4N = class extends DecoderPlugin {
|
|
|
1507
1856
|
decodeResult.decoder.name = this.name;
|
|
1508
1857
|
decodeResult.message = message;
|
|
1509
1858
|
decodeResult.formatted.description = "Airline Defined";
|
|
1510
|
-
let
|
|
1511
|
-
if (
|
|
1859
|
+
let text2 = message.text;
|
|
1860
|
+
if (text2.match(/^M\d{2}A\w{6}/)) {
|
|
1512
1861
|
ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
|
|
1513
|
-
|
|
1862
|
+
text2 = text2.substring(10);
|
|
1514
1863
|
}
|
|
1515
1864
|
decodeResult.decoded = true;
|
|
1516
|
-
const fields =
|
|
1517
|
-
if (
|
|
1518
|
-
decodeResult.raw.day_of_month =
|
|
1519
|
-
ResultFormatter.departureAirport(decodeResult,
|
|
1520
|
-
ResultFormatter.arrivalAirport(decodeResult,
|
|
1521
|
-
ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(
|
|
1522
|
-
ResultFormatter.altitude(decodeResult,
|
|
1523
|
-
decodeResult.remaining.text = [
|
|
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(" ");
|
|
1524
1873
|
} else if (fields.length === 33) {
|
|
1525
1874
|
decodeResult.raw.date = fields[3];
|
|
1526
1875
|
if (fields[1] === "B") {
|
|
@@ -1538,10 +1887,10 @@ var Label_4N = class extends DecoderPlugin {
|
|
|
1538
1887
|
decodeResult.remaining.text = [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != "").join(",");
|
|
1539
1888
|
} else {
|
|
1540
1889
|
decodeResult.decoded = false;
|
|
1541
|
-
decodeResult.remaining.text =
|
|
1890
|
+
decodeResult.remaining.text = text2;
|
|
1542
1891
|
}
|
|
1543
1892
|
if (decodeResult.decoded) {
|
|
1544
|
-
if (decodeResult.remaining.text
|
|
1893
|
+
if (!decodeResult.remaining.text)
|
|
1545
1894
|
decodeResult.decoder.decodeLevel = "full";
|
|
1546
1895
|
else
|
|
1547
1896
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -1729,14 +2078,14 @@ var Label_83 = class extends DecoderPlugin {
|
|
|
1729
2078
|
decodeResult.decoder.name = this.name;
|
|
1730
2079
|
decodeResult.message = message;
|
|
1731
2080
|
decodeResult.formatted.description = "Airline Defined";
|
|
1732
|
-
let
|
|
1733
|
-
if (
|
|
2081
|
+
let text2 = message.text;
|
|
2082
|
+
if (text2.match(/^M\d{2}A\w{6}/)) {
|
|
1734
2083
|
ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
|
|
1735
|
-
|
|
2084
|
+
text2 = text2.substring(10);
|
|
1736
2085
|
}
|
|
1737
2086
|
decodeResult.decoded = true;
|
|
1738
|
-
if (
|
|
1739
|
-
const fields =
|
|
2087
|
+
if (text2.substring(0, 10) === "4DH3 ETAT2") {
|
|
2088
|
+
const fields = text2.split(/\s+/);
|
|
1740
2089
|
if (fields[2].length > 5) {
|
|
1741
2090
|
decodeResult.raw.day_of_month = fields[2].substring(5);
|
|
1742
2091
|
}
|
|
@@ -1745,14 +2094,17 @@ var Label_83 = class extends DecoderPlugin {
|
|
|
1745
2094
|
ResultFormatter.departureAirport(decodeResult, subfields[0]);
|
|
1746
2095
|
ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
|
|
1747
2096
|
ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
|
|
1748
|
-
ResultFormatter.eta(decodeResult, fields[6] + "00");
|
|
1749
|
-
} else if (
|
|
1750
|
-
decodeResult.raw.day_of_month =
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
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);
|
|
1754
2106
|
} else {
|
|
1755
|
-
const fields =
|
|
2107
|
+
const fields = text2.replace(/\s/g, "").split(",");
|
|
1756
2108
|
if (fields.length === 9) {
|
|
1757
2109
|
ResultFormatter.departureAirport(decodeResult, fields[0]);
|
|
1758
2110
|
ResultFormatter.arrivalAirport(decodeResult, fields[1]);
|
|
@@ -1765,7 +2117,7 @@ var Label_83 = class extends DecoderPlugin {
|
|
|
1765
2117
|
longitude: Number(fields[4].replace(/\s/g, ""))
|
|
1766
2118
|
}
|
|
1767
2119
|
);
|
|
1768
|
-
ResultFormatter.altitude(decodeResult, fields[5]);
|
|
2120
|
+
ResultFormatter.altitude(decodeResult, Number(fields[5]));
|
|
1769
2121
|
ResultFormatter.groundspeed(decodeResult, fields[6]);
|
|
1770
2122
|
ResultFormatter.heading(decodeResult, fields[7]);
|
|
1771
2123
|
decodeResult.remaining.text = fields[8];
|
|
@@ -1775,7 +2127,7 @@ var Label_83 = class extends DecoderPlugin {
|
|
|
1775
2127
|
}
|
|
1776
2128
|
}
|
|
1777
2129
|
if (decodeResult.decoded) {
|
|
1778
|
-
if (decodeResult.remaining.text
|
|
2130
|
+
if (!decodeResult.remaining.text)
|
|
1779
2131
|
decodeResult.decoder.decodeLevel = "full";
|
|
1780
2132
|
else
|
|
1781
2133
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -1806,19 +2158,8 @@ var Label_8E = class extends DecoderPlugin {
|
|
|
1806
2158
|
console.log(`Label 8E ETA: groups`);
|
|
1807
2159
|
console.log(results.groups);
|
|
1808
2160
|
}
|
|
1809
|
-
decodeResult.
|
|
1810
|
-
|
|
1811
|
-
code: "ETA",
|
|
1812
|
-
label: "Estimated Time of Arrival",
|
|
1813
|
-
value: DateTimeUtils.UTCToString(results.groups.arrival_eta)
|
|
1814
|
-
});
|
|
1815
|
-
decodeResult.raw.arrival_icao = results.groups.arrival_icao;
|
|
1816
|
-
decodeResult.formatted.items.push({
|
|
1817
|
-
type: "destination",
|
|
1818
|
-
code: "DST",
|
|
1819
|
-
label: "Destination",
|
|
1820
|
-
value: decodeResult.raw.arrival_icao
|
|
1821
|
-
});
|
|
2161
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta + "00"));
|
|
2162
|
+
ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
|
|
1822
2163
|
}
|
|
1823
2164
|
decodeResult.decoded = true;
|
|
1824
2165
|
decodeResult.decoder.decodeLevel = "full";
|
|
@@ -1871,44 +2212,158 @@ var Label_ColonComma = class extends DecoderPlugin {
|
|
|
1871
2212
|
}
|
|
1872
2213
|
};
|
|
1873
2214
|
|
|
1874
|
-
// lib/plugins/Label_H1_FLR.ts
|
|
1875
|
-
var Label_H1_FLR = class extends DecoderPlugin {
|
|
1876
|
-
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";
|
|
1877
2332
|
qualifiers() {
|
|
1878
2333
|
return {
|
|
1879
2334
|
labels: ["H1"],
|
|
1880
|
-
preambles: ["
|
|
2335
|
+
preambles: ["WRN", "#CFBWRN"]
|
|
1881
2336
|
};
|
|
1882
2337
|
}
|
|
1883
2338
|
decode(message, options = {}) {
|
|
1884
2339
|
let decodeResult = this.defaultResult();
|
|
1885
2340
|
decodeResult.decoder.name = this.name;
|
|
1886
|
-
decodeResult.formatted.description = "
|
|
2341
|
+
decodeResult.formatted.description = "Warning Message";
|
|
1887
2342
|
decodeResult.message = message;
|
|
1888
|
-
const parts = message.text.split("/
|
|
2343
|
+
const parts = message.text.split("/WN");
|
|
1889
2344
|
if (parts.length > 1) {
|
|
1890
2345
|
decodeResult.remaining.text = "";
|
|
1891
2346
|
const fields = parts[0].split("/");
|
|
1892
2347
|
for (let i = 1; i < fields.length; i++) {
|
|
1893
2348
|
const field = fields[i];
|
|
1894
2349
|
if (field.startsWith("PN")) {
|
|
1895
|
-
|
|
2350
|
+
processUnknown2(decodeResult, "/" + field);
|
|
1896
2351
|
} else {
|
|
1897
|
-
|
|
2352
|
+
processUnknown2(decodeResult, "/" + field);
|
|
1898
2353
|
}
|
|
1899
2354
|
}
|
|
1900
2355
|
const data = parts[1].substring(0, 20);
|
|
1901
2356
|
const msg = parts[1].substring(20);
|
|
1902
2357
|
const datetime = data.substring(0, 12);
|
|
1903
2358
|
const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
|
|
1904
|
-
|
|
2359
|
+
processUnknown2(decodeResult, data.substring(12));
|
|
1905
2360
|
decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
|
|
1906
|
-
decodeResult.raw.
|
|
2361
|
+
decodeResult.raw.warning_message = msg;
|
|
1907
2362
|
decodeResult.formatted.items.push({
|
|
1908
|
-
type: "
|
|
1909
|
-
code: "
|
|
1910
|
-
label: "
|
|
1911
|
-
value: decodeResult.raw.
|
|
2363
|
+
type: "warning",
|
|
2364
|
+
code: "WRN",
|
|
2365
|
+
label: "Warning Message",
|
|
2366
|
+
value: decodeResult.raw.warning_message
|
|
1912
2367
|
});
|
|
1913
2368
|
decodeResult.decoded = true;
|
|
1914
2369
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -1923,7 +2378,7 @@ var Label_H1_FLR = class extends DecoderPlugin {
|
|
|
1923
2378
|
return decodeResult;
|
|
1924
2379
|
}
|
|
1925
2380
|
};
|
|
1926
|
-
function
|
|
2381
|
+
function processUnknown2(decodeResult, value) {
|
|
1927
2382
|
decodeResult.remaining.text += value;
|
|
1928
2383
|
}
|
|
1929
2384
|
|
|
@@ -2089,11 +2544,10 @@ function addCompanyRoute(decodeResult, value) {
|
|
|
2089
2544
|
// lib/utils/h1_helper.ts
|
|
2090
2545
|
var H1Helper = class {
|
|
2091
2546
|
static decodeH1Message(decodeResult, message) {
|
|
2092
|
-
let allKnownFields = true;
|
|
2093
2547
|
const checksum = message.slice(-4);
|
|
2094
2548
|
const data = message.slice(0, message.length - 4);
|
|
2095
2549
|
const fields = data.split("/");
|
|
2096
|
-
|
|
2550
|
+
parseMessageType(decodeResult, fields[0]);
|
|
2097
2551
|
for (let i = 1; i < fields.length; ++i) {
|
|
2098
2552
|
if (fields[i].startsWith("FN")) {
|
|
2099
2553
|
decodeResult.raw.flight_number = fields[i].substring(2);
|
|
@@ -2112,32 +2566,22 @@ var H1Helper = class {
|
|
|
2112
2566
|
decodeResult.raw.message_timestamp = time;
|
|
2113
2567
|
} else if (fields[i].startsWith("PS")) {
|
|
2114
2568
|
const pos = processPS(decodeResult, fields[i].substring(2).split(","));
|
|
2115
|
-
allKnownFields == allKnownFields && pos;
|
|
2116
2569
|
} else if (fields[i].startsWith("DT")) {
|
|
2117
2570
|
const data2 = fields[i].substring(2).split(",");
|
|
2118
|
-
|
|
2119
|
-
allKnownFields = allKnownFields && dt;
|
|
2571
|
+
processDT(decodeResult, data2);
|
|
2120
2572
|
} else if (fields[i].startsWith("ID")) {
|
|
2121
2573
|
processIdentification(decodeResult, fields[i].substring(2).split(","));
|
|
2122
2574
|
} else if (fields[i].startsWith("LR")) {
|
|
2123
2575
|
const data2 = fields[i].substring(2).split(",");
|
|
2124
|
-
|
|
2125
|
-
allKnownFields = allKnownFields && lr;
|
|
2576
|
+
processLR(decodeResult, data2);
|
|
2126
2577
|
} else if (fields[i].startsWith("RI") || fields[i].startsWith("RF") || fields[i].startsWith("RP")) {
|
|
2127
|
-
|
|
2128
|
-
allKnownFields = allKnownFields && fp;
|
|
2578
|
+
FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
|
|
2129
2579
|
} else if (fields[i].startsWith("PR")) {
|
|
2130
|
-
allKnownFields = false;
|
|
2131
2580
|
decodeResult.remaining.text += "/" + fields[i];
|
|
2132
|
-
} else if (fields[i].startsWith("PS")) {
|
|
2133
|
-
allKnownFields = false;
|
|
2134
|
-
decodeResult.remaining.text += fields[i];
|
|
2135
2581
|
} else if (fields[i].startsWith("AF")) {
|
|
2136
|
-
|
|
2137
|
-
allKnownFields = allKnownFields && af;
|
|
2582
|
+
processAirField(decodeResult, fields[i].substring(2).split(","));
|
|
2138
2583
|
} else if (fields[i].startsWith("TD")) {
|
|
2139
|
-
|
|
2140
|
-
allKnownFields = allKnownFields && td;
|
|
2584
|
+
processTimeOfDeparture(decodeResult, fields[i].substring(2).split(","));
|
|
2141
2585
|
} else if (fields[i].startsWith("FX")) {
|
|
2142
2586
|
decodeResult.raw.free_text = fields[i].substring(2);
|
|
2143
2587
|
decodeResult.formatted.items.push({
|
|
@@ -2148,23 +2592,21 @@ var H1Helper = class {
|
|
|
2148
2592
|
});
|
|
2149
2593
|
} else {
|
|
2150
2594
|
decodeResult.remaining.text += "/" + fields[i];
|
|
2151
|
-
allKnownFields = false;
|
|
2152
2595
|
}
|
|
2153
2596
|
}
|
|
2154
2597
|
if (decodeResult.formatted.items.length > 0) {
|
|
2155
2598
|
ResultFormatter.checksum(decodeResult, checksum);
|
|
2156
2599
|
}
|
|
2157
|
-
return
|
|
2600
|
+
return true;
|
|
2158
2601
|
}
|
|
2159
2602
|
};
|
|
2160
2603
|
function processAirField(decodeResult, data) {
|
|
2161
2604
|
if (data.length === 2) {
|
|
2162
2605
|
ResultFormatter.departureAirport(decodeResult, data[0]);
|
|
2163
2606
|
ResultFormatter.arrivalAirport(decodeResult, data[1]);
|
|
2164
|
-
|
|
2607
|
+
} else {
|
|
2608
|
+
decodeResult.remaining.text += "AF/" + data.join(",");
|
|
2165
2609
|
}
|
|
2166
|
-
decodeResult.remaining.text += "AF/" + data.join(",");
|
|
2167
|
-
return false;
|
|
2168
2610
|
}
|
|
2169
2611
|
function processTimeOfDeparture(decodeResult, data) {
|
|
2170
2612
|
if (data.length === 2) {
|
|
@@ -2182,10 +2624,9 @@ function processTimeOfDeparture(decodeResult, data) {
|
|
|
2182
2624
|
label: "Estimated Departure Time",
|
|
2183
2625
|
value: `${data[1].substring(0, 2)}:${data[1].substring(2)}`
|
|
2184
2626
|
});
|
|
2185
|
-
|
|
2627
|
+
} else {
|
|
2628
|
+
decodeResult.remaining.text += "/TD" + data.join(",");
|
|
2186
2629
|
}
|
|
2187
|
-
decodeResult.remaining.text += "/TD" + data.join(",");
|
|
2188
|
-
return false;
|
|
2189
2630
|
}
|
|
2190
2631
|
function processIdentification(decodeResult, data) {
|
|
2191
2632
|
ResultFormatter.tail(decodeResult, data[0]);
|
|
@@ -2197,7 +2638,6 @@ function processIdentification(decodeResult, data) {
|
|
|
2197
2638
|
}
|
|
2198
2639
|
}
|
|
2199
2640
|
function processDT(decodeResult, data) {
|
|
2200
|
-
let allKnownFields = true;
|
|
2201
2641
|
if (!decodeResult.raw.arrival_icao) {
|
|
2202
2642
|
ResultFormatter.arrivalAirport(decodeResult, data[0]);
|
|
2203
2643
|
} else if (decodeResult.raw.arrival_icao != data[0]) {
|
|
@@ -2210,19 +2650,16 @@ function processDT(decodeResult, data) {
|
|
|
2210
2650
|
ResultFormatter.currentFuel(decodeResult, Number(data[2]));
|
|
2211
2651
|
}
|
|
2212
2652
|
if (data.length > 3) {
|
|
2213
|
-
ResultFormatter.eta(decodeResult, data[3]);
|
|
2653
|
+
ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[3]));
|
|
2214
2654
|
}
|
|
2215
2655
|
if (data.length > 4) {
|
|
2216
2656
|
ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
|
|
2217
2657
|
}
|
|
2218
2658
|
if (data.length > 5) {
|
|
2219
|
-
allKnownFields = false;
|
|
2220
2659
|
decodeResult.remaining.text += "," + data.slice(5).join(",");
|
|
2221
2660
|
}
|
|
2222
|
-
return allKnownFields;
|
|
2223
2661
|
}
|
|
2224
2662
|
function processLR(decodeResult, data) {
|
|
2225
|
-
let allKnownFields = true;
|
|
2226
2663
|
if (data.length === 19) {
|
|
2227
2664
|
ResultFormatter.unknown(decodeResult, data[1]);
|
|
2228
2665
|
ResultFormatter.flightNumber(decodeResult, data[2]);
|
|
@@ -2230,34 +2667,47 @@ function processLR(decodeResult, data) {
|
|
|
2230
2667
|
ResultFormatter.arrivalAirport(decodeResult, data[4]);
|
|
2231
2668
|
ResultFormatter.arrivalRunway(decodeResult, data[5]);
|
|
2232
2669
|
ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
|
|
2233
|
-
allKnownFields = false;
|
|
2234
2670
|
} else {
|
|
2235
|
-
|
|
2671
|
+
ResultFormatter.unknown(decodeResult, data.join(","));
|
|
2236
2672
|
}
|
|
2237
|
-
return allKnownFields;
|
|
2238
2673
|
}
|
|
2239
2674
|
function parseMessageType(decodeResult, messageType) {
|
|
2240
|
-
let decoded = true;
|
|
2241
2675
|
const parts = messageType.split("#");
|
|
2242
2676
|
if (parts.length == 1) {
|
|
2243
|
-
|
|
2244
|
-
|
|
2677
|
+
const type = parts[0].substring(0, 3);
|
|
2678
|
+
if (type === "POS" && parts[0].length !== 3) {
|
|
2679
|
+
processPosition2(decodeResult, parts[0].substring(3).split(","));
|
|
2245
2680
|
}
|
|
2246
|
-
return
|
|
2681
|
+
return processMessageType(decodeResult, type);
|
|
2247
2682
|
} else if (parts.length == 2) {
|
|
2248
2683
|
if (parts[0].length > 0) {
|
|
2249
2684
|
decodeResult.remaining.text += parts[0].substring(0, 3);
|
|
2250
2685
|
decodeResult.raw.flight_number = parts[0].substring(3);
|
|
2251
|
-
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));
|
|
2252
2687
|
}
|
|
2253
|
-
|
|
2254
|
-
|
|
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(","));
|
|
2255
2691
|
}
|
|
2256
|
-
decodeResult
|
|
2257
|
-
|
|
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";
|
|
2258
2710
|
}
|
|
2259
|
-
decodeResult.remaining.text += messageType;
|
|
2260
|
-
return false;
|
|
2261
2711
|
}
|
|
2262
2712
|
function processDC(decodeResult, data) {
|
|
2263
2713
|
decodeResult.raw.message_date = data[0];
|
|
@@ -2266,13 +2716,9 @@ function processDC(decodeResult, data) {
|
|
|
2266
2716
|
const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
|
|
2267
2717
|
const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
|
|
2268
2718
|
decodeResult.raw.message_timestamp = time;
|
|
2269
|
-
} else {
|
|
2270
|
-
return false;
|
|
2271
2719
|
}
|
|
2272
|
-
return true;
|
|
2273
2720
|
}
|
|
2274
2721
|
function processPS(decodeResult, data) {
|
|
2275
|
-
let allKnownFields = true;
|
|
2276
2722
|
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
|
|
2277
2723
|
if (position) {
|
|
2278
2724
|
decodeResult.raw.position = position;
|
|
@@ -2282,8 +2728,6 @@ function processPS(decodeResult, data) {
|
|
|
2282
2728
|
label: "Aircraft Position",
|
|
2283
2729
|
value: CoordinateUtils.coordinateString(position)
|
|
2284
2730
|
});
|
|
2285
|
-
} else {
|
|
2286
|
-
allKnownFields = false;
|
|
2287
2731
|
}
|
|
2288
2732
|
if (data.length === 9) {
|
|
2289
2733
|
processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
|
|
@@ -2302,11 +2746,8 @@ function processPS(decodeResult, data) {
|
|
|
2302
2746
|
ResultFormatter.unknown(decodeResult, data[9]);
|
|
2303
2747
|
ResultFormatter.unknown(decodeResult, data.slice(11).join(","));
|
|
2304
2748
|
}
|
|
2305
|
-
allKnownFields = false;
|
|
2306
|
-
return allKnownFields;
|
|
2307
2749
|
}
|
|
2308
2750
|
function processPosition2(decodeResult, data) {
|
|
2309
|
-
let allKnownFields = true;
|
|
2310
2751
|
const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
|
|
2311
2752
|
if (position) {
|
|
2312
2753
|
decodeResult.raw.position = position;
|
|
@@ -2316,8 +2757,6 @@ function processPosition2(decodeResult, data) {
|
|
|
2316
2757
|
label: "Aircraft Position",
|
|
2317
2758
|
value: CoordinateUtils.coordinateString(position)
|
|
2318
2759
|
});
|
|
2319
|
-
} else {
|
|
2320
|
-
allKnownFields = false;
|
|
2321
2760
|
}
|
|
2322
2761
|
if (data.length >= 10) {
|
|
2323
2762
|
ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
|
|
@@ -2332,8 +2771,6 @@ function processPosition2(decodeResult, data) {
|
|
|
2332
2771
|
ResultFormatter.unknown(decodeResult, data[12]);
|
|
2333
2772
|
ResultFormatter.unknown(decodeResult, data[13]);
|
|
2334
2773
|
}
|
|
2335
|
-
allKnownFields = false;
|
|
2336
|
-
return allKnownFields;
|
|
2337
2774
|
}
|
|
2338
2775
|
function processRoute(decodeResult, last, time, next, eta, then, date) {
|
|
2339
2776
|
const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
|
|
@@ -2356,175 +2793,23 @@ function processRoute(decodeResult, last, time, next, eta, then, date) {
|
|
|
2356
2793
|
});
|
|
2357
2794
|
}
|
|
2358
2795
|
|
|
2359
|
-
// lib/plugins/
|
|
2360
|
-
var
|
|
2361
|
-
name = "label-h1
|
|
2796
|
+
// lib/plugins/Label_H1.ts
|
|
2797
|
+
var Label_H1 = class extends DecoderPlugin {
|
|
2798
|
+
name = "label-h1";
|
|
2362
2799
|
qualifiers() {
|
|
2363
2800
|
return {
|
|
2364
|
-
labels: ["H1"]
|
|
2365
|
-
preambles: ["FPN", "#M1BFPN"]
|
|
2801
|
+
labels: ["H1"]
|
|
2366
2802
|
};
|
|
2367
2803
|
}
|
|
2368
2804
|
decode(message, options = {}) {
|
|
2369
2805
|
let decodeResult = this.defaultResult();
|
|
2370
2806
|
decodeResult.decoder.name = this.name;
|
|
2371
|
-
decodeResult.formatted.description = "Flight Plan";
|
|
2372
2807
|
decodeResult.message = message;
|
|
2373
2808
|
decodeResult.remaining.text = "";
|
|
2374
2809
|
const msg = message.text.replace(/\n|\r/g, "");
|
|
2375
|
-
const
|
|
2376
|
-
decodeResult.decoded =
|
|
2377
|
-
decodeResult.decoder.decodeLevel =
|
|
2378
|
-
if (decodeResult.formatted.items.length === 0) {
|
|
2379
|
-
if (options.debug) {
|
|
2380
|
-
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2381
|
-
}
|
|
2382
|
-
decodeResult.remaining.text = message.text;
|
|
2383
|
-
decodeResult.decoded = false;
|
|
2384
|
-
decodeResult.decoder.decodeLevel = "none";
|
|
2385
|
-
}
|
|
2386
|
-
return decodeResult;
|
|
2387
|
-
}
|
|
2388
|
-
};
|
|
2389
|
-
|
|
2390
|
-
// lib/plugins/Label_H1_FTX.ts
|
|
2391
|
-
var Label_H1_FTX = class extends DecoderPlugin {
|
|
2392
|
-
name = "label-h1-ftx";
|
|
2393
|
-
qualifiers() {
|
|
2394
|
-
return {
|
|
2395
|
-
labels: ["H1"],
|
|
2396
|
-
preambles: ["FTX", "- #MDFTX"]
|
|
2397
|
-
};
|
|
2398
|
-
}
|
|
2399
|
-
decode(message, options = {}) {
|
|
2400
|
-
let decodeResult = this.defaultResult();
|
|
2401
|
-
decodeResult.decoder.name = this.name;
|
|
2402
|
-
decodeResult.formatted.description = "Free Text";
|
|
2403
|
-
decodeResult.message = message;
|
|
2404
|
-
decodeResult.remaining.text = "";
|
|
2405
|
-
const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
|
|
2406
|
-
decodeResult.decoded = true;
|
|
2407
|
-
decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
|
|
2408
|
-
if (decodeResult.formatted.items.length === 0) {
|
|
2409
|
-
if (options.debug) {
|
|
2410
|
-
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2411
|
-
}
|
|
2412
|
-
decodeResult.remaining.text = message.text;
|
|
2413
|
-
decodeResult.decoded = false;
|
|
2414
|
-
decodeResult.decoder.decodeLevel = "none";
|
|
2415
|
-
}
|
|
2416
|
-
return decodeResult;
|
|
2417
|
-
}
|
|
2418
|
-
};
|
|
2419
|
-
|
|
2420
|
-
// lib/plugins/Label_H1_INI.ts
|
|
2421
|
-
var Label_H1_INI = class extends DecoderPlugin {
|
|
2422
|
-
// eslint-disable-line camelcase
|
|
2423
|
-
name = "label-h1-ini";
|
|
2424
|
-
qualifiers() {
|
|
2425
|
-
return {
|
|
2426
|
-
labels: ["H1"],
|
|
2427
|
-
preambles: ["INI", "- #MDINI"]
|
|
2428
|
-
};
|
|
2429
|
-
}
|
|
2430
|
-
decode(message, options = {}) {
|
|
2431
|
-
const decodeResult = this.defaultResult();
|
|
2432
|
-
decodeResult.decoder.name = this.name;
|
|
2433
|
-
decodeResult.formatted.description = "Flight Plan Initial Report";
|
|
2434
|
-
decodeResult.message = message;
|
|
2435
|
-
decodeResult.remaining.text = "";
|
|
2436
|
-
const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
|
|
2437
|
-
decodeResult.decoded = true;
|
|
2438
|
-
decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
|
|
2439
|
-
if (decodeResult.formatted.items.length === 0) {
|
|
2440
|
-
if (options.debug) {
|
|
2441
|
-
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2442
|
-
}
|
|
2443
|
-
decodeResult.remaining.text = message.text;
|
|
2444
|
-
decodeResult.decoded = false;
|
|
2445
|
-
decodeResult.decoder.decodeLevel = "none";
|
|
2446
|
-
}
|
|
2447
|
-
return decodeResult;
|
|
2448
|
-
}
|
|
2449
|
-
};
|
|
2450
|
-
|
|
2451
|
-
// lib/plugins/Label_H1_OHMA.ts
|
|
2452
|
-
import * as zlib from "minizlib";
|
|
2453
|
-
var Label_H1_OHMA = class extends DecoderPlugin {
|
|
2454
|
-
name = "label-h1-ohma";
|
|
2455
|
-
qualifiers() {
|
|
2456
|
-
return {
|
|
2457
|
-
labels: ["H1"],
|
|
2458
|
-
preambles: ["OHMA", "/RTNBOCR.OHMA", "#T1B/RTNBOCR.OHMA"]
|
|
2459
|
-
};
|
|
2460
|
-
}
|
|
2461
|
-
decode(message, options = {}) {
|
|
2462
|
-
let decodeResult = this.defaultResult();
|
|
2463
|
-
decodeResult.decoder.name = this.name;
|
|
2464
|
-
decodeResult.formatted.description = "OHMA Message";
|
|
2465
|
-
decodeResult.message = message;
|
|
2466
|
-
decodeResult.remaining.text = "";
|
|
2467
|
-
const data = message.text.split("OHMA")[1];
|
|
2468
|
-
try {
|
|
2469
|
-
const compressedBuffer = Buffer.from(data, "base64");
|
|
2470
|
-
const decompress = new zlib.Inflate({ windowBits: 15 });
|
|
2471
|
-
decompress.write(compressedBuffer);
|
|
2472
|
-
decompress.flush(zlib.constants.Z_SYNC_FLUSH);
|
|
2473
|
-
const result = decompress.read();
|
|
2474
|
-
const jsonText = result.toString();
|
|
2475
|
-
let formattedMsg;
|
|
2476
|
-
let jsonMessage;
|
|
2477
|
-
try {
|
|
2478
|
-
jsonMessage = JSON.parse(jsonText).message;
|
|
2479
|
-
} catch {
|
|
2480
|
-
jsonMessage = jsonText;
|
|
2481
|
-
}
|
|
2482
|
-
try {
|
|
2483
|
-
const ohmaMsg = JSON.parse(jsonMessage);
|
|
2484
|
-
formattedMsg = JSON.stringify(ohmaMsg, null, 2);
|
|
2485
|
-
} catch {
|
|
2486
|
-
formattedMsg = jsonMessage;
|
|
2487
|
-
}
|
|
2488
|
-
decodeResult.decoded = true;
|
|
2489
|
-
decodeResult.decoder.decodeLevel = "full";
|
|
2490
|
-
decodeResult.raw.ohma = jsonText;
|
|
2491
|
-
decodeResult.formatted.items.push({
|
|
2492
|
-
type: "ohma",
|
|
2493
|
-
code: "OHMA",
|
|
2494
|
-
label: "OHMA Downlink",
|
|
2495
|
-
value: formattedMsg
|
|
2496
|
-
});
|
|
2497
|
-
} catch (e) {
|
|
2498
|
-
if (options.debug) {
|
|
2499
|
-
console.log(`Decoder: Unknown H1 OHMA message: ${message.text}`, e);
|
|
2500
|
-
}
|
|
2501
|
-
decodeResult.remaining.text += message.text;
|
|
2502
|
-
decodeResult.decoded = false;
|
|
2503
|
-
decodeResult.decoder.decodeLevel = "none";
|
|
2504
|
-
}
|
|
2505
|
-
return decodeResult;
|
|
2506
|
-
}
|
|
2507
|
-
};
|
|
2508
|
-
|
|
2509
|
-
// lib/plugins/Label_H1_POS.ts
|
|
2510
|
-
var Label_H1_POS = class extends DecoderPlugin {
|
|
2511
|
-
name = "label-h1-pos";
|
|
2512
|
-
qualifiers() {
|
|
2513
|
-
return {
|
|
2514
|
-
labels: ["H1", "4J"],
|
|
2515
|
-
preambles: ["POS", "#M1BPOS", "/.POS"]
|
|
2516
|
-
//TODO - support data before #
|
|
2517
|
-
};
|
|
2518
|
-
}
|
|
2519
|
-
decode(message, options = {}) {
|
|
2520
|
-
let decodeResult = this.defaultResult();
|
|
2521
|
-
decodeResult.decoder.name = this.name;
|
|
2522
|
-
decodeResult.formatted.description = "Position Report";
|
|
2523
|
-
decodeResult.message = message;
|
|
2524
|
-
decodeResult.remaining.text = "";
|
|
2525
|
-
const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
|
|
2526
|
-
decodeResult.decoded = true;
|
|
2527
|
-
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";
|
|
2528
2813
|
if (decodeResult.formatted.items.length === 0) {
|
|
2529
2814
|
if (options.debug) {
|
|
2530
2815
|
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
@@ -2537,62 +2822,6 @@ var Label_H1_POS = class extends DecoderPlugin {
|
|
|
2537
2822
|
}
|
|
2538
2823
|
};
|
|
2539
2824
|
|
|
2540
|
-
// lib/plugins/Label_H1_WRN.ts
|
|
2541
|
-
var Label_H1_WRN = class extends DecoderPlugin {
|
|
2542
|
-
name = "label-h1-wrn";
|
|
2543
|
-
qualifiers() {
|
|
2544
|
-
return {
|
|
2545
|
-
labels: ["H1"],
|
|
2546
|
-
preambles: ["WRN", "#CFBWRN"]
|
|
2547
|
-
};
|
|
2548
|
-
}
|
|
2549
|
-
decode(message, options = {}) {
|
|
2550
|
-
let decodeResult = this.defaultResult();
|
|
2551
|
-
decodeResult.decoder.name = this.name;
|
|
2552
|
-
decodeResult.formatted.description = "Warning Message";
|
|
2553
|
-
decodeResult.message = message;
|
|
2554
|
-
const parts = message.text.split("/WN");
|
|
2555
|
-
if (parts.length > 1) {
|
|
2556
|
-
decodeResult.remaining.text = "";
|
|
2557
|
-
const fields = parts[0].split("/");
|
|
2558
|
-
for (let i = 1; i < fields.length; i++) {
|
|
2559
|
-
const field = fields[i];
|
|
2560
|
-
if (field.startsWith("PN")) {
|
|
2561
|
-
processUnknown2(decodeResult, "/" + field);
|
|
2562
|
-
} else {
|
|
2563
|
-
processUnknown2(decodeResult, "/" + field);
|
|
2564
|
-
}
|
|
2565
|
-
}
|
|
2566
|
-
const data = parts[1].substring(0, 20);
|
|
2567
|
-
const msg = parts[1].substring(20);
|
|
2568
|
-
const datetime = data.substring(0, 12);
|
|
2569
|
-
const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
|
|
2570
|
-
processUnknown2(decodeResult, data.substring(12));
|
|
2571
|
-
decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
|
|
2572
|
-
decodeResult.raw.warning_message = msg;
|
|
2573
|
-
decodeResult.formatted.items.push({
|
|
2574
|
-
type: "warning",
|
|
2575
|
-
code: "WRN",
|
|
2576
|
-
label: "Warning Message",
|
|
2577
|
-
value: decodeResult.raw.warning_message
|
|
2578
|
-
});
|
|
2579
|
-
decodeResult.decoded = true;
|
|
2580
|
-
decodeResult.decoder.decodeLevel = "partial";
|
|
2581
|
-
} else {
|
|
2582
|
-
if (options.debug) {
|
|
2583
|
-
console.log(`Decoder: Unknown H1 message: ${message.text}`);
|
|
2584
|
-
}
|
|
2585
|
-
decodeResult.remaining.text = message.text;
|
|
2586
|
-
decodeResult.decoded = false;
|
|
2587
|
-
decodeResult.decoder.decodeLevel = "none";
|
|
2588
|
-
}
|
|
2589
|
-
return decodeResult;
|
|
2590
|
-
}
|
|
2591
|
-
};
|
|
2592
|
-
function processUnknown2(decodeResult, value) {
|
|
2593
|
-
decodeResult.remaining.text += value;
|
|
2594
|
-
}
|
|
2595
|
-
|
|
2596
2825
|
// lib/plugins/Label_HX.ts
|
|
2597
2826
|
var Label_HX = class extends DecoderPlugin {
|
|
2598
2827
|
name = "label-hx";
|
|
@@ -2636,7 +2865,7 @@ var Label_HX = class extends DecoderPlugin {
|
|
|
2636
2865
|
});
|
|
2637
2866
|
}
|
|
2638
2867
|
if (decodeResult.decoded) {
|
|
2639
|
-
if (decodeResult.remaining.text
|
|
2868
|
+
if (!decodeResult.remaining.text)
|
|
2640
2869
|
decodeResult.decoder.decodeLevel = "full";
|
|
2641
2870
|
else
|
|
2642
2871
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -2791,7 +3020,7 @@ var Label_QR = class extends DecoderPlugin {
|
|
|
2791
3020
|
}
|
|
2792
3021
|
];
|
|
2793
3022
|
decodeResult.decoded = true;
|
|
2794
|
-
if (decodeResult.remaining.text
|
|
3023
|
+
if (!decodeResult.remaining.text)
|
|
2795
3024
|
decodeResult.decoder.decodeLevel = "full";
|
|
2796
3025
|
else
|
|
2797
3026
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -2836,7 +3065,7 @@ var Label_QP = class extends DecoderPlugin {
|
|
|
2836
3065
|
}
|
|
2837
3066
|
];
|
|
2838
3067
|
decodeResult.decoded = true;
|
|
2839
|
-
if (decodeResult.remaining.text
|
|
3068
|
+
if (!decodeResult.remaining.text)
|
|
2840
3069
|
decodeResult.decoder.decodeLevel = "full";
|
|
2841
3070
|
else
|
|
2842
3071
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -2881,7 +3110,7 @@ var Label_QS = class extends DecoderPlugin {
|
|
|
2881
3110
|
}
|
|
2882
3111
|
];
|
|
2883
3112
|
decodeResult.decoded = true;
|
|
2884
|
-
if (decodeResult.remaining.text
|
|
3113
|
+
if (!decodeResult.remaining.text)
|
|
2885
3114
|
decodeResult.decoder.decodeLevel = "full";
|
|
2886
3115
|
else
|
|
2887
3116
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -2943,7 +3172,7 @@ var Label_QQ = class extends DecoderPlugin {
|
|
|
2943
3172
|
});
|
|
2944
3173
|
}
|
|
2945
3174
|
decodeResult.decoded = true;
|
|
2946
|
-
if (decodeResult.remaining.text
|
|
3175
|
+
if (!decodeResult.remaining.text)
|
|
2947
3176
|
decodeResult.decoder.decodeLevel = "full";
|
|
2948
3177
|
else
|
|
2949
3178
|
decodeResult.decoder.decodeLevel = "partial";
|
|
@@ -3763,7 +3992,7 @@ var MessageDecoder = class {
|
|
|
3763
3992
|
this.plugins = [];
|
|
3764
3993
|
this.debug = false;
|
|
3765
3994
|
this.registerPlugin(new Label_ColonComma(this));
|
|
3766
|
-
this.registerPlugin(new
|
|
3995
|
+
this.registerPlugin(new Label_5Z_Slash(this));
|
|
3767
3996
|
this.registerPlugin(new Label_10_LDR(this));
|
|
3768
3997
|
this.registerPlugin(new Label_10_POS(this));
|
|
3769
3998
|
this.registerPlugin(new Label_10_Slash(this));
|
|
@@ -3774,21 +4003,24 @@ var MessageDecoder = class {
|
|
|
3774
4003
|
this.registerPlugin(new Label_16_N_Space(this));
|
|
3775
4004
|
this.registerPlugin(new Label_20_POS(this));
|
|
3776
4005
|
this.registerPlugin(new Label_21_POS(this));
|
|
4006
|
+
this.registerPlugin(new Label_24_Slash(this));
|
|
3777
4007
|
this.registerPlugin(new Label_30_Slash_EA(this));
|
|
3778
4008
|
this.registerPlugin(new Label_44_ETA(this));
|
|
3779
4009
|
this.registerPlugin(new Label_44_IN(this));
|
|
3780
4010
|
this.registerPlugin(new Label_44_OFF(this));
|
|
3781
4011
|
this.registerPlugin(new Label_44_ON(this));
|
|
3782
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));
|
|
3783
4018
|
this.registerPlugin(new Label_4N(this));
|
|
3784
4019
|
this.registerPlugin(new Label_B6_Forwardslash(this));
|
|
3785
|
-
this.registerPlugin(new Label_H1_FPN(this));
|
|
3786
4020
|
this.registerPlugin(new Label_H1_FLR(this));
|
|
3787
|
-
this.registerPlugin(new Label_H1_FTX(this));
|
|
3788
|
-
this.registerPlugin(new Label_H1_INI(this));
|
|
3789
4021
|
this.registerPlugin(new Label_H1_OHMA(this));
|
|
3790
|
-
this.registerPlugin(new Label_H1_POS(this));
|
|
3791
4022
|
this.registerPlugin(new Label_H1_WRN(this));
|
|
4023
|
+
this.registerPlugin(new Label_H1(this));
|
|
3792
4024
|
this.registerPlugin(new Label_HX(this));
|
|
3793
4025
|
this.registerPlugin(new Label_80(this));
|
|
3794
4026
|
this.registerPlugin(new Label_83(this));
|
|
@@ -3836,29 +4068,30 @@ var MessageDecoder = class {
|
|
|
3836
4068
|
console.log("Usable plugins");
|
|
3837
4069
|
console.log(usablePlugins);
|
|
3838
4070
|
}
|
|
3839
|
-
let result
|
|
3840
|
-
|
|
3841
|
-
|
|
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];
|
|
3842
4091
|
result = plugin.decode(message);
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
error: "No known decoder plugin for this message",
|
|
3847
|
-
decoder: {
|
|
3848
|
-
name: "none",
|
|
3849
|
-
type: "none",
|
|
3850
|
-
decodeLevel: "none"
|
|
3851
|
-
},
|
|
3852
|
-
message,
|
|
3853
|
-
remaining: {
|
|
3854
|
-
text: message.text
|
|
3855
|
-
},
|
|
3856
|
-
raw: {},
|
|
3857
|
-
formatted: {
|
|
3858
|
-
description: "Not Decoded",
|
|
3859
|
-
items: []
|
|
3860
|
-
}
|
|
3861
|
-
};
|
|
4092
|
+
if (result.decoded) {
|
|
4093
|
+
break;
|
|
4094
|
+
}
|
|
3862
4095
|
}
|
|
3863
4096
|
if (options.debug) {
|
|
3864
4097
|
console.log("Result");
|