@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.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 departureAirport(decodeResult, value) {
146
- decodeResult.raw.departure_icao = value;
346
+ static callsign(decodeResult, value) {
347
+ decodeResult.raw.callsign = value;
147
348
  decodeResult.formatted.items.push({
148
- type: "origin",
149
- code: "ORG",
150
- label: "Origin",
151
- value: decodeResult.raw.departure_icao
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
- decodeResult.raw.arrival_icao = value;
165
- decodeResult.formatted.items.push({
166
- type: "destination",
167
- code: "DST",
168
- label: "Destination",
169
- value: decodeResult.raw.arrival_icao
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 eta(decodeResult, value) {
173
- decodeResult.raw.eta_time = value;
402
+ static alternateAirport(decodeResult, value) {
403
+ decodeResult.raw.alternate_icao = value;
174
404
  decodeResult.formatted.items.push({
175
- type: "eta",
176
- code: "ETA",
177
- label: "Estimated Time of Arrival",
178
- value: value.substring(0, 2) + ":" + value.substring(2, 4) + ":" + value.substring(4, 6)
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.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
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/Label_5Z.ts
250
- var Label_5Z = class extends DecoderPlugin {
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 uaRegex = /^\/(?<type>\w+) (?<remainder>.+)/;
287
- let results = message.text.match(uaRegex);
288
- if (results && results.length >= 2) {
289
- const type = results.groups.type.split("/")[0];
290
- const { remainder } = results.groups;
291
- const typeDescription = this.descriptions[type] ? this.descriptions[type] : "Unknown";
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 rdcRegex = /^(?<from>\w\w\w)(?<to>\w\w\w) (?<unknown1>\d\d) R(?<runway>.+) G(?<unknown2>.+)$/;
306
- results = remainder.match(rdcRegex);
307
- if (results) {
308
- ResultFormatter.departureAirport(decodeResult, results.groups.from);
309
- ResultFormatter.arrivalAirport(decodeResult, results.groups.to);
310
- ResultFormatter.arrivalRunway(decodeResult, results.groups.runway);
311
- } else {
312
- if (options.debug) {
313
- console.log(`Decoder: Unkown 5Z RDC format: ${remainder}`);
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
- decodeResult.remaining.text = remainder;
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?.debug) {
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
- decodeResult.remaining.text = [...parts.slice(0, 5), parts[11], ...parts.slice(13)].join(",");
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?.debug) {
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/DateTimeUtils.ts
417
- var DateTimeUtils = class {
418
- // Expects a four digit UTC time string (HHMM)
419
- static UTCToString(UTCString) {
420
- let utcDate = /* @__PURE__ */ new Date();
421
- utcDate.setUTCHours(+UTCString.substr(0, 2), +UTCString.substr(2, 2), 0);
422
- return utcDate.toTimeString();
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
- // Expects a six digit date string and a four digit UTC time string
425
- // (DDMMYY) (HHMM)
426
- static UTCDateTimeToString(dateString, timeString) {
427
- let utcDate = /* @__PURE__ */ new Date();
428
- utcDate.setUTCDate(+dateString.substr(0, 2));
429
- utcDate.setUTCMonth(+dateString.substr(2, 2));
430
- if (dateString.length === 6) {
431
- utcDate.setUTCFullYear(2e3 + +dateString.substr(4, 2));
432
- }
433
- if (timeString.length === 6) {
434
- utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), +timeString.substr(4, 2));
435
- } else {
436
- utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), 0);
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.raw.departure_icao = results[3];
818
- decodeResult.raw.arrival_icao = results[4];
819
- decodeResult.raw.alternate_icao = results[5];
820
- decodeResult.raw.arrival_runway = results[8].replace(decodeResult.raw.arrival_icao, "");
821
- decodeResult.formatted.items.push({
822
- type: "eta",
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
- console.log(`DEBUG: ${this.name}: Variation 1 detected`);
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
- console.log(`DEBUG: ${this.name}: Variation 2 detected`);
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
- console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
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
- processAlt(decodeResult, fields[3]);
924
- processTemp(decodeResult, fields[6]);
925
- processArrvApt(decodeResult, fields[8]);
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
- console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
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 false;
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
- if (position) {
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.formatted.items.push({
1014
- type: "eta",
1015
- code: "ETA",
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/Label_80.ts
1319
- var Label_80 = class extends DecoderPlugin {
1320
- name = "label-80";
1321
- descriptions = {
1322
- ALT: "Altitude",
1323
- DWND: "Wind Direction",
1324
- ETA: "Estimated Time of Arrival",
1325
- FOB: "Fuel on Board",
1326
- FL: "Flight Level",
1327
- HDG: "Heading",
1328
- MCH: "Aircraft Speed",
1329
- NWYP: "Next Waypoint",
1330
- POS: "Aircraft Position",
1331
- SAT: "Static Air Temperature",
1332
- SWND: "Wind Speed",
1333
- TAS: "True Airspeed",
1334
- WYP: "Waypoint"
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.raw.origin = results.groups.orig;
1351
- decodeResult.formatted.items.push({
1352
- type: "origin",
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.field) {
1965
+ switch (match.groups?.field) {
1392
1966
  case "ALT": {
1393
- decodeResult.raw.altitude = match.groups.value;
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
- decodeResult.raw.altitude = flight_level * 100;
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.groups.lat) * (posResult.groups.lngd === "S" ? -1 : 1);
1462
- const lon = Number(posResult.groups.lng) * (posResult.groups.lngd === "W" ? -1 : 1);
1463
- const latitude = Number.isInteger(lat) ? lat / 1e3 : lat / 100;
1464
- const longitude = Number.isInteger(lon) ? lon / 1e3 : lon / 100;
1465
- decodeResult.raw.position = {
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
- decodeResult.formatted.items.push({
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.field != void 0) {
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.formatted.items.push({
1529
- type: "eta",
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: ["FLR", "#CFBFLR"]
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 = "Fault Log Report";
2341
+ decodeResult.formatted.description = "Warning Message";
1606
2342
  decodeResult.message = message;
1607
- const parts = message.text.split("/FR");
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
- processUnknown(decodeResult, "/" + field);
2350
+ processUnknown2(decodeResult, "/" + field);
1615
2351
  } else {
1616
- processUnknown(decodeResult, "/" + field);
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
- processUnknown(decodeResult, data.substring(12));
2359
+ processUnknown2(decodeResult, data.substring(12));
1624
2360
  decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
1625
- decodeResult.raw.fault_message = msg;
2361
+ decodeResult.raw.warning_message = msg;
1626
2362
  decodeResult.formatted.items.push({
1627
- type: "fault",
1628
- code: "FR",
1629
- label: "Fault Report",
1630
- value: decodeResult.raw.fault_message
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 processUnknown(decodeResult, value) {
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
- allKnownFields = allKnownFields && parseMessageType(decodeResult, fields[0]);
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
- const dt = processDT(decodeResult, data2);
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
- const lr = processLR(decodeResult, data2);
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
- const fp = FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
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
- const af = processAirField(decodeResult, fields[i].substring(2).split(","));
1856
- allKnownFields = allKnownFields && af;
2582
+ processAirField(decodeResult, fields[i].substring(2).split(","));
1857
2583
  } else if (fields[i].startsWith("TD")) {
1858
- const td = processTimeOfDeparture(decodeResult, fields[i].substring(2).split(","));
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 allKnownFields;
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
- return true;
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
- return true;
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
- decodeResult.raw.tail = data[0];
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
- allKnownFields = false;
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
- if (parts[0].startsWith("POS") && parts[0].length !== 3 && !parts[0].startsWith("POS/")) {
1969
- decoded = processPosition2(decodeResult, parts[0].substring(3).split(","));
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 decoded;
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
- if (parts[1].substring(3, 6) === "POS" && parts[1].length !== 6 && parts[1].substring(3, 7) !== "POS/") {
1979
- decoded = processPosition2(decodeResult, parts[1].substring(6).split(","));
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.raw.message_type = messageType;
1982
- return decoded;
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/Label_H1_FPN.ts
2089
- var Label_H1_FPN = class extends DecoderPlugin {
2090
- name = "label-h1-fpn";
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 fulllyDecoded = H1Helper.decodeH1Message(decodeResult, msg);
2105
- decodeResult.decoded = true;
2106
- decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
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 Label_5Z(this));
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
- if (usablePlugins.length > 0) {
3567
- const plugin = usablePlugins[0];
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
- } else {
3570
- result = {
3571
- decoded: false,
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");