@airframes/acars-decoder 1.6.11 → 1.6.13

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;
@@ -61,7 +129,7 @@ var DecoderPlugin = class {
61
129
  };
62
130
 
63
131
  // lib/utils/coordinate_utils.ts
64
- var CoordinateUtils = class {
132
+ var CoordinateUtils = class _CoordinateUtils {
65
133
  /**
66
134
  * Decode a string of coordinates into an object with latitude and longitude in millidegrees
67
135
  * @param stringCoords - The string of coordinates to decode
@@ -78,8 +146,8 @@ var CoordinateUtils = class {
78
146
  longitudeChars = stringCoords.substring(8, 14);
79
147
  }
80
148
  if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
81
- results.latitude = Number(stringCoords.substring(1, 6)) / 1e3 * (firstChar === "S" ? -1 : 1);
82
- results.longitude = Number(longitudeChars) / 1e3 * (middleChar === "W" ? -1 : 1);
149
+ results.latitude = Number(stringCoords.substring(1, 6)) / 1e3 * _CoordinateUtils.getDirection(firstChar);
150
+ results.longitude = Number(longitudeChars) / 1e3 * _CoordinateUtils.getDirection(middleChar);
83
151
  } else {
84
152
  return;
85
153
  }
@@ -105,8 +173,8 @@ var CoordinateUtils = class {
105
173
  const lonDeg = Math.trunc(Number(longitudeChars) / 1e3);
106
174
  const lonMin = Number(longitudeChars) % 1e3 / 10;
107
175
  if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
108
- results.latitude = (latDeg + latMin / 60) * (firstChar === "S" ? -1 : 1);
109
- results.longitude = (lonDeg + lonMin / 60) * (middleChar === "W" ? -1 : 1);
176
+ results.latitude = (latDeg + latMin / 60) * _CoordinateUtils.getDirection(firstChar);
177
+ results.longitude = (lonDeg + lonMin / 60) * _CoordinateUtils.getDirection(middleChar);
110
178
  } else {
111
179
  return;
112
180
  }
@@ -130,9 +198,137 @@ var CoordinateUtils = class {
130
198
  }
131
199
  };
132
200
 
201
+ // lib/utils/route_utils.ts
202
+ var RouteUtils = class _RouteUtils {
203
+ static formatFlightState(state) {
204
+ switch (state) {
205
+ case "TO":
206
+ return "Takeoff";
207
+ case "IC":
208
+ return "Initial Climb";
209
+ case "CL":
210
+ return "Climb";
211
+ case "ER":
212
+ return "En Route";
213
+ case "DC":
214
+ return "Descent";
215
+ case "AP":
216
+ return "Approach";
217
+ default:
218
+ return `Unknown ${state}`;
219
+ }
220
+ }
221
+ static routeToString(route) {
222
+ let str = "";
223
+ if (route.name) {
224
+ str += route.name;
225
+ }
226
+ if (route.runway) {
227
+ str += `(${route.runway})`;
228
+ }
229
+ if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
230
+ str += " starting at ";
231
+ } else if (str.length !== 0 && route.waypoints) {
232
+ str += ": ";
233
+ }
234
+ if (route.waypoints) {
235
+ str += _RouteUtils.waypointsToString(route.waypoints);
236
+ }
237
+ return str;
238
+ }
239
+ static waypointToString(waypoint) {
240
+ let s = waypoint.name;
241
+ if (waypoint.latitude && waypoint.longitude) {
242
+ s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
243
+ }
244
+ if (waypoint.offset) {
245
+ s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
246
+ }
247
+ if (waypoint.time && waypoint.timeFormat) {
248
+ s += `@${DateTimeUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
249
+ }
250
+ return s;
251
+ }
252
+ static getWaypoint(leg) {
253
+ const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
254
+ if (regex?.length == 4) {
255
+ return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
256
+ }
257
+ const waypoint = leg.split(",");
258
+ if (waypoint.length == 2) {
259
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
260
+ if (position) {
261
+ return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
262
+ }
263
+ }
264
+ if (leg.length == 13 || leg.length == 14) {
265
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
266
+ const name = waypoint.length == 2 ? waypoint[0] : "";
267
+ if (position) {
268
+ return { name, latitude: position.latitude, longitude: position.longitude };
269
+ }
270
+ }
271
+ return { name: leg };
272
+ }
273
+ static waypointsToString(waypoints) {
274
+ let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
275
+ if (str.startsWith(" > ")) {
276
+ str = ">>" + str.slice(2);
277
+ }
278
+ return str;
279
+ }
280
+ };
281
+
133
282
  // lib/utils/result_formatter.ts
134
283
  var ResultFormatter = class {
284
+ static route(decodeResult, route) {
285
+ decodeResult.raw.route = route;
286
+ decodeResult.formatted.items.push({
287
+ type: "aircraft_route",
288
+ code: "ROUTE",
289
+ label: "Aircraft Route",
290
+ value: RouteUtils.routeToString(route)
291
+ });
292
+ }
293
+ static state_change(decodeResult, from, to) {
294
+ decodeResult.raw.state_change = {
295
+ from,
296
+ to
297
+ };
298
+ from = RouteUtils.formatFlightState(from);
299
+ to = RouteUtils.formatFlightState(to);
300
+ decodeResult.formatted.items.push({
301
+ type: "state_change",
302
+ code: "STATE_CHANGE",
303
+ label: "State Change",
304
+ value: `${from} -> ${to}`
305
+ });
306
+ }
307
+ static freetext(decodeResult, value) {
308
+ decodeResult.raw.freetext = value;
309
+ decodeResult.formatted.items.push({
310
+ type: "freetext",
311
+ code: "FREE_TEXT",
312
+ label: "Free Text",
313
+ value
314
+ });
315
+ }
316
+ static door_event(decodeResult, name, state) {
317
+ decodeResult.raw.door_event = {
318
+ door: name,
319
+ state
320
+ };
321
+ decodeResult.formatted.items.push({
322
+ type: "door_event",
323
+ code: "DOOR",
324
+ label: "Door Event",
325
+ value: `${name} ${state}`
326
+ });
327
+ }
135
328
  static position(decodeResult, value) {
329
+ if (!value || isNaN(value.latitude) || isNaN(value.longitude)) {
330
+ return;
331
+ }
136
332
  decodeResult.raw.position = value;
137
333
  decodeResult.formatted.items.push({
138
334
  type: "aircraft_position",
@@ -152,16 +348,41 @@ var ResultFormatter = class {
152
348
  }
153
349
  static flightNumber(decodeResult, value) {
154
350
  decodeResult.raw.flight_number = value;
351
+ decodeResult.formatted.items.push({
352
+ type: "flight_number",
353
+ code: "FLIGHT",
354
+ label: "Flight Number",
355
+ value: decodeResult.raw.flight_number
356
+ });
155
357
  }
156
- static departureAirport(decodeResult, value) {
157
- decodeResult.raw.departure_icao = value;
358
+ static callsign(decodeResult, value) {
359
+ decodeResult.raw.callsign = value;
158
360
  decodeResult.formatted.items.push({
159
- type: "origin",
160
- code: "ORG",
161
- label: "Origin",
162
- value: decodeResult.raw.departure_icao
361
+ type: "callsign",
362
+ code: "CALLSIGN",
363
+ label: "Callsign",
364
+ value: decodeResult.raw.callsign
163
365
  });
164
366
  }
367
+ static departureAirport(decodeResult, value, type = "ICAO") {
368
+ if (type === "ICAO") {
369
+ decodeResult.raw.departure_icao = value;
370
+ decodeResult.formatted.items.push({
371
+ type: "icao",
372
+ code: "ORG",
373
+ label: "Origin",
374
+ value
375
+ });
376
+ } else {
377
+ decodeResult.raw.departure_iata = value;
378
+ decodeResult.formatted.items.push({
379
+ type: "iata",
380
+ code: "ORG",
381
+ label: "Origin",
382
+ value
383
+ });
384
+ }
385
+ }
165
386
  static departureRunway(decodeResult, value) {
166
387
  decodeResult.raw.departure_runway = value;
167
388
  decodeResult.formatted.items.push({
@@ -171,33 +392,52 @@ var ResultFormatter = class {
171
392
  value: decodeResult.raw.departure_runway
172
393
  });
173
394
  }
174
- static arrivalAirport(decodeResult, value) {
175
- decodeResult.raw.arrival_icao = value;
176
- decodeResult.formatted.items.push({
177
- type: "destination",
178
- code: "DST",
179
- label: "Destination",
180
- value: decodeResult.raw.arrival_icao
181
- });
395
+ static arrivalAirport(decodeResult, value, type = "ICAO") {
396
+ if (type === "ICAO") {
397
+ decodeResult.raw.arrival_icao = value;
398
+ decodeResult.formatted.items.push({
399
+ type: "icao",
400
+ code: "DST",
401
+ label: "Destination",
402
+ value
403
+ });
404
+ } else {
405
+ decodeResult.raw.arrival_iata = value;
406
+ decodeResult.formatted.items.push({
407
+ type: "iata",
408
+ code: "DST",
409
+ label: "Destination",
410
+ value
411
+ });
412
+ }
182
413
  }
183
414
  static alternateAirport(decodeResult, value) {
184
415
  decodeResult.raw.alternate_icao = value;
185
416
  decodeResult.formatted.items.push({
186
- type: "destination",
417
+ type: "icao",
187
418
  code: "ALT_DST",
188
419
  label: "Alternate Destination",
189
420
  value: decodeResult.raw.alternate_icao
190
421
  });
191
422
  }
192
- // FIXME - make seconds since midnight for time of day
193
- static eta(decodeResult, value) {
194
- decodeResult.raw.eta_time = value;
195
- decodeResult.formatted.items.push({
196
- type: "eta",
197
- code: "ETA",
198
- label: "Estimated Time of Arrival",
199
- value: value.substring(0, 2) + ":" + value.substring(2, 4) + ":" + value.substring(4, 6)
200
- });
423
+ static eta(decodeResult, time, type = "tod") {
424
+ if (type === "tod") {
425
+ decodeResult.raw.eta_time = time;
426
+ decodeResult.formatted.items.push({
427
+ type: "time_of_day",
428
+ code: "ETA",
429
+ label: "Estimated Time of Arrival",
430
+ value: DateTimeUtils.timestampToString(time, "tod")
431
+ });
432
+ } else {
433
+ decodeResult.raw.eta_date = time;
434
+ decodeResult.formatted.items.push({
435
+ type: "epoch",
436
+ code: "ETA",
437
+ label: "Estimated Time of Arrival",
438
+ value: DateTimeUtils.timestampToString(time, "epoch")
439
+ });
440
+ }
201
441
  }
202
442
  static arrivalRunway(decodeResult, value) {
203
443
  decodeResult.raw.arrival_runway = value;
@@ -254,12 +494,12 @@ var ResultFormatter = class {
254
494
  });
255
495
  }
256
496
  static temperature(decodeResult, value) {
257
- decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
497
+ decodeResult.raw.outside_air_temperature = Number(value.replace("M", "-").replace("P", "+"));
258
498
  decodeResult.formatted.items.push({
259
499
  type: "outside_air_temperature",
260
500
  code: "OATEMP",
261
501
  label: "Outside Air Temperature (C)",
262
- value: `${decodeResult.raw.outside_air_temperature}`
502
+ value: `${decodeResult.raw.outside_air_temperature} degrees`
263
503
  });
264
504
  }
265
505
  static heading(decodeResult, value) {
@@ -282,52 +522,99 @@ var ResultFormatter = class {
282
522
  }
283
523
  static out(decodeResult, time) {
284
524
  decodeResult.raw.out_time = time;
285
- const date = new Date(time * 1e3);
286
525
  decodeResult.formatted.items.push({
287
526
  type: "time_of_day",
288
527
  code: "OUT",
289
528
  label: "Out of Gate Time",
290
- value: date.toISOString().slice(11, 19)
529
+ value: DateTimeUtils.timestampToString(time, "tod")
291
530
  });
292
531
  }
293
532
  static off(decodeResult, time) {
294
533
  decodeResult.raw.off_time = time;
295
- const date = new Date(time * 1e3);
296
534
  decodeResult.formatted.items.push({
297
535
  type: "time_of_day",
298
536
  code: "OFF",
299
537
  label: "Takeoff Time",
300
- value: date.toISOString().slice(11, 19)
538
+ value: DateTimeUtils.timestampToString(time, "tod")
301
539
  });
302
540
  }
303
541
  static on(decodeResult, time) {
304
542
  decodeResult.raw.on_time = time;
305
- const date = new Date(time * 1e3);
306
543
  decodeResult.formatted.items.push({
307
544
  type: "time_of_day",
308
545
  code: "ON",
309
546
  label: "Landing Time",
310
- value: date.toISOString().slice(11, 19)
547
+ value: DateTimeUtils.timestampToString(time, "tod")
311
548
  });
312
549
  }
313
550
  static in(decodeResult, time) {
314
551
  decodeResult.raw.in_time = time;
315
- const date = new Date(time * 1e3);
316
552
  decodeResult.formatted.items.push({
317
553
  type: "time_of_day",
318
554
  code: "IN",
319
555
  label: "In Gate Time",
320
- value: date.toISOString().slice(11, 19)
556
+ value: DateTimeUtils.timestampToString(time, "tod")
557
+ });
558
+ }
559
+ static time_of_day(decodeResult, time) {
560
+ decodeResult.raw.time_of_day = time;
561
+ decodeResult.formatted.items.push({
562
+ type: "time_of_day",
563
+ code: "MSG_TOD",
564
+ label: "Message Timestamp",
565
+ value: DateTimeUtils.timestampToString(time, "tod")
566
+ });
567
+ }
568
+ static day(decodeResult, day) {
569
+ decodeResult.raw.day_of_month = day;
570
+ decodeResult.formatted.items.push({
571
+ type: "day_of_month",
572
+ code: "MSG_DAY",
573
+ label: "Day of Month",
574
+ value: `${day}`
575
+ });
576
+ }
577
+ static departureDay(decodeResult, day) {
578
+ decodeResult.raw.departure_day_of_month = day;
579
+ decodeResult.formatted.items.push({
580
+ type: "day_of_month",
581
+ code: "DEP_DAY",
582
+ label: "Departure Day",
583
+ value: `${day}`
584
+ });
585
+ }
586
+ static arrivalDay(decodeResult, day) {
587
+ decodeResult.raw.arrival_day_of_month = day;
588
+ decodeResult.formatted.items.push({
589
+ type: "day_of_month",
590
+ code: "ARR_DAY",
591
+ label: "Arrival Day",
592
+ value: `${day}`
593
+ });
594
+ }
595
+ static text(decodeResult, text) {
596
+ decodeResult.raw.text = text;
597
+ decodeResult.formatted.items.push({
598
+ type: "text",
599
+ code: "TEXT",
600
+ label: "Text Message",
601
+ value: text
321
602
  });
322
603
  }
323
- static unknown(decodeResult, value) {
324
- decodeResult.remaining.text += "," + value;
604
+ static unknown(decodeResult, value, sep = ",") {
605
+ if (!decodeResult.remaining.text)
606
+ decodeResult.remaining.text = value;
607
+ else
608
+ decodeResult.remaining.text += sep + value;
609
+ }
610
+ static unknownArr(decodeResult, value, sep = ",") {
611
+ this.unknown(decodeResult, value.join(sep), sep);
325
612
  }
326
613
  };
327
614
 
328
- // lib/plugins/Label_5Z.ts
329
- var Label_5Z = class extends DecoderPlugin {
330
- name = "label-5z";
615
+ // lib/plugins/Label_5Z_Slash.ts
616
+ var Label_5Z_Slash = class extends DecoderPlugin {
617
+ name = "label-5z-slash";
331
618
  descriptions = {
332
619
  B1: "Request Weight and Balance",
333
620
  B3: "Request Departure Clearance",
@@ -345,6 +632,7 @@ var Label_5Z = class extends DecoderPlugin {
345
632
  D6: "From-To + Date",
346
633
  D7: "From-To + Alternate + Time",
347
634
  EO: "In Range",
635
+ ET: "Expected Time",
348
636
  PW: "Position Weather",
349
637
  RL: "Request Release",
350
638
  R3: "Request HOWGOZIT Message",
@@ -355,53 +643,87 @@ var Label_5Z = class extends DecoderPlugin {
355
643
  };
356
644
  qualifiers() {
357
645
  return {
358
- labels: ["5Z"]
646
+ labels: ["5Z"],
647
+ preambles: ["/"]
359
648
  };
360
649
  }
361
650
  decode(message, options = {}) {
362
651
  const decodeResult = this.defaultResult();
363
652
  decodeResult.decoder.name = this.name;
364
653
  decodeResult.formatted.description = "Airline Designated Downlink";
365
- const uaRegex = /^\/(?<type>\w+) (?<remainder>.+)/;
366
- let results = message.text.match(uaRegex);
367
- if (results && results.length >= 2) {
368
- const type = results.groups.type.split("/")[0];
369
- const { remainder } = results.groups;
370
- const typeDescription = this.descriptions[type] ? this.descriptions[type] : "Unknown";
654
+ const lines = message.text.split("\r\n");
655
+ if (lines[0] === "/TXT") {
656
+ ResultFormatter.text(decodeResult, lines.slice(1).join("\r\n"));
657
+ decodeResult.decoded = true;
658
+ decodeResult.decoder.decodeLevel = "full";
659
+ return decodeResult;
660
+ }
661
+ const data = lines[0].split("/");
662
+ const header = data[1].split(" ");
663
+ const type = header[0];
664
+ const typeDescription = this.descriptions[type];
665
+ if (typeDescription) {
371
666
  decodeResult.raw.airline = "United Airlines";
372
667
  decodeResult.formatted.items.push({
373
668
  type: "airline",
669
+ code: "AIRLINE",
374
670
  label: "Airline",
375
671
  value: "United Airlines"
376
672
  });
377
673
  decodeResult.raw.message_type = type;
378
674
  decodeResult.formatted.items.push({
379
675
  type: "message_type",
676
+ code: "MSG_TYPE",
380
677
  label: "Message Type",
381
678
  value: `${typeDescription} (${type})`
382
679
  });
383
- if (type === "B3") {
384
- const rdcRegex = /^(?<from>\w\w\w)(?<to>\w\w\w) (?<unknown1>\d\d) R(?<runway>.+) G(?<unknown2>.+)$/;
385
- results = remainder.match(rdcRegex);
386
- if (results) {
387
- ResultFormatter.departureAirport(decodeResult, results.groups.from);
388
- ResultFormatter.arrivalAirport(decodeResult, results.groups.to);
389
- ResultFormatter.arrivalRunway(decodeResult, results.groups.runway);
390
- } else {
391
- if (options.debug) {
392
- console.log(`Decoder: Unkown 5Z RDC format: ${remainder}`);
393
- }
680
+ if (type === "B3" && data[1] === "B3 TO DATA REQ ") {
681
+ const info = data[2].split(" ");
682
+ ResultFormatter.departureAirport(decodeResult, info[1]);
683
+ ResultFormatter.arrivalAirport(decodeResult, info[2]);
684
+ decodeResult.raw.day_of_month = Number(info[3]);
685
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
686
+ ResultFormatter.arrivalRunway(decodeResult, info[5].slice(1));
687
+ ResultFormatter.unknownArr(decodeResult, data.slice(3), "/");
688
+ } else if (type === "B3") {
689
+ ResultFormatter.departureAirport(decodeResult, header[1].substring(0, 3), "IATA");
690
+ ResultFormatter.arrivalAirport(decodeResult, header[1].substring(3), "IATA");
691
+ decodeResult.raw.day_of_month = Number(header[2]);
692
+ ResultFormatter.arrivalRunway(decodeResult, header[3].slice(1));
693
+ if (header.length > 4) {
694
+ ResultFormatter.unknownArr(decodeResult, header.slice(4), "/");
394
695
  }
696
+ } else if (type === "C3" && data[1] === "C3 GATE REQ ") {
697
+ const info = data[2].split(" ");
698
+ ResultFormatter.departureAirport(decodeResult, info[1]);
699
+ ResultFormatter.arrivalAirport(decodeResult, info[2]);
700
+ decodeResult.raw.day_of_month = Number(info[3]);
701
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
702
+ ResultFormatter.unknownArr(decodeResult, info.slice(5), " ");
703
+ } else if (type === "C3") {
704
+ ResultFormatter.departureAirport(decodeResult, header[1].substring(0, 3), "IATA");
705
+ ResultFormatter.arrivalAirport(decodeResult, header[1].substring(3), "IATA");
706
+ } else if (type === "ET") {
707
+ const airports = data[2].split(" ");
708
+ ResultFormatter.departureAirport(decodeResult, airports[1]);
709
+ ResultFormatter.arrivalAirport(decodeResult, airports[2]);
710
+ decodeResult.raw.day_of_month = Number(airports[3]);
711
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(airports[4]));
712
+ const estimates = data[3].split(" ");
713
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(estimates[1] + "00"));
714
+ ResultFormatter.unknown(decodeResult, estimates[2]);
395
715
  } else {
396
- decodeResult.remaining.text = remainder;
716
+ if (options.debug) {
717
+ console.log(`Decoder: Unkown 5Z RDC format: ${message.text}`);
718
+ }
397
719
  }
398
720
  decodeResult.decoded = true;
399
- decodeResult.decoder.decodeLevel = "partial";
721
+ decodeResult.decoder.decodeLevel = decodeResult.remaining.text ? "partial" : "full";
400
722
  } else {
401
723
  if (options.debug) {
402
724
  console.log(`Decoder: Unknown 5Z message: ${message.text}`);
403
725
  }
404
- decodeResult.remaining.text = message.text;
726
+ ResultFormatter.unknown(decodeResult, message.text);
405
727
  decodeResult.decoded = false;
406
728
  decodeResult.decoder.decodeLevel = "none";
407
729
  }
@@ -429,7 +751,7 @@ var Label_10_LDR = class extends DecoderPlugin {
429
751
  if (options.debug) {
430
752
  console.log(`Decoder: Unknown 10 message: ${message.text}`);
431
753
  }
432
- decodeResult.remaining.text = message.text;
754
+ ResultFormatter.unknown(decodeResult, message.text);
433
755
  decodeResult.decoded = false;
434
756
  decodeResult.decoder.decodeLevel = "none";
435
757
  return decodeResult;
@@ -450,7 +772,7 @@ var Label_10_LDR = class extends DecoderPlugin {
450
772
  if (altRwy != "") {
451
773
  ResultFormatter.alternateRunway(decodeResult, altRwy);
452
774
  }
453
- decodeResult.remaining.text = [...parts.slice(0, 5), ...parts.slice(15)].join(",");
775
+ ResultFormatter.unknownArr(decodeResult, [...parts.slice(0, 5), ...parts.slice(15)]);
454
776
  decodeResult.decoded = true;
455
777
  decodeResult.decoder.decodeLevel = "partial";
456
778
  return decodeResult;
@@ -477,7 +799,7 @@ var Label_10_POS = class extends DecoderPlugin {
477
799
  if (options.debug) {
478
800
  console.log(`Decoder: Unknown 10 message: ${message.text}`);
479
801
  }
480
- decodeResult.remaining.text = message.text;
802
+ ResultFormatter.unknown(decodeResult, message.text);
481
803
  decodeResult.decoded = false;
482
804
  decodeResult.decoder.decodeLevel = "none";
483
805
  return decodeResult;
@@ -490,160 +812,37 @@ var Label_10_POS = class extends DecoderPlugin {
490
812
  };
491
813
  ResultFormatter.position(decodeResult, position);
492
814
  ResultFormatter.altitude(decodeResult, Number(parts[7]));
493
- decodeResult.remaining.text = [parts[0], ...parts.slice(3, 7), ...parts.slice(8)].join(",");
815
+ ResultFormatter.unknownArr(decodeResult, [parts[0], ...parts.slice(3, 7), ...parts.slice(8)]);
494
816
  decodeResult.decoded = true;
495
817
  decodeResult.decoder.decodeLevel = "partial";
496
818
  return decodeResult;
497
819
  }
498
820
  };
499
821
 
500
- // lib/DateTimeUtils.ts
501
- var DateTimeUtils = class {
502
- // Expects a four digit UTC time string (HHMM)
503
- static UTCToString(UTCString) {
504
- let utcDate = /* @__PURE__ */ new Date();
505
- utcDate.setUTCHours(+UTCString.substr(0, 2), +UTCString.substr(2, 2), 0);
506
- return utcDate.toTimeString();
822
+ // lib/plugins/Label_10_Slash.ts
823
+ var Label_10_Slash = class extends DecoderPlugin {
824
+ // eslint-disable-line camelcase
825
+ name = "label-10-slash";
826
+ qualifiers() {
827
+ return {
828
+ labels: ["10"],
829
+ preambles: ["/"]
830
+ };
507
831
  }
508
- // Expects a six digit date string and a four digit UTC time string
509
- // (DDMMYY) (HHMM)
510
- static UTCDateTimeToString(dateString, timeString) {
511
- let utcDate = /* @__PURE__ */ new Date();
512
- utcDate.setUTCDate(+dateString.substr(0, 2));
513
- utcDate.setUTCMonth(+dateString.substr(2, 2));
514
- if (dateString.length === 6) {
515
- utcDate.setUTCFullYear(2e3 + +dateString.substr(4, 2));
516
- }
517
- if (timeString.length === 6) {
518
- utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), +timeString.substr(4, 2));
519
- } else {
520
- utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), 0);
521
- }
522
- return utcDate.toUTCString();
523
- }
524
- /**
525
- *
526
- * @param time HHMMSS
527
- * @returns seconds since midnight
528
- */
529
- static convertHHMMSSToTod(time) {
530
- const h = Number(time.substring(0, 2));
531
- const m = Number(time.substring(2, 4));
532
- const s = Number(time.substring(4, 6));
533
- const tod = h * 3600 + m * 60 + s;
534
- return tod;
535
- }
536
- /**
537
- *
538
- * @param time HHMMSS
539
- * @param date MMDDYY or MMDDYYYY
540
- * @returns seconds since epoch
541
- */
542
- static convertDateTimeToEpoch(time, date) {
543
- if (date.length === 6) {
544
- date = date.substring(0, 4) + `20${date.substring(4, 6)}`;
545
- }
546
- const timestamp = `${date.substring(4, 8)}-${date.substring(0, 2)}-${date.substring(2, 4)}T${time.substring(0, 2)}:${time.substring(2, 4)}:${time.substring(4, 6)}.000Z`;
547
- const millis = Date.parse(timestamp);
548
- return millis / 1e3;
549
- }
550
- };
551
-
552
- // lib/utils/route_utils.ts
553
- var RouteUtils = class _RouteUtils {
554
- static routeToString(route) {
555
- let str = "";
556
- if (route.name) {
557
- str += route.name;
558
- }
559
- if (route.runway) {
560
- str += `(${route.runway})`;
561
- }
562
- if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
563
- str += " starting at ";
564
- } else if (str.length !== 0 && route.waypoints) {
565
- str += ": ";
566
- }
567
- if (route.waypoints) {
568
- str += _RouteUtils.waypointsToString(route.waypoints);
569
- }
570
- return str;
571
- }
572
- static waypointToString(waypoint) {
573
- let s = waypoint.name;
574
- if (waypoint.latitude && waypoint.longitude) {
575
- s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
576
- }
577
- if (waypoint.offset) {
578
- s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
579
- }
580
- if (waypoint.time && waypoint.timeFormat) {
581
- s += `@${_RouteUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
582
- }
583
- return s;
584
- }
585
- static getWaypoint(leg) {
586
- const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
587
- if (regex?.length == 4) {
588
- return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
589
- }
590
- const waypoint = leg.split(",");
591
- if (waypoint.length == 2) {
592
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
593
- if (position) {
594
- return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
595
- }
596
- }
597
- if (leg.length == 13 || leg.length == 14) {
598
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
599
- const name = waypoint.length == 2 ? waypoint[0] : "";
600
- if (position) {
601
- return { name, latitude: position.latitude, longitude: position.longitude };
602
- }
603
- }
604
- return { name: leg };
605
- }
606
- // move out if we want public
607
- static timestampToString(time, format) {
608
- const date = new Date(time * 1e3);
609
- if (format == "tod") {
610
- return date.toISOString().slice(11, 19);
611
- }
612
- return date.toISOString().slice(0, -5) + "Z";
613
- }
614
- static waypointsToString(waypoints) {
615
- let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
616
- if (str.startsWith(" > ")) {
617
- str = ">>" + str.slice(2);
618
- }
619
- return str;
620
- }
621
- };
622
-
623
- // lib/plugins/Label_10_Slash.ts
624
- var Label_10_Slash = class extends DecoderPlugin {
625
- // eslint-disable-line camelcase
626
- name = "label-10-slash";
627
- qualifiers() {
628
- return {
629
- labels: ["10"],
630
- preambles: ["/"]
631
- };
632
- }
633
- decode(message, options = {}) {
634
- const decodeResult = this.defaultResult();
635
- decodeResult.decoder.name = this.name;
636
- decodeResult.formatted.description = "Position Report";
637
- decodeResult.message = message;
638
- const parts = message.text.split("/");
639
- if (parts.length < 17) {
640
- if (options.debug) {
641
- console.log(`Decoder: Unknown 10 message: ${message.text}`);
642
- }
643
- decodeResult.remaining.text = message.text;
644
- decodeResult.decoded = false;
645
- decodeResult.decoder.decodeLevel = "none";
646
- return decodeResult;
832
+ decode(message, options = {}) {
833
+ const decodeResult = this.defaultResult();
834
+ decodeResult.decoder.name = this.name;
835
+ decodeResult.formatted.description = "Position Report";
836
+ decodeResult.message = message;
837
+ const parts = message.text.split("/");
838
+ if (parts.length < 17) {
839
+ if (options.debug) {
840
+ console.log(`Decoder: Unknown 10 message: ${message.text}`);
841
+ }
842
+ ResultFormatter.unknown(decodeResult, message.text);
843
+ decodeResult.decoded = false;
844
+ decodeResult.decoder.decodeLevel = "none";
845
+ return decodeResult;
647
846
  }
648
847
  const lat = parts[1];
649
848
  const lon = parts[2];
@@ -655,7 +854,7 @@ var Label_10_Slash = class extends DecoderPlugin {
655
854
  ResultFormatter.heading(decodeResult, Number(parts[5]));
656
855
  ResultFormatter.altitude(decodeResult, 100 * Number(parts[6]));
657
856
  ResultFormatter.arrivalAirport(decodeResult, parts[7]);
658
- ResultFormatter.eta(decodeResult, parts[8] + "00");
857
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[8] + "00"));
659
858
  const waypoints = [{
660
859
  name: parts[11]
661
860
  }, {
@@ -667,17 +866,11 @@ var Label_10_Slash = class extends DecoderPlugin {
667
866
  time: DateTimeUtils.convertHHMMSSToTod(parts[15] + "00"),
668
867
  timeFormat: "tod"
669
868
  }];
670
- decodeResult.raw.route = { waypoints };
671
- decodeResult.formatted.items.push({
672
- type: "aircraft_route",
673
- code: "ROUTE",
674
- label: "Aircraft Route",
675
- value: RouteUtils.routeToString(decodeResult.raw.route)
676
- });
869
+ ResultFormatter.route(decodeResult, { waypoints });
677
870
  if (parts[16]) {
678
871
  ResultFormatter.departureAirport(decodeResult, parts[16]);
679
872
  }
680
- decodeResult.remaining.text = [parts[3], parts[4], ...parts.slice(9, 11), ...parts.slice(17)].join("/");
873
+ ResultFormatter.unknownArr(decodeResult, [parts[3], parts[4], ...parts.slice(9, 11), ...parts.slice(17)], "/");
681
874
  decodeResult.decoded = true;
682
875
  decodeResult.decoder.decodeLevel = "partial";
683
876
  return decodeResult;
@@ -699,35 +892,29 @@ var Label_12_N_Space = class extends DecoderPlugin {
699
892
  decodeResult.formatted.description = "Position Report";
700
893
  decodeResult.message = message;
701
894
  const variant1Regex = /^(?<lat>[NS])\s(?<lat_coord>.*),(?<long>[EW])\s*(?<long_coord>.*),(?<alt>.*),(?<unkwn1>.*),\s*(?<unkwn2>.*),.(?<airframe>.*),(?<unkwn3>.*)$/;
702
- let results;
703
- if (results = message.text.match(variant1Regex)) {
895
+ let results = message.text.match(variant1Regex);
896
+ if (results?.groups) {
704
897
  if (options.debug) {
705
898
  console.log(`Label 12 N : results`);
706
899
  console.log(results);
707
900
  }
708
- decodeResult.raw.position = {
901
+ ResultFormatter.position(decodeResult, {
709
902
  latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
710
903
  longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
711
- };
712
- const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
713
- decodeResult.formatted.items.push({
714
- type: "aircraft_position",
715
- code: "POS",
716
- label: "Aircraft Position",
717
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
718
904
  });
905
+ const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
719
906
  ResultFormatter.altitude(decodeResult, altitude);
720
- decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}, ${results.groups.unkwn3}`;
907
+ ResultFormatter.unknownArr(decodeResult, [results.groups.unkwn1, results.groups.unkwn2, results.groups.unkwn3]);
721
908
  decodeResult.decoded = true;
722
909
  decodeResult.decoder.decodeLevel = "partial";
723
- } else {
724
- if (options.debug) {
725
- console.log(`Decoder: Unknown 12 message: ${message.text}`);
726
- }
727
- decodeResult.remaining.text = message.text;
728
- decodeResult.decoded = false;
729
- decodeResult.decoder.decodeLevel = "none";
910
+ return decodeResult;
730
911
  }
912
+ if (options.debug) {
913
+ console.log(`Decoder: Unknown 12 message: ${message.text}`);
914
+ }
915
+ ResultFormatter.unknown(decodeResult, message.text);
916
+ decodeResult.decoded = false;
917
+ decodeResult.decoder.decodeLevel = "none";
731
918
  return decodeResult;
732
919
  }
733
920
  };
@@ -754,12 +941,11 @@ var Label_13Through18_Slash = class extends DecoderPlugin {
754
941
  if (options?.debug) {
755
942
  console.log(`Decoder: Unknown OOOI message: ${message.text}`);
756
943
  }
757
- decodeResult.remaining.text = message.text;
944
+ ResultFormatter.unknown(decodeResult, message.text);
758
945
  decodeResult.decoded = false;
759
946
  decodeResult.decoder.decodeLevel = "none";
760
947
  return decodeResult;
761
948
  }
762
- decodeResult.remaining.text = "";
763
949
  const data = parts[2].split(" ");
764
950
  ResultFormatter.departureAirport(decodeResult, data[1]);
765
951
  ResultFormatter.arrivalAirport(decodeResult, data[2]);
@@ -775,7 +961,7 @@ var Label_13Through18_Slash = class extends DecoderPlugin {
775
961
  ResultFormatter.in(decodeResult, time);
776
962
  }
777
963
  if (parts.length === 7) {
778
- decodeResult.remaining.text += parts.slice(4).join("/");
964
+ ResultFormatter.unknownArr(decodeResult, parts.slice(4), "/");
779
965
  }
780
966
  for (let i = 1; i < lines.length; i++) {
781
967
  if (lines[i].startsWith("/LOC")) {
@@ -789,11 +975,9 @@ var Label_13Through18_Slash = class extends DecoderPlugin {
789
975
  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)))
790
976
  };
791
977
  }
792
- if (!isNaN(position.latitude) && !isNaN(position.longitude)) {
793
- ResultFormatter.position(decodeResult, position);
794
- }
978
+ ResultFormatter.position(decodeResult, position);
795
979
  } else {
796
- decodeResult.remaining.text += "\r\n" + lines[i];
980
+ ResultFormatter.unknown(decodeResult, lines[i], "\r\n");
797
981
  }
798
982
  }
799
983
  decodeResult.decoded = true;
@@ -838,16 +1022,8 @@ var Label_15 = class extends DecoderPlugin {
838
1022
  decodeResult.formatted.description = "Position Report";
839
1023
  const twoZeeRegex = /^\(2(?<between>.+)\(Z$/;
840
1024
  const results = message.text.match(twoZeeRegex);
841
- if (results) {
842
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.between.substr(0, 13));
843
- if (decodeResult.raw.position) {
844
- decodeResult.formatted.items.push({
845
- type: "position",
846
- code: "POS",
847
- label: "Position",
848
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
849
- });
850
- }
1025
+ if (results?.groups) {
1026
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.between.substr(0, 13)));
851
1027
  }
852
1028
  decodeResult.decoded = true;
853
1029
  decodeResult.decoder.decodeLevel = "partial";
@@ -871,31 +1047,23 @@ var Label_15_FST = class extends DecoderPlugin {
871
1047
  decodeResult.message = message;
872
1048
  const parts = message.text.split(" ");
873
1049
  const header = parts[0];
874
- decodeResult.raw.departure_icao = header.substring(5, 9);
875
- decodeResult.raw.arrival_icao = header.substring(9, 13);
876
1050
  const stringCoords = header.substring(13);
877
1051
  const firstChar = stringCoords.substring(0, 1);
878
1052
  const middleChar = stringCoords.substring(7, 8);
879
1053
  decodeResult.raw.position = {};
880
1054
  if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
881
- decodeResult.raw.position.latitude = Number(stringCoords.substring(1, 7)) / 1e4 * (firstChar === "S" ? -1 : 1);
882
- decodeResult.raw.position.longitude = Number(stringCoords.substring(8, 15)) / 1e4 * (middleChar === "W" ? -1 : 1);
883
- decodeResult.raw.altitude = Number(stringCoords.substring(15)) * 100;
1055
+ const lat = Number(stringCoords.substring(1, 7)) / 1e4 * (firstChar === "S" ? -1 : 1);
1056
+ const lon = Number(stringCoords.substring(8, 15)) / 1e4 * (middleChar === "W" ? -1 : 1);
1057
+ ResultFormatter.position(decodeResult, { latitude: lat, longitude: lon });
1058
+ ResultFormatter.altitude(decodeResult, Number(stringCoords.substring(15)) * 100);
884
1059
  } else {
885
1060
  decodeResult.decoded = false;
886
1061
  decodeResult.decoder.decodeLevel = "none";
887
1062
  return decodeResult;
888
1063
  }
889
- decodeResult.formatted.items.push({
890
- type: "aircraft_position",
891
- code: "POS",
892
- label: "Aircraft Position",
893
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
894
- });
895
- ResultFormatter.altitude(decodeResult, decodeResult.raw.altitude);
896
- ResultFormatter.departureAirport(decodeResult, decodeResult.raw.departure_icao);
897
- ResultFormatter.arrivalAirport(decodeResult, decodeResult.raw.arrival_icao);
898
- decodeResult.remaining.text = parts.slice(1).join(" ");
1064
+ ResultFormatter.departureAirport(decodeResult, header.substring(5, 9));
1065
+ ResultFormatter.arrivalAirport(decodeResult, header.substring(9, 13));
1066
+ ResultFormatter.unknownArr(decodeResult, parts.slice(1), " ");
899
1067
  decodeResult.decoded = true;
900
1068
  decodeResult.decoder.decodeLevel = "partial";
901
1069
  return decodeResult;
@@ -918,52 +1086,45 @@ var Label_16_N_Space = class extends DecoderPlugin {
918
1086
  decodeResult.message = message;
919
1087
  let variant1Regex = /^(?<lat>[NS])\s(?<lat_coord>.*),(?<long>[EW])\s*(?<long_coord>.*),(?<alt>.*),(?<unkwn1>.*),\s*(?<unkwn2>.*)$/;
920
1088
  let variant2Regex = /^(?<lat>[NS])\s(?<lat_coord>.*)\/(?<long>[EW])\s*(?<long_coord>.*)$/;
921
- let results;
922
- if (results = message.text.match(variant1Regex)) {
1089
+ let results = message.text.match(variant1Regex);
1090
+ if (results?.groups) {
923
1091
  if (options.debug) {
924
1092
  console.log(`Label 16 N : results`);
925
1093
  console.log(results);
926
1094
  }
927
- decodeResult.raw.position = {
1095
+ let pos = {
928
1096
  latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
929
1097
  longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
930
1098
  };
931
1099
  const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
932
- decodeResult.formatted.items.push({
933
- type: "aircraft_position",
934
- code: "POS",
935
- label: "Aircraft Position",
936
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
937
- });
1100
+ ResultFormatter.position(decodeResult, pos);
938
1101
  ResultFormatter.altitude(decodeResult, altitude);
939
- decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}`;
1102
+ ResultFormatter.unknownArr(decodeResult, [results.groups.unkwn1, results.groups.unkwn2]);
940
1103
  decodeResult.decoded = true;
941
1104
  decodeResult.decoder.decodeLevel = "partial";
942
- } else if (results = message.text.match(variant2Regex)) {
1105
+ return decodeResult;
1106
+ }
1107
+ results = message.text.match(variant2Regex);
1108
+ if (results?.groups) {
943
1109
  if (options.debug) {
944
1110
  console.log(`Label 16 N : results`);
945
1111
  console.log(results);
946
1112
  }
947
- decodeResult.raw.position = {
1113
+ let pos = {
948
1114
  latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
949
1115
  longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
950
1116
  };
951
- decodeResult.formatted.items.push({
952
- type: "aircraft_position",
953
- code: "POS",
954
- label: "Aircraft Position",
955
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
956
- });
1117
+ ResultFormatter.position(decodeResult, pos);
957
1118
  decodeResult.decoded = true;
958
1119
  decodeResult.decoder.decodeLevel = "full";
959
- } else {
960
- if (options.debug) {
961
- console.log(`Decoder: Unknown 16 message: ${message.text}`);
962
- }
963
- decodeResult.remaining.text = message.text;
964
- decodeResult.decoded = false;
965
- decodeResult.decoder.decodeLevel = "none";
1120
+ return decodeResult;
1121
+ }
1122
+ if (options.debug) {
1123
+ console.log(`Decoder: Unknown 16 message: ${message.text}`);
966
1124
  }
1125
+ ResultFormatter.unknown(decodeResult, message.text);
1126
+ decodeResult.decoded = false;
1127
+ decodeResult.decoder.decodeLevel = "none";
967
1128
  return decodeResult;
968
1129
  }
969
1130
  };
@@ -989,28 +1150,12 @@ var Label_1M_Slash = class extends DecoderPlugin {
989
1150
  console.log(results);
990
1151
  }
991
1152
  decodeResult.raw.flight_number = results[0];
992
- decodeResult.raw.departure_icao = results[3];
993
- decodeResult.raw.arrival_icao = results[4];
994
- decodeResult.raw.alternate_icao = results[5];
995
- decodeResult.raw.arrival_runway = results[8].replace(decodeResult.raw.arrival_icao, "");
996
- decodeResult.formatted.items.push({
997
- type: "eta",
998
- code: "ETA",
999
- label: "Estimated Time of Arrival",
1000
- value: DateTimeUtils.UTCDateTimeToString(results[2], results[7])
1001
- });
1002
- decodeResult.formatted.items.push({
1003
- type: "destination",
1004
- code: "DST",
1005
- label: "Destination",
1006
- value: decodeResult.raw.arrival_icao
1007
- });
1008
- decodeResult.formatted.items.push({
1009
- type: "origin",
1010
- code: "ORG",
1011
- label: "Origin",
1012
- value: decodeResult.raw.departure_icao
1013
- });
1153
+ ResultFormatter.departureAirport(decodeResult, results[3]);
1154
+ ResultFormatter.arrivalAirport(decodeResult, results[4]);
1155
+ ResultFormatter.alternateAirport(decodeResult, results[5]);
1156
+ ResultFormatter.arrivalRunway(decodeResult, results[8].replace(results[4], ""));
1157
+ const yymmdd = results[2];
1158
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertDateTimeToEpoch(results[7] + "00", yymmdd.substring(2, 4) + yymmdd.substring(4, 6) + yymmdd.substring(0, 2)), "epoch");
1014
1159
  }
1015
1160
  decodeResult.decoded = true;
1016
1161
  decodeResult.decoder.decodeLevel = "partial";
@@ -1018,13 +1163,13 @@ var Label_1M_Slash = class extends DecoderPlugin {
1018
1163
  }
1019
1164
  };
1020
1165
 
1021
- // lib/plugins/Label_20_POS.ts
1022
- var Label_20_POS = class extends DecoderPlugin {
1023
- name = "label-20-pos";
1166
+ // lib/plugins/Label_1L_3-line.ts
1167
+ var Label_1L_3Line = class extends DecoderPlugin {
1168
+ // eslint-disable-line camelcase
1169
+ name = "label-1l-3-line";
1024
1170
  qualifiers() {
1025
1171
  return {
1026
- labels: ["20"],
1027
- preambles: ["POS"]
1172
+ labels: ["1L"]
1028
1173
  };
1029
1174
  }
1030
1175
  decode(message, options = {}) {
@@ -1032,59 +1177,88 @@ var Label_20_POS = class extends DecoderPlugin {
1032
1177
  decodeResult.decoder.name = this.name;
1033
1178
  decodeResult.formatted.description = "Position Report";
1034
1179
  decodeResult.message = message;
1035
- decodeResult.raw.preamble = message.text.substring(0, 3);
1036
- const content = message.text.substring(3);
1037
- const fields = content.split(",");
1038
- if (fields.length == 11) {
1039
- if (options.debug) {
1040
- console.log(`DEBUG: ${this.name}: Variation 1 detected`);
1041
- }
1042
- const rawCoords = fields[0];
1043
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
1044
- if (decodeResult.raw.position) {
1045
- decodeResult.formatted.items.push({
1046
- type: "position",
1047
- code: "POS",
1048
- label: "Position",
1049
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1050
- });
1051
- }
1052
- decodeResult.decoded = true;
1053
- decodeResult.decoder.decodeLevel = "full";
1054
- } else if (fields.length == 5) {
1055
- if (options.debug) {
1056
- console.log(`DEBUG: ${this.name}: Variation 2 detected`);
1057
- }
1058
- const rawCoords = fields[0];
1059
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
1060
- if (decodeResult.raw.position) {
1061
- decodeResult.formatted.items.push({
1062
- type: "position",
1063
- code: "POS",
1064
- label: "Position",
1065
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1066
- });
1067
- }
1068
- decodeResult.decoded = true;
1069
- decodeResult.decoder.decodeLevel = "full";
1070
- } else {
1180
+ const lines = message.text.split("\r\n");
1181
+ if (lines.length !== 3) {
1071
1182
  if (options.debug) {
1072
- console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
1183
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1073
1184
  }
1185
+ decodeResult.remaining.text = message.text;
1074
1186
  decodeResult.decoded = false;
1075
1187
  decodeResult.decoder.decodeLevel = "none";
1188
+ return decodeResult;
1189
+ }
1190
+ const parts = message.text.replaceAll("\r\n", "/").split("/");
1191
+ const data = /* @__PURE__ */ new Map();
1192
+ data.set("", parts[0]);
1193
+ for (let i = 1; i < parts.length; i++) {
1194
+ const part = parts[i].split(" ");
1195
+ data.set(part[0], part.slice(1).join(" "));
1196
+ }
1197
+ const dep = data.get("DEP");
1198
+ if (dep) {
1199
+ ResultFormatter.departureAirport(decodeResult, dep);
1200
+ data.delete("DEP");
1201
+ }
1202
+ const des = data.get("DES");
1203
+ if (des) {
1204
+ ResultFormatter.arrivalAirport(decodeResult, des);
1205
+ data.delete("DES");
1206
+ }
1207
+ const eta = data.get("ETA");
1208
+ if (eta) {
1209
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta + "00"));
1210
+ data.delete("ETA");
1211
+ }
1212
+ const alt = data.get("ALT");
1213
+ if (alt) {
1214
+ ResultFormatter.altitude(decodeResult, Number(alt));
1215
+ data.delete("ALT");
1216
+ }
1217
+ const fn = data.get("FN");
1218
+ if (fn) {
1219
+ ResultFormatter.flightNumber(decodeResult, fn);
1220
+ data.delete("FN");
1076
1221
  }
1222
+ const day = data.get("DAY");
1223
+ const utc = data.get("UTC");
1224
+ if (day && utc) {
1225
+ decodeResult.raw.message_timestamp = Date.parse(day + " GMT+0000") / 1e3 + DateTimeUtils.convertHHMMSSToTod(utc);
1226
+ data.delete("DAY");
1227
+ data.delete("UTC");
1228
+ }
1229
+ const lat = data.get("LAT");
1230
+ const lon = data.get("LON");
1231
+ if (lat && lon) {
1232
+ ResultFormatter.position(decodeResult, {
1233
+ latitude: CoordinateUtils.getDirection(lat[0]) * Number(lat.substring(1)),
1234
+ longitude: CoordinateUtils.getDirection(lon[0]) * Number(lon.substring(1))
1235
+ });
1236
+ data.delete("LAT");
1237
+ data.delete("LON");
1238
+ }
1239
+ let remaining = "";
1240
+ for (const [key, value] of data.entries()) {
1241
+ if (key === "") {
1242
+ remaining += value;
1243
+ } else {
1244
+ remaining += `/${key} ${value}`;
1245
+ }
1246
+ }
1247
+ decodeResult.remaining.text = remaining;
1248
+ decodeResult.decoded = true;
1249
+ decodeResult.decoder.decodeLevel = "partial";
1077
1250
  return decodeResult;
1078
1251
  }
1079
1252
  };
1080
1253
 
1081
- // lib/plugins/Label_21_POS.ts
1082
- var Label_21_POS = class extends DecoderPlugin {
1083
- name = "label-21-pos";
1254
+ // lib/plugins/Label_1L_070.ts
1255
+ var Label_1L_070 = class extends DecoderPlugin {
1256
+ // eslint-disable-line camelcase
1257
+ name = "label-1l-070";
1084
1258
  qualifiers() {
1085
1259
  return {
1086
- labels: ["21"],
1087
- preambles: ["POS"]
1260
+ labels: ["1L"],
1261
+ preambles: ["000000070"]
1088
1262
  };
1089
1263
  }
1090
1264
  decode(message, options = {}) {
@@ -1092,81 +1266,416 @@ var Label_21_POS = class extends DecoderPlugin {
1092
1266
  decodeResult.decoder.name = this.name;
1093
1267
  decodeResult.formatted.description = "Position Report";
1094
1268
  decodeResult.message = message;
1095
- decodeResult.raw.preamble = message.text.substring(0, 3);
1096
- const content = message.text.substring(3);
1097
- const fields = content.split(",");
1098
- if (fields.length == 9) {
1099
- processPosition(decodeResult, fields[0].trim());
1100
- processAlt(decodeResult, fields[3]);
1101
- processTemp(decodeResult, fields[6]);
1102
- processArrvApt(decodeResult, fields[8]);
1103
- decodeResult.remaining.text = [
1104
- fields[1],
1105
- fields[2],
1106
- fields[4],
1107
- fields[5],
1108
- fields[7]
1109
- ].join(",");
1110
- decodeResult.decoded = true;
1111
- decodeResult.decoder.decodeLevel = "partial";
1112
- } else {
1269
+ if (!message.text.startsWith("000000070")) {
1113
1270
  if (options.debug) {
1114
- console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
1271
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1115
1272
  }
1273
+ decodeResult.remaining.text = message.text;
1116
1274
  decodeResult.decoded = false;
1117
1275
  decodeResult.decoder.decodeLevel = "none";
1276
+ return decodeResult;
1118
1277
  }
1119
- return decodeResult;
1120
- }
1121
- };
1122
- function processPosition(decodeResult, value) {
1123
- if (value.length !== 16 && value[0] !== "N" && value[0] !== "S" && value[8] !== "W" && value[8] !== "E") {
1124
- return false;
1125
- }
1126
- const latDir = value[0] === "N" ? 1 : -1;
1278
+ const parts = message.text.substring(9).split(",");
1279
+ if (parts.length !== 7) {
1280
+ if (options.debug) {
1281
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1282
+ }
1283
+ decodeResult.remaining.text = message.text;
1284
+ decodeResult.decoded = false;
1285
+ decodeResult.decoder.decodeLevel = "none";
1286
+ return decodeResult;
1287
+ }
1288
+ ResultFormatter.departureAirport(decodeResult, parts[0]);
1289
+ ResultFormatter.arrivalAirport(decodeResult, parts[1]);
1290
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[2] + "00"));
1291
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[3] + "00"));
1292
+ ResultFormatter.position(decodeResult, {
1293
+ latitude: CoordinateUtils.getDirection(parts[4][0]) * Number(parts[4].substring(1)),
1294
+ longitude: CoordinateUtils.getDirection(parts[5][0]) * Number(parts[5].substring(1))
1295
+ });
1296
+ decodeResult.remaining.text = parts[6];
1297
+ decodeResult.decoded = true;
1298
+ decodeResult.decoder.decodeLevel = "partial";
1299
+ return decodeResult;
1300
+ }
1301
+ };
1302
+
1303
+ // lib/plugins/Label_1L_660.ts
1304
+ var Label_1L_660 = class extends DecoderPlugin {
1305
+ // eslint-disable-line camelcase
1306
+ name = "label-1l-660";
1307
+ qualifiers() {
1308
+ return {
1309
+ labels: ["1L"],
1310
+ preambles: ["000000660"]
1311
+ };
1312
+ }
1313
+ decode(message, options = {}) {
1314
+ const decodeResult = this.defaultResult();
1315
+ decodeResult.decoder.name = this.name;
1316
+ decodeResult.formatted.description = "Position Report";
1317
+ decodeResult.message = message;
1318
+ if (!message.text.startsWith("000000660")) {
1319
+ if (options.debug) {
1320
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1321
+ }
1322
+ decodeResult.remaining.text = message.text;
1323
+ decodeResult.decoded = false;
1324
+ decodeResult.decoder.decodeLevel = "none";
1325
+ return decodeResult;
1326
+ }
1327
+ const parts = message.text.substring(9).split(",");
1328
+ if (parts.length !== 5) {
1329
+ if (options.debug) {
1330
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1331
+ }
1332
+ decodeResult.remaining.text = message.text;
1333
+ decodeResult.decoded = false;
1334
+ decodeResult.decoder.decodeLevel = "none";
1335
+ return decodeResult;
1336
+ }
1337
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(parts[0]);
1338
+ if (position) {
1339
+ ResultFormatter.position(decodeResult, position);
1340
+ }
1341
+ const hhmmss = parts[1].substring(0, 6);
1342
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(hhmmss));
1343
+ const fl = parts[1].substring(6, 9);
1344
+ ResultFormatter.altitude(decodeResult, Number(fl) * 100);
1345
+ const next = parts[1].substring(9);
1346
+ ResultFormatter.route(decodeResult, { waypoints: [{ name: next.trim() }] });
1347
+ decodeResult.remaining.text = parts.slice(2).join(",");
1348
+ decodeResult.decoded = true;
1349
+ decodeResult.decoder.decodeLevel = "partial";
1350
+ return decodeResult;
1351
+ }
1352
+ };
1353
+
1354
+ // lib/plugins/Label_1L_Slash.ts
1355
+ var Label_1L_Slash = class extends DecoderPlugin {
1356
+ // eslint-disable-line camelcase
1357
+ name = "label-1l-1-line";
1358
+ qualifiers() {
1359
+ return {
1360
+ labels: ["1L"],
1361
+ preambles: ["+", "-"]
1362
+ };
1363
+ }
1364
+ decode(message, options = {}) {
1365
+ const decodeResult = this.defaultResult();
1366
+ decodeResult.decoder.name = this.name;
1367
+ decodeResult.formatted.description = "Position Report";
1368
+ decodeResult.message = message;
1369
+ const parts = message.text.split("/");
1370
+ if (parts.length !== 7) {
1371
+ if (options.debug) {
1372
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1373
+ }
1374
+ decodeResult.remaining.text = message.text;
1375
+ decodeResult.decoded = false;
1376
+ decodeResult.decoder.decodeLevel = "none";
1377
+ return decodeResult;
1378
+ }
1379
+ const data = /* @__PURE__ */ new Map();
1380
+ data.set("LAT", parts[0].replaceAll(" ", ""));
1381
+ data.set("LON", parts[1].replaceAll(" ", ""));
1382
+ for (let i = 2; i < parts.length; i++) {
1383
+ const part = parts[i].split(" ");
1384
+ data.set(part[0], part.slice(1).join(" "));
1385
+ }
1386
+ console.log(data);
1387
+ const position = {
1388
+ latitude: Number(data.get("LAT")),
1389
+ longitude: Number(data.get("LON"))
1390
+ };
1391
+ data.delete("LAT");
1392
+ data.delete("LON");
1393
+ ResultFormatter.position(decodeResult, position);
1394
+ const utc = data.get("UTC");
1395
+ if (utc) {
1396
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(utc));
1397
+ data.delete("UTC");
1398
+ }
1399
+ const alt = data.get("ALT");
1400
+ if (alt) {
1401
+ ResultFormatter.altitude(decodeResult, Number(alt));
1402
+ data.delete("ALT");
1403
+ }
1404
+ const fob = data.get("FOB");
1405
+ if (fob) {
1406
+ ResultFormatter.currentFuel(decodeResult, Number(fob));
1407
+ data.delete("FOB");
1408
+ }
1409
+ const eta = data.get("ETA");
1410
+ if (eta) {
1411
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta + "00"));
1412
+ data.delete("ETA");
1413
+ }
1414
+ let remaining = "";
1415
+ for (const [key, value] of data.entries()) {
1416
+ remaining += `/${key} ${value}`;
1417
+ }
1418
+ decodeResult.remaining.text = remaining;
1419
+ decodeResult.decoded = true;
1420
+ decodeResult.decoder.decodeLevel = "partial";
1421
+ return decodeResult;
1422
+ }
1423
+ };
1424
+
1425
+ // lib/plugins/Label_20_POS.ts
1426
+ var Label_20_POS = class extends DecoderPlugin {
1427
+ name = "label-20-pos";
1428
+ qualifiers() {
1429
+ return {
1430
+ labels: ["20"],
1431
+ preambles: ["POS"]
1432
+ };
1433
+ }
1434
+ decode(message, options = {}) {
1435
+ const decodeResult = this.defaultResult();
1436
+ decodeResult.decoder.name = this.name;
1437
+ decodeResult.formatted.description = "Position Report";
1438
+ decodeResult.message = message;
1439
+ decodeResult.raw.preamble = message.text.substring(0, 3);
1440
+ const content = message.text.substring(3);
1441
+ const fields = content.split(",");
1442
+ if (fields.length == 11) {
1443
+ if (options.debug) {
1444
+ console.log(`DEBUG: ${this.name}: Variation 1 detected`);
1445
+ }
1446
+ const rawCoords = fields[0];
1447
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(rawCoords));
1448
+ decodeResult.decoded = true;
1449
+ decodeResult.decoder.decodeLevel = "full";
1450
+ } else if (fields.length == 5) {
1451
+ if (options.debug) {
1452
+ console.log(`DEBUG: ${this.name}: Variation 2 detected`);
1453
+ }
1454
+ const position = CoordinateUtils.decodeStringCoordinates(fields[0]);
1455
+ if (position) {
1456
+ ResultFormatter.position(decodeResult, position);
1457
+ }
1458
+ decodeResult.decoded = true;
1459
+ decodeResult.decoder.decodeLevel = "full";
1460
+ } else {
1461
+ if (options.debug) {
1462
+ console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
1463
+ }
1464
+ decodeResult.decoded = false;
1465
+ decodeResult.decoder.decodeLevel = "none";
1466
+ }
1467
+ return decodeResult;
1468
+ }
1469
+ };
1470
+
1471
+ // lib/plugins/Label_21_POS.ts
1472
+ var Label_21_POS = class extends DecoderPlugin {
1473
+ name = "label-21-pos";
1474
+ qualifiers() {
1475
+ return {
1476
+ labels: ["21"],
1477
+ preambles: ["POS"]
1478
+ };
1479
+ }
1480
+ decode(message, options = {}) {
1481
+ const decodeResult = this.defaultResult();
1482
+ decodeResult.decoder.name = this.name;
1483
+ decodeResult.formatted.description = "Position Report";
1484
+ decodeResult.message = message;
1485
+ decodeResult.raw.preamble = message.text.substring(0, 3);
1486
+ const content = message.text.substring(3);
1487
+ const fields = content.split(",");
1488
+ if (fields.length == 9) {
1489
+ processPosition(decodeResult, fields[0].trim());
1490
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2]));
1491
+ ResultFormatter.altitude(decodeResult, Number(fields[3]));
1492
+ ResultFormatter.temperature(decodeResult, fields[6].replace(/ /g, ""));
1493
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[7]));
1494
+ ResultFormatter.arrivalAirport(decodeResult, fields[8]);
1495
+ ResultFormatter.unknownArr(decodeResult, [fields[1], fields[4], fields[5]]);
1496
+ decodeResult.decoded = true;
1497
+ decodeResult.decoder.decodeLevel = "partial";
1498
+ } else {
1499
+ if (options.debug) {
1500
+ console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${content}`);
1501
+ }
1502
+ decodeResult.decoded = false;
1503
+ decodeResult.decoder.decodeLevel = "none";
1504
+ }
1505
+ return decodeResult;
1506
+ }
1507
+ };
1508
+ function processPosition(decodeResult, value) {
1509
+ if (value.length !== 16 && value[0] !== "N" && value[0] !== "S" && value[8] !== "W" && value[8] !== "E") {
1510
+ return;
1511
+ }
1512
+ const latDir = value[0] === "N" ? 1 : -1;
1127
1513
  const lonDir = value[8] === "E" ? 1 : -1;
1128
1514
  const position = {
1129
1515
  latitude: latDir * Number(value.substring(1, 7)),
1130
1516
  longitude: lonDir * Number(value.substring(9, 15))
1131
1517
  };
1132
- if (position) {
1133
- decodeResult.raw.position = position;
1134
- decodeResult.formatted.items.push({
1135
- type: "aircraft_position",
1136
- code: "POS",
1137
- label: "Aircraft Position",
1138
- value: CoordinateUtils.coordinateString(position)
1518
+ ResultFormatter.position(decodeResult, position);
1519
+ }
1520
+
1521
+ // lib/plugins/Label_22_OFF.ts
1522
+ var Label_22_OFF = class extends DecoderPlugin {
1523
+ name = "label-22-off";
1524
+ qualifiers() {
1525
+ return {
1526
+ labels: ["22"],
1527
+ preambles: ["OFF"]
1528
+ };
1529
+ }
1530
+ decode(message, options = {}) {
1531
+ const decodeResult = this.defaultResult();
1532
+ decodeResult.decoder.name = this.name;
1533
+ decodeResult.formatted.description = "Takeoff Report";
1534
+ decodeResult.message = message;
1535
+ if (message.text.startsWith("OFF01")) {
1536
+ const fields = message.text.substring(5).split("/");
1537
+ if (fields.length != 2) {
1538
+ decodeResult.decoded = false;
1539
+ decodeResult.decoder.decodeLevel = "none";
1540
+ return decodeResult;
1541
+ }
1542
+ ResultFormatter.flightNumber(decodeResult, fields[0]);
1543
+ ResultFormatter.departureDay(decodeResult, Number(fields[1].substring(0, 2)));
1544
+ ResultFormatter.arrivalDay(decodeResult, Number(fields[1].substring(2, 4)));
1545
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(4, 8) + "00"));
1546
+ ResultFormatter.departureAirport(decodeResult, fields[1].substring(8, 12));
1547
+ ResultFormatter.arrivalAirport(decodeResult, fields[1].substring(12, 16));
1548
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 22)));
1549
+ ResultFormatter.unknown(decodeResult, fields[1].substring(22));
1550
+ decodeResult.decoded = true;
1551
+ decodeResult.decoder.decodeLevel = "partial";
1552
+ } else if (message.text.startsWith("OFF02\r\n")) {
1553
+ const fields = message.text.substring(7).split(",");
1554
+ if (fields.length != 4) {
1555
+ decodeResult.decoded = false;
1556
+ decodeResult.decoder.decodeLevel = "none";
1557
+ return decodeResult;
1558
+ }
1559
+ ResultFormatter.departureAirport(decodeResult, fields[0]);
1560
+ ResultFormatter.arrivalAirport(decodeResult, fields[1]);
1561
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2] + "00"));
1562
+ ResultFormatter.unknown(decodeResult, fields[3]);
1563
+ decodeResult.decoded = true;
1564
+ decodeResult.decoder.decodeLevel = "partial";
1565
+ } else if (message.text.startsWith("OFF02")) {
1566
+ const fields = message.text.substring(5).split("/");
1567
+ if (fields.length != 2) {
1568
+ decodeResult.decoded = false;
1569
+ decodeResult.decoder.decodeLevel = "none";
1570
+ return decodeResult;
1571
+ }
1572
+ ResultFormatter.flightNumber(decodeResult, fields[0]);
1573
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(fields[1].substring(0, 14));
1574
+ if (position) {
1575
+ ResultFormatter.position(decodeResult, position);
1576
+ }
1577
+ ResultFormatter.day(decodeResult, Number(fields[1].substring(14, 16)));
1578
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 20) + "00"));
1579
+ ResultFormatter.departureAirport(decodeResult, fields[1].substring(20, 24));
1580
+ ResultFormatter.arrivalAirport(decodeResult, fields[1].substring(24, 28));
1581
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(28, 32) + "00"));
1582
+ ResultFormatter.unknown(decodeResult, fields[1].substring(32, 36));
1583
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(36, 40) + "00"));
1584
+ decodeResult.decoded = true;
1585
+ decodeResult.decoder.decodeLevel = "partial";
1586
+ } else {
1587
+ if (options.debug) {
1588
+ console.log(`DEBUG: ${this.name}: Unknown variation.`);
1589
+ }
1590
+ decodeResult.decoded = false;
1591
+ decodeResult.decoder.decodeLevel = "none";
1592
+ }
1593
+ return decodeResult;
1594
+ }
1595
+ };
1596
+
1597
+ // lib/plugins/Label_22_POS.ts
1598
+ var Label_22_POS = class extends DecoderPlugin {
1599
+ name = "label-22-pos";
1600
+ qualifiers() {
1601
+ return {
1602
+ labels: ["22"],
1603
+ preambles: ["N", "S"]
1604
+ };
1605
+ }
1606
+ decode(message, options = {}) {
1607
+ const decodeResult = this.defaultResult();
1608
+ decodeResult.decoder.name = this.name;
1609
+ decodeResult.formatted.description = "Position Report";
1610
+ decodeResult.message = message;
1611
+ const fields = message.text.split(",");
1612
+ if (fields.length !== 11) {
1613
+ if (options.debug) {
1614
+ console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${fields.join(",")}`);
1615
+ }
1616
+ decodeResult.decoded = false;
1617
+ decodeResult.decoder.decodeLevel = "none";
1618
+ return decodeResult;
1619
+ }
1620
+ const latStr = fields[0].substring(1, 8);
1621
+ const lonStr = fields[0].substring(9);
1622
+ const lat = Number(latStr) / 1e4;
1623
+ const lon = Number(lonStr) / 1e4;
1624
+ ResultFormatter.position(decodeResult, {
1625
+ latitude: CoordinateUtils.getDirection(fields[0][0]) * lat,
1626
+ longitude: CoordinateUtils.getDirection(fields[0][8]) * lon
1139
1627
  });
1628
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2]));
1629
+ ResultFormatter.altitude(decodeResult, Number(fields[3]));
1630
+ ResultFormatter.unknownArr(decodeResult, [fields[1], ...fields.slice(4)]);
1631
+ decodeResult.decoded = true;
1632
+ decodeResult.decoder.decodeLevel = "partial";
1633
+ return decodeResult;
1140
1634
  }
1141
- return !!position;
1142
- }
1143
- function processAlt(decodeResult, value) {
1144
- decodeResult.raw.altitude = Number(value);
1145
- decodeResult.formatted.items.push({
1146
- type: "altitude",
1147
- code: "ALT",
1148
- label: "Altitude",
1149
- value: `${decodeResult.raw.altitude} feet`
1150
- });
1151
- }
1152
- function processTemp(decodeResult, value) {
1153
- decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
1154
- decodeResult.formatted.items.push({
1155
- type: "outside_air_temperature",
1156
- code: "OATEMP",
1157
- label: "Outside Air Temperature (C)",
1158
- value: `${decodeResult.raw.outside_air_temperature}`
1159
- });
1160
- }
1161
- function processArrvApt(decodeResult, value) {
1162
- decodeResult.raw.arrival_icao = value;
1163
- decodeResult.formatted.items.push({
1164
- type: "destination",
1165
- code: "DST",
1166
- label: "Destination",
1167
- value: decodeResult.raw.arrival_icao
1168
- });
1169
- }
1635
+ };
1636
+
1637
+ // lib/plugins/Label_24_Slash.ts
1638
+ var Label_24_Slash = class extends DecoderPlugin {
1639
+ name = "label-24-slash";
1640
+ qualifiers() {
1641
+ return {
1642
+ labels: ["24"],
1643
+ preambles: ["/"]
1644
+ };
1645
+ }
1646
+ decode(message, options = {}) {
1647
+ const decodeResult = this.defaultResult();
1648
+ decodeResult.decoder.name = this.name;
1649
+ decodeResult.formatted.description = "Position Report";
1650
+ decodeResult.message = message;
1651
+ const fields = message.text.split("/");
1652
+ if (fields.length == 10 && fields[0] == "" && fields[9] == "") {
1653
+ const mmddyy = fields[1].substring(4, 6) + fields[1].substring(2, 4) + fields[1].substring(0, 2);
1654
+ const hhmmss = fields[2] + "00";
1655
+ decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(hhmmss, mmddyy);
1656
+ ResultFormatter.flightNumber(decodeResult, fields[3]);
1657
+ ResultFormatter.altitude(decodeResult, Number(fields[4]));
1658
+ const lat = fields[5];
1659
+ const lon = fields[6];
1660
+ const position = {
1661
+ latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1)),
1662
+ longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1))
1663
+ };
1664
+ ResultFormatter.position(decodeResult, position);
1665
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[8] + "00"));
1666
+ ResultFormatter.unknown(decodeResult, fields[7]);
1667
+ decodeResult.decoded = true;
1668
+ decodeResult.decoder.decodeLevel = "partial";
1669
+ } else {
1670
+ if (options.debug) {
1671
+ console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}. Message: ${message.text}`);
1672
+ }
1673
+ decodeResult.decoded = false;
1674
+ decodeResult.decoder.decodeLevel = "none";
1675
+ }
1676
+ return decodeResult;
1677
+ }
1678
+ };
1170
1679
 
1171
1680
  // lib/plugins/Label_30_Slash_EA.ts
1172
1681
  var Label_30_Slash_EA = class extends DecoderPlugin {
@@ -1189,23 +1698,12 @@ var Label_30_Slash_EA = class extends DecoderPlugin {
1189
1698
  console.log(results);
1190
1699
  }
1191
1700
  }
1192
- decodeResult.formatted.items.push({
1193
- type: "eta",
1194
- code: "ETA",
1195
- label: "Estimated Time of Arrival",
1196
- value: DateTimeUtils.UTCToString(results[0].substr(2, 4))
1197
- });
1198
- if (results[1].substr(0, 2) === "DS") {
1199
- decodeResult.raw.arrival_icao = results[1].substr(2, 4);
1200
- decodeResult.formatted.items.push({
1201
- type: "destination",
1202
- code: "DST",
1203
- label: "Destination",
1204
- value: decodeResult.raw.arrival_icao
1205
- });
1206
- decodeResult.remaining.text = "/".concat(results[2]);
1701
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results[0].substr(2, 4) + "00"));
1702
+ if (results[1].substring(0, 2) === "DS") {
1703
+ ResultFormatter.arrivalAirport(decodeResult, results[1].substring(2, 6));
1704
+ ResultFormatter.unknown(decodeResult, "/".concat(results[2]));
1207
1705
  } else {
1208
- decodeResult.remaining.text = "/".concat(results[1], "/", results[2]);
1706
+ ResultFormatter.unknown(decodeResult, "/".concat(results[1], "/", results[2]));
1209
1707
  }
1210
1708
  decodeResult.decoded = true;
1211
1709
  decodeResult.decoder.decodeLevel = "partial";
@@ -1229,40 +1727,20 @@ var Label_44_ETA = class extends DecoderPlugin {
1229
1727
  decodeResult.message = message;
1230
1728
  const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
1231
1729
  const results = message.text.match(regex);
1232
- if (results) {
1730
+ if (results?.groups) {
1233
1731
  if (options.debug) {
1234
1732
  console.log(`Label 44 ETA Report: groups`);
1235
1733
  console.log(results.groups);
1236
1734
  }
1237
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
1238
- decodeResult.raw.departure_icao = results.groups.departure_icao;
1239
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1735
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords));
1736
+ ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1737
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1240
1738
  decodeResult.raw.current_time = Date.parse(
1241
1739
  (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.current_time.substr(0, 2) + ":" + results.groups.current_time.substr(2, 2) + ":00Z"
1242
1740
  );
1243
1741
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1244
- decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1245
- }
1246
- if (decodeResult.raw.position) {
1247
- decodeResult.formatted.items.push({
1248
- type: "position",
1249
- code: "POS",
1250
- label: "Position",
1251
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1252
- });
1742
+ ResultFormatter.remainingFuel(decodeResult, Number(results.groups.fuel_in_tons));
1253
1743
  }
1254
- decodeResult.formatted.items.push({
1255
- type: "origin",
1256
- code: "ORG",
1257
- label: "Origin",
1258
- value: decodeResult.raw.departure_icao
1259
- });
1260
- decodeResult.formatted.items.push({
1261
- type: "destination",
1262
- code: "DST",
1263
- label: "Destination",
1264
- value: decodeResult.raw.arrival_icao
1265
- });
1266
1744
  }
1267
1745
  decodeResult.decoded = true;
1268
1746
  decodeResult.decoder.decodeLevel = "full";
@@ -1286,40 +1764,20 @@ var Label_44_IN = class extends DecoderPlugin {
1286
1764
  decodeResult.message = message;
1287
1765
  const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
1288
1766
  const results = message.text.match(regex);
1289
- if (results) {
1767
+ if (results?.groups) {
1290
1768
  if (options.debug) {
1291
1769
  console.log(`Label 44 In Air Report: groups`);
1292
1770
  console.log(results.groups);
1293
1771
  }
1294
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
1295
- decodeResult.raw.departure_icao = results.groups.departure_icao;
1296
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1772
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords));
1773
+ ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1774
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1297
1775
  decodeResult.raw.current_time = Date.parse(
1298
1776
  (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.current_time.substr(0, 2) + ":" + results.groups.current_time.substr(2, 2) + ":00Z"
1299
1777
  );
1300
1778
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1301
1779
  decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1302
1780
  }
1303
- if (decodeResult.raw.position) {
1304
- decodeResult.formatted.items.push({
1305
- type: "position",
1306
- code: "POS",
1307
- label: "Position",
1308
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1309
- });
1310
- }
1311
- decodeResult.formatted.items.push({
1312
- type: "origin",
1313
- code: "ORG",
1314
- label: "Origin",
1315
- value: decodeResult.raw.departure_icao
1316
- });
1317
- decodeResult.formatted.items.push({
1318
- type: "destination",
1319
- code: "DST",
1320
- label: "Destination",
1321
- value: decodeResult.raw.arrival_icao
1322
- });
1323
1781
  }
1324
1782
  decodeResult.decoded = true;
1325
1783
  decodeResult.decoder.decodeLevel = "full";
@@ -1343,13 +1801,14 @@ var Label_44_OFF = class extends DecoderPlugin {
1343
1801
  decodeResult.message = message;
1344
1802
  const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<eta_time>.*),(?<fuel_in_tons>.*)$/;
1345
1803
  const results = message.text.match(regex);
1346
- if (results) {
1804
+ if (results?.groups) {
1347
1805
  if (options.debug) {
1348
1806
  console.log(`Label 44 Off Runway Report: groups`);
1349
1807
  console.log(results.groups);
1350
1808
  }
1351
- decodeResult.raw.departure_icao = results.groups.departure_icao;
1352
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1809
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords));
1810
+ ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1811
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1353
1812
  decodeResult.raw.current_time = Date.parse(
1354
1813
  (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.current_time.substr(0, 2) + ":" + results.groups.current_time.substr(2, 2) + ":00Z"
1355
1814
  );
@@ -1359,27 +1818,6 @@ var Label_44_OFF = class extends DecoderPlugin {
1359
1818
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1360
1819
  decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1361
1820
  }
1362
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
1363
- if (decodeResult.raw.position) {
1364
- decodeResult.formatted.items.push({
1365
- type: "position",
1366
- code: "POS",
1367
- label: "Position",
1368
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1369
- });
1370
- }
1371
- decodeResult.formatted.items.push({
1372
- type: "origin",
1373
- code: "ORG",
1374
- label: "Origin",
1375
- value: decodeResult.raw.departure_icao
1376
- });
1377
- decodeResult.formatted.items.push({
1378
- type: "destination",
1379
- code: "DST",
1380
- label: "Destination",
1381
- value: decodeResult.raw.arrival_icao
1382
- });
1383
1821
  }
1384
1822
  decodeResult.decoded = true;
1385
1823
  decodeResult.decoder.decodeLevel = "full";
@@ -1403,40 +1841,20 @@ var Label_44_ON = class extends DecoderPlugin {
1403
1841
  decodeResult.message = message;
1404
1842
  const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
1405
1843
  const results = message.text.match(regex);
1406
- if (results) {
1844
+ if (results?.groups) {
1407
1845
  if (options.debug) {
1408
1846
  console.log(`Label 44 On Runway Report: groups`);
1409
1847
  console.log(results.groups);
1410
1848
  }
1411
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
1412
- decodeResult.raw.departure_icao = results.groups.departure_icao;
1413
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1849
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords));
1850
+ ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1851
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1414
1852
  decodeResult.raw.current_time = Date.parse(
1415
1853
  (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.current_time.substr(0, 2) + ":" + results.groups.current_time.substr(2, 2) + ":00Z"
1416
1854
  );
1417
1855
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1418
- decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1856
+ ResultFormatter.remainingFuel(decodeResult, Number(results.groups.fuel_in_tons));
1419
1857
  }
1420
- if (decodeResult.raw.position) {
1421
- decodeResult.formatted.items.push({
1422
- type: "position",
1423
- code: "POS",
1424
- label: "Position",
1425
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1426
- });
1427
- }
1428
- decodeResult.formatted.items.push({
1429
- type: "origin",
1430
- code: "ORG",
1431
- label: "Origin",
1432
- value: decodeResult.raw.departure_icao
1433
- });
1434
- decodeResult.formatted.items.push({
1435
- type: "destination",
1436
- code: "DST",
1437
- label: "Destination",
1438
- value: decodeResult.raw.arrival_icao
1439
- });
1440
1858
  }
1441
1859
  decodeResult.decoded = true;
1442
1860
  decodeResult.decoder.decodeLevel = "full";
@@ -1460,12 +1878,12 @@ var Label_44_POS = class extends DecoderPlugin {
1460
1878
  decodeResult.message = message;
1461
1879
  const regex = /^.*,(?<unsplit_coords>.*),(?<flight_level_or_ground>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<eta_time>.*),(?<fuel_in_tons>.*)$/;
1462
1880
  const results = message.text.match(regex);
1463
- if (results) {
1881
+ if (results?.groups) {
1464
1882
  if (options.debug) {
1465
1883
  console.log(`Label 44 Position Report: groups`);
1466
1884
  console.log(results.groups);
1467
1885
  }
1468
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(results.groups.unsplit_coords);
1886
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(results.groups.unsplit_coords));
1469
1887
  const flight_level = results.groups.flight_level_or_ground == "GRD" || results.groups.flight_level_or_ground == "***" ? 0 : Number(results.groups.flight_level_or_ground);
1470
1888
  decodeResult.raw.current_time = Date.parse(
1471
1889
  (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.current_time.substr(0, 2) + ":" + results.groups.current_time.substr(2, 2) + ":00Z"
@@ -1476,20 +1894,221 @@ var Label_44_POS = class extends DecoderPlugin {
1476
1894
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1477
1895
  decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1478
1896
  }
1479
- if (decodeResult.raw.position) {
1480
- decodeResult.formatted.items.push({
1481
- type: "aircraft_position",
1482
- code: "POS",
1483
- label: "Aircraft Position",
1484
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1485
- });
1486
- }
1487
1897
  ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1488
1898
  ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1489
1899
  ResultFormatter.altitude(decodeResult, flight_level * 100);
1490
1900
  }
1491
1901
  decodeResult.decoded = true;
1492
- decodeResult.decoder.decodeLevel = "full";
1902
+ decodeResult.decoder.decodeLevel = "full";
1903
+ return decodeResult;
1904
+ }
1905
+ };
1906
+
1907
+ // lib/plugins/Label_4A.ts
1908
+ var Label_4A = class extends DecoderPlugin {
1909
+ name = "label-4a";
1910
+ qualifiers() {
1911
+ return {
1912
+ labels: ["4A"]
1913
+ };
1914
+ }
1915
+ decode(message, options = {}) {
1916
+ const decodeResult = this.defaultResult();
1917
+ decodeResult.decoder.name = this.name;
1918
+ decodeResult.message = message;
1919
+ decodeResult.formatted.description = "Latest New Format";
1920
+ let text = message.text;
1921
+ if (text.match(/^M\d{2}A\w{6}/)) {
1922
+ ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
1923
+ text = text.substring(10);
1924
+ }
1925
+ decodeResult.decoded = true;
1926
+ const fields = text.split(",");
1927
+ if (fields.length === 11) {
1928
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[0]));
1929
+ ResultFormatter.tail(decodeResult, fields[2].replace(".", ""));
1930
+ if (fields[3])
1931
+ ResultFormatter.callsign(decodeResult, fields[3]);
1932
+ ResultFormatter.departureAirport(decodeResult, fields[4]);
1933
+ ResultFormatter.arrivalAirport(decodeResult, fields[5]);
1934
+ ResultFormatter.altitude(decodeResult, Number(text.substring(48, 51)) * 100);
1935
+ ResultFormatter.unknownArr(decodeResult, fields.slice(8));
1936
+ } else if (fields.length === 6) {
1937
+ if (fields[0].match(/^[NS]/)) {
1938
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(fields[0].substring(0, 13)));
1939
+ let wp1 = {
1940
+ name: fields[0].substring(13).trim(),
1941
+ time: DateTimeUtils.convertHHMMSSToTod(fields[1].substring(0, 6)),
1942
+ timeFormat: "tod"
1943
+ };
1944
+ ResultFormatter.altitude(decodeResult, Number(fields[1].substring(6, 9)) * 100);
1945
+ let wp2 = {
1946
+ name: fields[1].substring(9).trim(),
1947
+ time: DateTimeUtils.convertHHMMSSToTod(fields[2]),
1948
+ timeFormat: "tod"
1949
+ };
1950
+ ResultFormatter.route(decodeResult, { waypoints: [wp1, wp2] });
1951
+ ResultFormatter.temperature(decodeResult, fields[3]);
1952
+ ResultFormatter.unknownArr(decodeResult, fields.slice(4));
1953
+ } else {
1954
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[0]));
1955
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1]));
1956
+ ResultFormatter.unknown(decodeResult, fields[2]);
1957
+ ResultFormatter.altitude(decodeResult, Number(fields[3]));
1958
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates((fields[4] + fields[5]).replace(/[ \.]/g, "")));
1959
+ }
1960
+ } else {
1961
+ decodeResult.decoded = false;
1962
+ ResultFormatter.unknown(decodeResult, text);
1963
+ }
1964
+ if (decodeResult.decoded) {
1965
+ if (!decodeResult.remaining.text)
1966
+ decodeResult.decoder.decodeLevel = "full";
1967
+ else
1968
+ decodeResult.decoder.decodeLevel = "partial";
1969
+ } else {
1970
+ decodeResult.decoder.decodeLevel = "none";
1971
+ }
1972
+ return decodeResult;
1973
+ }
1974
+ };
1975
+
1976
+ // lib/plugins/Label_4A_01.ts
1977
+ var Label_4A_01 = class extends DecoderPlugin {
1978
+ name = "label-4a-01";
1979
+ qualifiers() {
1980
+ return {
1981
+ labels: ["4A"],
1982
+ preambles: ["01"]
1983
+ };
1984
+ }
1985
+ decode(message, options = {}) {
1986
+ const decodeResult = this.defaultResult();
1987
+ decodeResult.decoder.name = this.name;
1988
+ decodeResult.message = message;
1989
+ decodeResult.formatted.description = "Latest New Format";
1990
+ decodeResult.decoded = true;
1991
+ 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)/);
1992
+ if (rgx) {
1993
+ ResultFormatter.state_change(decodeResult, rgx[1], rgx[2]);
1994
+ ResultFormatter.callsign(decodeResult, rgx[3]);
1995
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(rgx[4] + "00"));
1996
+ ResultFormatter.departureAirport(decodeResult, rgx[5]);
1997
+ ResultFormatter.arrivalAirport(decodeResult, rgx[6]);
1998
+ ResultFormatter.altitude(decodeResult, Number(rgx[7].replace(/ /g, "")));
1999
+ ResultFormatter.unknown(decodeResult, rgx[8]);
2000
+ ResultFormatter.temperature(decodeResult, rgx[9].replace(/ /g, ""));
2001
+ } else {
2002
+ decodeResult.decoded = false;
2003
+ ResultFormatter.unknown(decodeResult, message.text);
2004
+ }
2005
+ if (decodeResult.decoded) {
2006
+ if (!decodeResult.remaining.text)
2007
+ decodeResult.decoder.decodeLevel = "full";
2008
+ else
2009
+ decodeResult.decoder.decodeLevel = "partial";
2010
+ } else {
2011
+ decodeResult.decoder.decodeLevel = "none";
2012
+ }
2013
+ return decodeResult;
2014
+ }
2015
+ };
2016
+
2017
+ // lib/plugins/Label_4A_DIS.ts
2018
+ var Label_4A_DIS = class extends DecoderPlugin {
2019
+ name = "label-4a-dis";
2020
+ qualifiers() {
2021
+ return {
2022
+ labels: ["4A"],
2023
+ preambles: ["DIS"]
2024
+ };
2025
+ }
2026
+ decode(message, options = {}) {
2027
+ const decodeResult = this.defaultResult();
2028
+ decodeResult.decoder.name = this.name;
2029
+ decodeResult.message = message;
2030
+ decodeResult.formatted.description = "Latest New Format";
2031
+ decodeResult.decoded = true;
2032
+ const fields = message.text.split(",");
2033
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(2) + "00"));
2034
+ ResultFormatter.callsign(decodeResult, fields[2]);
2035
+ ResultFormatter.freetext(decodeResult, fields.slice(3).join(""));
2036
+ if (decodeResult.decoded) {
2037
+ if (!decodeResult.remaining.text)
2038
+ decodeResult.decoder.decodeLevel = "full";
2039
+ else
2040
+ decodeResult.decoder.decodeLevel = "partial";
2041
+ } else {
2042
+ decodeResult.decoder.decodeLevel = "none";
2043
+ }
2044
+ return decodeResult;
2045
+ }
2046
+ };
2047
+
2048
+ // lib/plugins/Label_4A_DOOR.ts
2049
+ var Label_4A_DOOR = class extends DecoderPlugin {
2050
+ name = "label-4a-door";
2051
+ qualifiers() {
2052
+ return {
2053
+ labels: ["4A"],
2054
+ preambles: ["DOOR"]
2055
+ };
2056
+ }
2057
+ decode(message, options = {}) {
2058
+ const decodeResult = this.defaultResult();
2059
+ decodeResult.decoder.name = this.name;
2060
+ decodeResult.message = message;
2061
+ decodeResult.formatted.description = "Latest New Format";
2062
+ decodeResult.decoded = true;
2063
+ const fields = message.text.split(" ");
2064
+ if (fields.length === 3) {
2065
+ ResultFormatter.door_event(decodeResult, fields[0].split("/")[1], fields[1]);
2066
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2] + "00"));
2067
+ } else {
2068
+ decodeResult.decoded = false;
2069
+ ResultFormatter.unknown(decodeResult, message.text);
2070
+ }
2071
+ if (decodeResult.decoded) {
2072
+ if (!decodeResult.remaining.text)
2073
+ decodeResult.decoder.decodeLevel = "full";
2074
+ else
2075
+ decodeResult.decoder.decodeLevel = "partial";
2076
+ } else {
2077
+ decodeResult.decoder.decodeLevel = "none";
2078
+ }
2079
+ return decodeResult;
2080
+ }
2081
+ };
2082
+
2083
+ // lib/plugins/Label_4A_Slash_01.ts
2084
+ var Label_4A_Slash_01 = class extends DecoderPlugin {
2085
+ name = "label-4a-slash-01";
2086
+ qualifiers() {
2087
+ return {
2088
+ labels: ["4A"],
2089
+ preambles: ["/01"]
2090
+ };
2091
+ }
2092
+ decode(message, options = {}) {
2093
+ const decodeResult = this.defaultResult();
2094
+ decodeResult.decoder.name = this.name;
2095
+ decodeResult.message = message;
2096
+ decodeResult.formatted.description = "Latest New Format";
2097
+ decodeResult.decoded = true;
2098
+ if (message.text.length === 5 && message.text.substring(0, 4) === "/01-") {
2099
+ ResultFormatter.unknown(decodeResult, message.text.substring(4));
2100
+ } else {
2101
+ decodeResult.decoded = false;
2102
+ ResultFormatter.unknown(decodeResult, message.text);
2103
+ }
2104
+ if (decodeResult.decoded) {
2105
+ if (!decodeResult.remaining.text)
2106
+ decodeResult.decoder.decodeLevel = "full";
2107
+ else
2108
+ decodeResult.decoder.decodeLevel = "partial";
2109
+ } else {
2110
+ decodeResult.decoder.decodeLevel = "none";
2111
+ }
1493
2112
  return decodeResult;
1494
2113
  }
1495
2114
  };
@@ -1519,13 +2138,13 @@ var Label_4N = class extends DecoderPlugin {
1519
2138
  ResultFormatter.departureAirport(decodeResult, text.substring(8, 11));
1520
2139
  ResultFormatter.arrivalAirport(decodeResult, text.substring(13, 16));
1521
2140
  ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(30, 45).replace(/^(.)0/, "$1")));
1522
- ResultFormatter.altitude(decodeResult, text.substring(48, 51) * 100);
1523
- decodeResult.remaining.text = [text.substring(2, 4), text.substring(19, 29)].join(" ");
2141
+ ResultFormatter.altitude(decodeResult, Number(text.substring(48, 51)) * 100);
2142
+ ResultFormatter.unknownArr(decodeResult, [text.substring(2, 4), text.substring(19, 29)], " ");
1524
2143
  } else if (fields.length === 33) {
1525
2144
  decodeResult.raw.date = fields[3];
1526
2145
  if (fields[1] === "B") {
1527
2146
  ResultFormatter.position(decodeResult, { latitude: Number(fields[4]), longitude: Number(fields[5]) });
1528
- ResultFormatter.altitude(decodeResult, fields[6]);
2147
+ ResultFormatter.altitude(decodeResult, Number(fields[6]));
1529
2148
  }
1530
2149
  ResultFormatter.departureAirport(decodeResult, fields[8]);
1531
2150
  ResultFormatter.arrivalAirport(decodeResult, fields[9]);
@@ -1535,13 +2154,13 @@ var Label_4N = class extends DecoderPlugin {
1535
2154
  ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
1536
2155
  }
1537
2156
  ResultFormatter.checksum(decodeResult, fields[32]);
1538
- decodeResult.remaining.text = [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != "").join(",");
2157
+ ResultFormatter.unknownArr(decodeResult, [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != ""));
1539
2158
  } else {
1540
2159
  decodeResult.decoded = false;
1541
- decodeResult.remaining.text = text;
2160
+ ResultFormatter.unknown(decodeResult, text);
1542
2161
  }
1543
2162
  if (decodeResult.decoded) {
1544
- if (decodeResult.remaining.text === "")
2163
+ if (!decodeResult.remaining.text)
1545
2164
  decodeResult.decoder.decodeLevel = "full";
1546
2165
  else
1547
2166
  decodeResult.decoder.decodeLevel = "partial";
@@ -1634,23 +2253,14 @@ var Label_80 = class extends DecoderPlugin {
1634
2253
  break;
1635
2254
  }
1636
2255
  case "FOB": {
1637
- decodeResult.raw.fuel_on_board = match.groups.value;
1638
- decodeResult.formatted.items.push({
1639
- type: "fuel_on_board",
1640
- code: "FOB",
1641
- label: this.descriptions[match.groups.field],
1642
- value: decodeResult.raw.fuel_on_board
1643
- });
2256
+ const fob = Number(match.groups.value);
2257
+ if (!isNaN(fob)) {
2258
+ ResultFormatter.currentFuel(decodeResult, fob);
2259
+ }
1644
2260
  break;
1645
2261
  }
1646
2262
  case "HDG": {
1647
- decodeResult.raw.heading = Number(match.groups.value);
1648
- decodeResult.formatted.items.push({
1649
- type: "heading",
1650
- code: "HDG",
1651
- label: this.descriptions[match.groups.field],
1652
- value: decodeResult.raw.heading
1653
- });
2263
+ ResultFormatter.heading(decodeResult, Number(match.groups.value));
1654
2264
  break;
1655
2265
  }
1656
2266
  case "MCH": {
@@ -1740,17 +2350,20 @@ var Label_83 = class extends DecoderPlugin {
1740
2350
  if (fields[2].length > 5) {
1741
2351
  decodeResult.raw.day_of_month = fields[2].substring(5);
1742
2352
  }
1743
- decodeResult.remaining.text = fields[2].substring(0, 4);
2353
+ ResultFormatter.unknown(decodeResult, fields[2].substring(0, 4));
1744
2354
  const subfields = fields[3].split("/");
1745
2355
  ResultFormatter.departureAirport(decodeResult, subfields[0]);
1746
2356
  ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
1747
2357
  ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
1748
- ResultFormatter.eta(decodeResult, fields[6] + "00");
2358
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[6] + "00"));
1749
2359
  } else if (text.substring(0, 5) === "001PR") {
1750
2360
  decodeResult.raw.day_of_month = text.substring(5, 7);
1751
- ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(13, 28).replace(/\./g, "")));
2361
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(13, 28).replace(/\./g, ""));
2362
+ if (position) {
2363
+ ResultFormatter.position(decodeResult, position);
2364
+ }
1752
2365
  ResultFormatter.altitude(decodeResult, Number(text.substring(28, 33)));
1753
- decodeResult.remaining.text = text.substring(33);
2366
+ ResultFormatter.unknown(decodeResult, text.substring(33));
1754
2367
  } else {
1755
2368
  const fields = text.replace(/\s/g, "").split(",");
1756
2369
  if (fields.length === 9) {
@@ -1765,17 +2378,17 @@ var Label_83 = class extends DecoderPlugin {
1765
2378
  longitude: Number(fields[4].replace(/\s/g, ""))
1766
2379
  }
1767
2380
  );
1768
- ResultFormatter.altitude(decodeResult, fields[5]);
1769
- ResultFormatter.groundspeed(decodeResult, fields[6]);
1770
- ResultFormatter.heading(decodeResult, fields[7]);
1771
- decodeResult.remaining.text = fields[8];
2381
+ ResultFormatter.altitude(decodeResult, Number(fields[5]));
2382
+ ResultFormatter.groundspeed(decodeResult, Number(fields[6]));
2383
+ ResultFormatter.heading(decodeResult, Number(fields[7]));
2384
+ ResultFormatter.unknown(decodeResult, fields[8]);
1772
2385
  } else {
1773
2386
  decodeResult.decoded = false;
1774
- decodeResult.remaining.text = message.text;
2387
+ ResultFormatter.unknown(decodeResult, message.text);
1775
2388
  }
1776
2389
  }
1777
2390
  if (decodeResult.decoded) {
1778
- if (decodeResult.remaining.text === "")
2391
+ if (!decodeResult.remaining.text)
1779
2392
  decodeResult.decoder.decodeLevel = "full";
1780
2393
  else
1781
2394
  decodeResult.decoder.decodeLevel = "partial";
@@ -1801,24 +2414,13 @@ var Label_8E = class extends DecoderPlugin {
1801
2414
  decodeResult.message = message;
1802
2415
  const regex = /^(?<arrival_icao>\w{4}),(?<arrival_eta>\d{4})$/;
1803
2416
  const results = message.text.match(regex);
1804
- if (results) {
2417
+ if (results?.groups) {
1805
2418
  if (options.debug) {
1806
2419
  console.log(`Label 8E ETA: groups`);
1807
2420
  console.log(results.groups);
1808
2421
  }
1809
- decodeResult.formatted.items.push({
1810
- type: "eta",
1811
- code: "ETA",
1812
- label: "Estimated Time of Arrival",
1813
- value: DateTimeUtils.UTCToString(results.groups.arrival_eta)
1814
- });
1815
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1816
- decodeResult.formatted.items.push({
1817
- type: "destination",
1818
- code: "DST",
1819
- label: "Destination",
1820
- value: decodeResult.raw.arrival_icao
1821
- });
2422
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta + "00"));
2423
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1822
2424
  }
1823
2425
  decodeResult.decoded = true;
1824
2426
  decodeResult.decoder.decodeLevel = "full";
@@ -1863,7 +2465,8 @@ var Label_ColonComma = class extends DecoderPlugin {
1863
2465
  decodeResult.formatted.items.push({
1864
2466
  type: "frequency",
1865
2467
  label: "Frequency",
1866
- value: `${decodeResult.raw.frequency} MHz`
2468
+ value: `${decodeResult.raw.frequency} MHz`,
2469
+ code: "FREQ"
1867
2470
  });
1868
2471
  decodeResult.decoded = true;
1869
2472
  decodeResult.decoder.decodeLevel = "full";
@@ -1871,62 +2474,6 @@ var Label_ColonComma = class extends DecoderPlugin {
1871
2474
  }
1872
2475
  };
1873
2476
 
1874
- // lib/plugins/Label_H1_FLR.ts
1875
- var Label_H1_FLR = class extends DecoderPlugin {
1876
- name = "label-h1-flr";
1877
- qualifiers() {
1878
- return {
1879
- labels: ["H1"],
1880
- preambles: ["FLR", "#CFBFLR"]
1881
- };
1882
- }
1883
- decode(message, options = {}) {
1884
- let decodeResult = this.defaultResult();
1885
- decodeResult.decoder.name = this.name;
1886
- decodeResult.formatted.description = "Fault Log Report";
1887
- decodeResult.message = message;
1888
- const parts = message.text.split("/FR");
1889
- if (parts.length > 1) {
1890
- decodeResult.remaining.text = "";
1891
- const fields = parts[0].split("/");
1892
- for (let i = 1; i < fields.length; i++) {
1893
- const field = fields[i];
1894
- if (field.startsWith("PN")) {
1895
- processUnknown(decodeResult, "/" + field);
1896
- } else {
1897
- processUnknown(decodeResult, "/" + field);
1898
- }
1899
- }
1900
- const data = parts[1].substring(0, 20);
1901
- const msg = parts[1].substring(20);
1902
- const datetime = data.substring(0, 12);
1903
- const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
1904
- processUnknown(decodeResult, data.substring(12));
1905
- decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
1906
- decodeResult.raw.fault_message = msg;
1907
- decodeResult.formatted.items.push({
1908
- type: "fault",
1909
- code: "FR",
1910
- label: "Fault Report",
1911
- value: decodeResult.raw.fault_message
1912
- });
1913
- decodeResult.decoded = true;
1914
- decodeResult.decoder.decodeLevel = "partial";
1915
- } else {
1916
- if (options.debug) {
1917
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
1918
- }
1919
- decodeResult.remaining.text = message.text;
1920
- decodeResult.decoded = false;
1921
- decodeResult.decoder.decodeLevel = "none";
1922
- }
1923
- return decodeResult;
1924
- }
1925
- };
1926
- function processUnknown(decodeResult, value) {
1927
- decodeResult.remaining.text += value;
1928
- }
1929
-
1930
2477
  // lib/utils/flight_plan_utils.ts
1931
2478
  var FlightPlanUtils = class _FlightPlanUtils {
1932
2479
  /**
@@ -1968,6 +2515,8 @@ var FlightPlanUtils = class _FlightPlanUtils {
1968
2515
  case "R":
1969
2516
  addRunway(decodeResult, value);
1970
2517
  break;
2518
+ // case 'WS': // something about routes, has altitude, so current parsing won't work
2519
+ // break;
1971
2520
  default:
1972
2521
  if (allKnownFields) {
1973
2522
  decodeResult.remaining.text = "";
@@ -2030,13 +2579,7 @@ function addRunway(decodeResult, value) {
2030
2579
  }
2031
2580
  function addRoute(decodeResult, value) {
2032
2581
  const route = value.split(".");
2033
- decodeResult.raw.route = { waypoints: route.map((leg) => RouteUtils.getWaypoint(leg)) };
2034
- decodeResult.formatted.items.push({
2035
- type: "aircraft_route",
2036
- code: "ROUTE",
2037
- label: "Aircraft Route",
2038
- value: RouteUtils.routeToString(decodeResult.raw.route)
2039
- });
2582
+ ResultFormatter.route(decodeResult, { waypoints: route.map((leg) => RouteUtils.getWaypoint(leg)) });
2040
2583
  }
2041
2584
  function addProcedure(decodeResult, value, type) {
2042
2585
  if (decodeResult.raw.procedures === void 0) {
@@ -2089,11 +2632,10 @@ function addCompanyRoute(decodeResult, value) {
2089
2632
  // lib/utils/h1_helper.ts
2090
2633
  var H1Helper = class {
2091
2634
  static decodeH1Message(decodeResult, message) {
2092
- let allKnownFields = true;
2093
2635
  const checksum = message.slice(-4);
2094
2636
  const data = message.slice(0, message.length - 4);
2095
2637
  const fields = data.split("/");
2096
- allKnownFields = allKnownFields && parseMessageType(decodeResult, fields[0]);
2638
+ parseMessageType(decodeResult, fields[0]);
2097
2639
  for (let i = 1; i < fields.length; ++i) {
2098
2640
  if (fields[i].startsWith("FN")) {
2099
2641
  decodeResult.raw.flight_number = fields[i].substring(2);
@@ -2112,59 +2654,49 @@ var H1Helper = class {
2112
2654
  decodeResult.raw.message_timestamp = time;
2113
2655
  } else if (fields[i].startsWith("PS")) {
2114
2656
  const pos = processPS(decodeResult, fields[i].substring(2).split(","));
2115
- allKnownFields == allKnownFields && pos;
2116
2657
  } else if (fields[i].startsWith("DT")) {
2117
2658
  const data2 = fields[i].substring(2).split(",");
2118
- const dt = processDT(decodeResult, data2);
2119
- allKnownFields = allKnownFields && dt;
2659
+ processDT(decodeResult, data2);
2120
2660
  } else if (fields[i].startsWith("ID")) {
2121
2661
  processIdentification(decodeResult, fields[i].substring(2).split(","));
2122
2662
  } else if (fields[i].startsWith("LR")) {
2123
2663
  const data2 = fields[i].substring(2).split(",");
2124
- const lr = processLR(decodeResult, data2);
2125
- allKnownFields = allKnownFields && lr;
2664
+ processLR(decodeResult, data2);
2126
2665
  } else if (fields[i].startsWith("RI") || fields[i].startsWith("RF") || fields[i].startsWith("RP")) {
2127
- const fp = FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
2128
- allKnownFields = allKnownFields && fp;
2666
+ FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
2129
2667
  } else if (fields[i].startsWith("PR")) {
2130
- allKnownFields = false;
2131
- decodeResult.remaining.text += "/" + fields[i];
2132
- } else if (fields[i].startsWith("PS")) {
2133
- allKnownFields = false;
2134
- decodeResult.remaining.text += fields[i];
2668
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
2135
2669
  } else if (fields[i].startsWith("AF")) {
2136
- const af = processAirField(decodeResult, fields[i].substring(2).split(","));
2137
- allKnownFields = allKnownFields && af;
2670
+ processAirField(decodeResult, fields[i].substring(2).split(","));
2138
2671
  } else if (fields[i].startsWith("TD")) {
2139
- const td = processTimeOfDeparture(decodeResult, fields[i].substring(2).split(","));
2140
- allKnownFields = allKnownFields && td;
2672
+ processTimeOfDeparture(decodeResult, fields[i].substring(2).split(","));
2141
2673
  } else if (fields[i].startsWith("FX")) {
2142
- decodeResult.raw.free_text = fields[i].substring(2);
2143
- decodeResult.formatted.items.push({
2144
- type: "text",
2145
- code: "TEXT",
2146
- label: "Free Text",
2147
- value: decodeResult.raw.free_text
2148
- });
2674
+ ResultFormatter.freetext(decodeResult, fields[i].substring(2));
2675
+ } else if (fields[i].startsWith("ET")) {
2676
+ if (fields[i].length === 7) {
2677
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(3) + "00"));
2678
+ } else if (fields[i].length === 8) {
2679
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(4) + "00"));
2680
+ } else {
2681
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
2682
+ }
2149
2683
  } else {
2150
- decodeResult.remaining.text += "/" + fields[i];
2151
- allKnownFields = false;
2684
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
2152
2685
  }
2153
2686
  }
2154
2687
  if (decodeResult.formatted.items.length > 0) {
2155
2688
  ResultFormatter.checksum(decodeResult, checksum);
2156
2689
  }
2157
- return allKnownFields;
2690
+ return true;
2158
2691
  }
2159
2692
  };
2160
2693
  function processAirField(decodeResult, data) {
2161
2694
  if (data.length === 2) {
2162
2695
  ResultFormatter.departureAirport(decodeResult, data[0]);
2163
2696
  ResultFormatter.arrivalAirport(decodeResult, data[1]);
2164
- return true;
2697
+ } else {
2698
+ ResultFormatter.unknown(decodeResult, data.join(","), "AF/");
2165
2699
  }
2166
- decodeResult.remaining.text += "AF/" + data.join(",");
2167
- return false;
2168
2700
  }
2169
2701
  function processTimeOfDeparture(decodeResult, data) {
2170
2702
  if (data.length === 2) {
@@ -2182,10 +2714,9 @@ function processTimeOfDeparture(decodeResult, data) {
2182
2714
  label: "Estimated Departure Time",
2183
2715
  value: `${data[1].substring(0, 2)}:${data[1].substring(2)}`
2184
2716
  });
2185
- return true;
2717
+ } else {
2718
+ ResultFormatter.unknown(decodeResult, data.join(","), "/TD");
2186
2719
  }
2187
- decodeResult.remaining.text += "/TD" + data.join(",");
2188
- return false;
2189
2720
  }
2190
2721
  function processIdentification(decodeResult, data) {
2191
2722
  ResultFormatter.tail(decodeResult, data[0]);
@@ -2197,11 +2728,10 @@ function processIdentification(decodeResult, data) {
2197
2728
  }
2198
2729
  }
2199
2730
  function processDT(decodeResult, data) {
2200
- let allKnownFields = true;
2201
2731
  if (!decodeResult.raw.arrival_icao) {
2202
2732
  ResultFormatter.arrivalAirport(decodeResult, data[0]);
2203
2733
  } else if (decodeResult.raw.arrival_icao != data[0]) {
2204
- decodeResult.remaining.text += "/" + data;
2734
+ ResultFormatter.unknownArr(decodeResult, data);
2205
2735
  }
2206
2736
  if (data.length > 1) {
2207
2737
  ResultFormatter.arrivalRunway(decodeResult, data[1]);
@@ -2210,19 +2740,16 @@ function processDT(decodeResult, data) {
2210
2740
  ResultFormatter.currentFuel(decodeResult, Number(data[2]));
2211
2741
  }
2212
2742
  if (data.length > 3) {
2213
- ResultFormatter.eta(decodeResult, data[3]);
2743
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[3]));
2214
2744
  }
2215
2745
  if (data.length > 4) {
2216
2746
  ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
2217
2747
  }
2218
2748
  if (data.length > 5) {
2219
- allKnownFields = false;
2220
- decodeResult.remaining.text += "," + data.slice(5).join(",");
2749
+ ResultFormatter.unknownArr(decodeResult, data);
2221
2750
  }
2222
- return allKnownFields;
2223
2751
  }
2224
2752
  function processLR(decodeResult, data) {
2225
- let allKnownFields = true;
2226
2753
  if (data.length === 19) {
2227
2754
  ResultFormatter.unknown(decodeResult, data[1]);
2228
2755
  ResultFormatter.flightNumber(decodeResult, data[2]);
@@ -2230,34 +2757,47 @@ function processLR(decodeResult, data) {
2230
2757
  ResultFormatter.arrivalAirport(decodeResult, data[4]);
2231
2758
  ResultFormatter.arrivalRunway(decodeResult, data[5]);
2232
2759
  ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
2233
- allKnownFields = false;
2234
2760
  } else {
2235
- allKnownFields = false;
2761
+ ResultFormatter.unknown(decodeResult, data.join(","));
2236
2762
  }
2237
- return allKnownFields;
2238
2763
  }
2239
2764
  function parseMessageType(decodeResult, messageType) {
2240
- let decoded = true;
2241
2765
  const parts = messageType.split("#");
2242
2766
  if (parts.length == 1) {
2243
- if (parts[0].startsWith("POS") && parts[0].length !== 3 && !parts[0].startsWith("POS/")) {
2244
- decoded = processPosition2(decodeResult, parts[0].substring(3).split(","));
2767
+ const type = parts[0].substring(0, 3);
2768
+ if (type === "POS" && parts[0].length !== 3) {
2769
+ processPosition2(decodeResult, parts[0].substring(3).split(","));
2245
2770
  }
2246
- return decoded;
2771
+ return processMessageType(decodeResult, type);
2247
2772
  } else if (parts.length == 2) {
2248
2773
  if (parts[0].length > 0) {
2249
- decodeResult.remaining.text += parts[0].substring(0, 3);
2774
+ ResultFormatter.unknown(decodeResult, parts[0].substring(0, 3));
2250
2775
  decodeResult.raw.flight_number = parts[0].substring(3);
2251
- decodeResult.remaining.text += "#" + parts[1].substring(0, 3);
2776
+ ResultFormatter.unknown(decodeResult, parts[1].length == 5 ? parts[1].substring(0, 2) : parts[1].substring(0, 3), "#");
2252
2777
  }
2253
- if (parts[1].substring(3, 6) === "POS" && parts[1].length !== 6 && parts[1].substring(3, 7) !== "POS/") {
2254
- decoded = processPosition2(decodeResult, parts[1].substring(6).split(","));
2778
+ const type = parts[1].length == 5 ? parts[1].substring(2, 5) : parts[1].substring(3, 6);
2779
+ if (parts[1].substring(3, 6) === "POS" && parts[1].length > 6) {
2780
+ processPosition2(decodeResult, parts[1].substring(6).split(","));
2255
2781
  }
2256
- decodeResult.raw.message_type = messageType;
2257
- return decoded;
2782
+ processMessageType(decodeResult, type);
2783
+ } else {
2784
+ ResultFormatter.unknown(decodeResult, messageType);
2785
+ }
2786
+ }
2787
+ function processMessageType(decodeResult, type) {
2788
+ if (type === "FPN") {
2789
+ decodeResult.formatted.description = "Flight Plan";
2790
+ } else if (type === "FTX") {
2791
+ decodeResult.formatted.description = "Free Text";
2792
+ } else if (type === "INI") {
2793
+ decodeResult.formatted.description = "Flight Plan Initial Report";
2794
+ } else if (type === "POS") {
2795
+ decodeResult.formatted.description = "Position Report";
2796
+ } else if (type === "PRG") {
2797
+ decodeResult.formatted.description = "Progress Report";
2798
+ } else {
2799
+ decodeResult.formatted.description = "Unknown H1 Message";
2258
2800
  }
2259
- decodeResult.remaining.text += messageType;
2260
- return false;
2261
2801
  }
2262
2802
  function processDC(decodeResult, data) {
2263
2803
  decodeResult.raw.message_date = data[0];
@@ -2266,13 +2806,9 @@ function processDC(decodeResult, data) {
2266
2806
  const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
2267
2807
  const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
2268
2808
  decodeResult.raw.message_timestamp = time;
2269
- } else {
2270
- return false;
2271
2809
  }
2272
- return true;
2273
2810
  }
2274
2811
  function processPS(decodeResult, data) {
2275
- let allKnownFields = true;
2276
2812
  const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2277
2813
  if (position) {
2278
2814
  decodeResult.raw.position = position;
@@ -2282,8 +2818,6 @@ function processPS(decodeResult, data) {
2282
2818
  label: "Aircraft Position",
2283
2819
  value: CoordinateUtils.coordinateString(position)
2284
2820
  });
2285
- } else {
2286
- allKnownFields = false;
2287
2821
  }
2288
2822
  if (data.length === 9) {
2289
2823
  processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
@@ -2302,11 +2836,8 @@ function processPS(decodeResult, data) {
2302
2836
  ResultFormatter.unknown(decodeResult, data[9]);
2303
2837
  ResultFormatter.unknown(decodeResult, data.slice(11).join(","));
2304
2838
  }
2305
- allKnownFields = false;
2306
- return allKnownFields;
2307
2839
  }
2308
2840
  function processPosition2(decodeResult, data) {
2309
- let allKnownFields = true;
2310
2841
  const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2311
2842
  if (position) {
2312
2843
  decodeResult.raw.position = position;
@@ -2316,8 +2847,6 @@ function processPosition2(decodeResult, data) {
2316
2847
  label: "Aircraft Position",
2317
2848
  value: CoordinateUtils.coordinateString(position)
2318
2849
  });
2319
- } else {
2320
- allKnownFields = false;
2321
2850
  }
2322
2851
  if (data.length >= 10) {
2323
2852
  ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
@@ -2332,8 +2861,6 @@ function processPosition2(decodeResult, data) {
2332
2861
  ResultFormatter.unknown(decodeResult, data[12]);
2333
2862
  ResultFormatter.unknown(decodeResult, data[13]);
2334
2863
  }
2335
- allKnownFields = false;
2336
- return allKnownFields;
2337
2864
  }
2338
2865
  function processRoute(decodeResult, last, time, next, eta, then, date) {
2339
2866
  const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
@@ -2356,30 +2883,27 @@ function processRoute(decodeResult, last, time, next, eta, then, date) {
2356
2883
  });
2357
2884
  }
2358
2885
 
2359
- // lib/plugins/Label_H1_FPN.ts
2360
- var Label_H1_FPN = class extends DecoderPlugin {
2361
- name = "label-h1-fpn";
2886
+ // lib/plugins/Label_H1.ts
2887
+ var Label_H1 = class extends DecoderPlugin {
2888
+ name = "label-h1";
2362
2889
  qualifiers() {
2363
2890
  return {
2364
- labels: ["H1"],
2365
- preambles: ["FPN", "#M1BFPN"]
2891
+ labels: ["H1"]
2366
2892
  };
2367
2893
  }
2368
2894
  decode(message, options = {}) {
2369
2895
  let decodeResult = this.defaultResult();
2370
2896
  decodeResult.decoder.name = this.name;
2371
- decodeResult.formatted.description = "Flight Plan";
2372
2897
  decodeResult.message = message;
2373
- decodeResult.remaining.text = "";
2374
2898
  const msg = message.text.replace(/\n|\r/g, "");
2375
- const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, msg);
2376
- decodeResult.decoded = true;
2377
- decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
2899
+ const decoded = H1Helper.decodeH1Message(decodeResult, msg);
2900
+ decodeResult.decoded = decoded;
2901
+ decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
2378
2902
  if (decodeResult.formatted.items.length === 0) {
2379
2903
  if (options.debug) {
2380
2904
  console.log(`Decoder: Unknown H1 message: ${message.text}`);
2381
2905
  }
2382
- decodeResult.remaining.text = message.text;
2906
+ ResultFormatter.unknown(decodeResult, message.text);
2383
2907
  decodeResult.decoded = false;
2384
2908
  decodeResult.decoder.decodeLevel = "none";
2385
2909
  }
@@ -2387,60 +2911,47 @@ var Label_H1_FPN = class extends DecoderPlugin {
2387
2911
  }
2388
2912
  };
2389
2913
 
2390
- // lib/plugins/Label_H1_FTX.ts
2391
- var Label_H1_FTX = class extends DecoderPlugin {
2392
- name = "label-h1-ftx";
2914
+ // lib/plugins/Label_H1_FLR.ts
2915
+ var Label_H1_FLR = class extends DecoderPlugin {
2916
+ name = "label-h1-flr";
2393
2917
  qualifiers() {
2394
2918
  return {
2395
2919
  labels: ["H1"],
2396
- preambles: ["FTX", "- #MDFTX"]
2920
+ preambles: ["FLR", "#CFBFLR"]
2397
2921
  };
2398
2922
  }
2399
2923
  decode(message, options = {}) {
2400
2924
  let decodeResult = this.defaultResult();
2401
2925
  decodeResult.decoder.name = this.name;
2402
- decodeResult.formatted.description = "Free Text";
2926
+ decodeResult.formatted.description = "Fault Log Report";
2403
2927
  decodeResult.message = message;
2404
- decodeResult.remaining.text = "";
2405
- const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
2406
- decodeResult.decoded = true;
2407
- decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
2408
- if (decodeResult.formatted.items.length === 0) {
2409
- if (options.debug) {
2410
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
2928
+ const parts = message.text.split("/FR");
2929
+ if (parts.length > 1) {
2930
+ const fields = parts[0].split("/");
2931
+ for (let i = 1; i < fields.length; i++) {
2932
+ const field = fields[i];
2933
+ ResultFormatter.unknown(decodeResult, field, "/");
2411
2934
  }
2412
- decodeResult.remaining.text = message.text;
2413
- decodeResult.decoded = false;
2414
- decodeResult.decoder.decodeLevel = "none";
2415
- }
2416
- return decodeResult;
2417
- }
2418
- };
2419
-
2420
- // lib/plugins/Label_H1_INI.ts
2421
- var Label_H1_INI = class extends DecoderPlugin {
2422
- // eslint-disable-line camelcase
2423
- name = "label-h1-ini";
2424
- qualifiers() {
2425
- return {
2426
- labels: ["H1"],
2427
- preambles: ["INI", "- #MDINI"]
2428
- };
2429
- }
2430
- decode(message, options = {}) {
2431
- const decodeResult = this.defaultResult();
2432
- decodeResult.decoder.name = this.name;
2433
- decodeResult.formatted.description = "Flight Plan Initial Report";
2434
- decodeResult.message = message;
2435
- decodeResult.remaining.text = "";
2436
- const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
2437
- decodeResult.decoded = true;
2438
- decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
2439
- if (decodeResult.formatted.items.length === 0) {
2935
+ const data = parts[1].substring(0, 20);
2936
+ const msg = parts[1].substring(20);
2937
+ const datetime = data.substring(0, 12);
2938
+ const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
2939
+ ResultFormatter.unknown(decodeResult, data.substring(12), "/");
2940
+ decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
2941
+ decodeResult.raw.fault_message = msg;
2942
+ decodeResult.formatted.items.push({
2943
+ type: "fault",
2944
+ code: "FR",
2945
+ label: "Fault Report",
2946
+ value: decodeResult.raw.fault_message
2947
+ });
2948
+ decodeResult.decoded = true;
2949
+ decodeResult.decoder.decodeLevel = "partial";
2950
+ } else {
2440
2951
  if (options.debug) {
2441
2952
  console.log(`Decoder: Unknown H1 message: ${message.text}`);
2442
2953
  }
2443
- decodeResult.remaining.text = message.text;
2954
+ ResultFormatter.unknown(decodeResult, message.text);
2444
2955
  decodeResult.decoded = false;
2445
2956
  decodeResult.decoder.decodeLevel = "none";
2446
2957
  }
@@ -2463,7 +2974,6 @@ var Label_H1_OHMA = class extends DecoderPlugin {
2463
2974
  decodeResult.decoder.name = this.name;
2464
2975
  decodeResult.formatted.description = "OHMA Message";
2465
2976
  decodeResult.message = message;
2466
- decodeResult.remaining.text = "";
2467
2977
  const data = message.text.split("OHMA")[1];
2468
2978
  try {
2469
2979
  const compressedBuffer = Buffer.from(data, "base64");
@@ -2498,7 +3008,7 @@ var Label_H1_OHMA = class extends DecoderPlugin {
2498
3008
  if (options.debug) {
2499
3009
  console.log(`Decoder: Unknown H1 OHMA message: ${message.text}`, e);
2500
3010
  }
2501
- decodeResult.remaining.text += message.text;
3011
+ ResultFormatter.unknown(decodeResult, message.text);
2502
3012
  decodeResult.decoded = false;
2503
3013
  decodeResult.decoder.decodeLevel = "none";
2504
3014
  }
@@ -2506,14 +3016,13 @@ var Label_H1_OHMA = class extends DecoderPlugin {
2506
3016
  }
2507
3017
  };
2508
3018
 
2509
- // lib/plugins/Label_H1_POS.ts
2510
- var Label_H1_POS = class extends DecoderPlugin {
2511
- name = "label-h1-pos";
3019
+ // lib/plugins/Label_H1_StarPOS.ts
3020
+ var Label_H1_StarPOS = class extends DecoderPlugin {
3021
+ name = "label-h1-star-pos";
2512
3022
  qualifiers() {
2513
3023
  return {
2514
- labels: ["H1", "4J"],
2515
- preambles: ["POS", "#M1BPOS", "/.POS"]
2516
- //TODO - support data before #
3024
+ labels: ["H1"],
3025
+ preambles: ["*POS"]
2517
3026
  };
2518
3027
  }
2519
3028
  decode(message, options = {}) {
@@ -2521,18 +3030,28 @@ var Label_H1_POS = class extends DecoderPlugin {
2521
3030
  decodeResult.decoder.name = this.name;
2522
3031
  decodeResult.formatted.description = "Position Report";
2523
3032
  decodeResult.message = message;
2524
- decodeResult.remaining.text = "";
2525
- const fulllyDecoded = H1Helper.decodeH1Message(decodeResult, message.text);
2526
- decodeResult.decoded = true;
2527
- decodeResult.decoder.decodeLevel = fulllyDecoded ? "full" : "partial";
2528
- if (decodeResult.formatted.items.length === 0) {
3033
+ const msg = message.text;
3034
+ if (msg.length !== 43 || !msg.startsWith("*POS")) {
2529
3035
  if (options.debug) {
2530
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
3036
+ console.log(`Decoder: Unknown H1 message: ${msg}`);
2531
3037
  }
2532
- decodeResult.remaining.text = message.text;
3038
+ ResultFormatter.unknown(decodeResult, msg);
2533
3039
  decodeResult.decoded = false;
2534
3040
  decodeResult.decoder.decodeLevel = "none";
3041
+ return decodeResult;
2535
3042
  }
3043
+ decodeResult.raw.month = Number(msg.substring(4, 6));
3044
+ decodeResult.raw.day_of_month = Number(msg.substring(6, 8));
3045
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(msg.substring(8, 12) + "00"));
3046
+ ResultFormatter.position(decodeResult, {
3047
+ // Deg Min, no sec
3048
+ latitude: CoordinateUtils.getDirection(msg.substring(12, 13)) * (Number(msg.substring(13, 15)) + Number(msg.substring(15, 17)) / 60),
3049
+ longitude: CoordinateUtils.getDirection(msg.substring(17, 18)) * (Number(msg.substring(18, 21)) + Number(msg.substring(21, 23)) / 60)
3050
+ });
3051
+ ResultFormatter.altitude(decodeResult, Number(msg.substring(23, 28)));
3052
+ ResultFormatter.unknown(decodeResult, msg.substring(28));
3053
+ decodeResult.decoded = true;
3054
+ decodeResult.decoder.decodeLevel = "partial";
2536
3055
  return decodeResult;
2537
3056
  }
2538
3057
  };
@@ -2553,21 +3072,13 @@ var Label_H1_WRN = class extends DecoderPlugin {
2553
3072
  decodeResult.message = message;
2554
3073
  const parts = message.text.split("/WN");
2555
3074
  if (parts.length > 1) {
2556
- decodeResult.remaining.text = "";
2557
3075
  const fields = parts[0].split("/");
2558
- for (let i = 1; i < fields.length; i++) {
2559
- const field = fields[i];
2560
- if (field.startsWith("PN")) {
2561
- processUnknown2(decodeResult, "/" + field);
2562
- } else {
2563
- processUnknown2(decodeResult, "/" + field);
2564
- }
2565
- }
3076
+ ResultFormatter.unknownArr(decodeResult, fields.slice(1), "/");
2566
3077
  const data = parts[1].substring(0, 20);
2567
3078
  const msg = parts[1].substring(20);
2568
3079
  const datetime = data.substring(0, 12);
2569
3080
  const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
2570
- processUnknown2(decodeResult, data.substring(12));
3081
+ ResultFormatter.unknown(decodeResult, data.substring(12), "/");
2571
3082
  decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
2572
3083
  decodeResult.raw.warning_message = msg;
2573
3084
  decodeResult.formatted.items.push({
@@ -2582,16 +3093,13 @@ var Label_H1_WRN = class extends DecoderPlugin {
2582
3093
  if (options.debug) {
2583
3094
  console.log(`Decoder: Unknown H1 message: ${message.text}`);
2584
3095
  }
2585
- decodeResult.remaining.text = message.text;
3096
+ ResultFormatter.unknown(decodeResult, message.text);
2586
3097
  decodeResult.decoded = false;
2587
3098
  decodeResult.decoder.decodeLevel = "none";
2588
3099
  }
2589
3100
  return decodeResult;
2590
3101
  }
2591
3102
  };
2592
- function processUnknown2(decodeResult, value) {
2593
- decodeResult.remaining.text += value;
2594
- }
2595
3103
 
2596
3104
  // lib/plugins/Label_HX.ts
2597
3105
  var Label_HX = class extends DecoderPlugin {
@@ -2616,27 +3124,20 @@ var Label_HX = class extends DecoderPlugin {
2616
3124
  let londir = parts[4].substring(0, 1);
2617
3125
  let londeg = Number(parts[4].substring(1, 4));
2618
3126
  let lonmin = Number(parts[4].substring(4, 8));
2619
- decodeResult.raw.position = {
3127
+ let pos = {
2620
3128
  latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
2621
3129
  longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
2622
3130
  };
2623
- decodeResult.remaining.text = parts.slice(5).join(" ");
3131
+ ResultFormatter.unknownArr(decodeResult, parts.slice(5), " ");
3132
+ ResultFormatter.position(decodeResult, pos);
2624
3133
  } else if (parts[2] === "43") {
2625
3134
  ResultFormatter.departureAirport(decodeResult, parts[3]);
2626
- decodeResult.remaining.text = parts.slice(4).join(" ");
3135
+ ResultFormatter.unknownArr(decodeResult, parts.slice(4), " ");
2627
3136
  } else {
2628
3137
  decodeResult.decoded = false;
2629
3138
  }
2630
- if (decodeResult.raw.position) {
2631
- decodeResult.formatted.items.push({
2632
- type: "aircraft_position",
2633
- code: "POS",
2634
- label: "Aircraft Position",
2635
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
2636
- });
2637
- }
2638
3139
  if (decodeResult.decoded) {
2639
- if (decodeResult.remaining.text === "")
3140
+ if (!decodeResult.remaining.text)
2640
3141
  decodeResult.decoder.decodeLevel = "full";
2641
3142
  else
2642
3143
  decodeResult.decoder.decodeLevel = "partial";
@@ -2664,7 +3165,7 @@ var Label_SQ = class extends DecoderPlugin {
2664
3165
  if (decodeResult.raw.version === "2") {
2665
3166
  const regex = /0(\d)X(?<org>\w)(?<iata>\w\w\w)(?<icao>\w\w\w\w)(?<station>\d)(?<lat>\d+)(?<latd>[NS])(?<lng>\d+)(?<lngd>[EW])V(?<vfreq>\d+)\/.*/;
2666
3167
  const result = message.text.match(regex);
2667
- if (result && result.length >= 8) {
3168
+ if (result?.groups && result.length >= 8) {
2668
3169
  decodeResult.raw.groundStation = {
2669
3170
  number: result.groups.station,
2670
3171
  iataCode: result.groups.iata,
@@ -2674,7 +3175,7 @@ var Label_SQ = class extends DecoderPlugin {
2674
3175
  longitude: Number(result.groups.lng) / 100 * (result.groups.lngd === "W" ? -1 : 1)
2675
3176
  }
2676
3177
  };
2677
- decodeResult.raw.vdlFrequency = result.groups.vfreq / 1e3;
3178
+ decodeResult.raw.vdlFrequency = Number(result.groups.vfreq) / 1e3;
2678
3179
  }
2679
3180
  }
2680
3181
  decodeResult.formatted.description = "Ground Station Squitter";
@@ -2765,33 +3266,13 @@ var Label_QR = class extends DecoderPlugin {
2765
3266
  decode(message, options = {}) {
2766
3267
  const decodeResult = this.defaultResult();
2767
3268
  decodeResult.decoder.name = this.name;
2768
- decodeResult.raw.origin = message.text.substring(0, 4);
2769
- decodeResult.raw.destination = message.text.substring(4, 8);
2770
- decodeResult.raw.wheels_on = message.text.substring(8, 12);
2771
- decodeResult.remaining.text = message.text.substring(12);
2772
3269
  decodeResult.formatted.description = "ON Report";
2773
- decodeResult.formatted.items = [
2774
- {
2775
- type: "origin",
2776
- code: "ORG",
2777
- label: "Origin",
2778
- value: decodeResult.raw.origin
2779
- },
2780
- {
2781
- type: "destination",
2782
- code: "DST",
2783
- label: "Destination",
2784
- value: decodeResult.raw.destination
2785
- },
2786
- {
2787
- type: "wheels_on",
2788
- code: "WON",
2789
- label: "Wheels ON",
2790
- value: decodeResult.raw.wheels_on
2791
- }
2792
- ];
3270
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3271
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3272
+ ResultFormatter.on(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3273
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
2793
3274
  decodeResult.decoded = true;
2794
- if (decodeResult.remaining.text === "")
3275
+ if (!decodeResult.remaining.text)
2795
3276
  decodeResult.decoder.decodeLevel = "full";
2796
3277
  else
2797
3278
  decodeResult.decoder.decodeLevel = "partial";
@@ -2810,33 +3291,13 @@ var Label_QP = class extends DecoderPlugin {
2810
3291
  decode(message, options = {}) {
2811
3292
  const decodeResult = this.defaultResult();
2812
3293
  decodeResult.decoder.name = this.name;
2813
- decodeResult.raw.origin = message.text.substring(0, 4);
2814
- decodeResult.raw.destination = message.text.substring(4, 8);
2815
- decodeResult.raw.gate_out = message.text.substring(8, 12);
2816
- decodeResult.remaining.text = message.text.substring(12);
2817
3294
  decodeResult.formatted.description = "OUT Report";
2818
- decodeResult.formatted.items = [
2819
- {
2820
- type: "origin",
2821
- code: "ORG",
2822
- label: "Origin",
2823
- value: decodeResult.raw.origin
2824
- },
2825
- {
2826
- type: "destination",
2827
- code: "DST",
2828
- label: "Destination",
2829
- value: decodeResult.raw.destination
2830
- },
2831
- {
2832
- type: "gate_out",
2833
- code: "GOUT",
2834
- label: "Gate OUT",
2835
- value: decodeResult.raw.gate_out
2836
- }
2837
- ];
3295
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3296
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3297
+ ResultFormatter.out(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3298
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
2838
3299
  decodeResult.decoded = true;
2839
- if (decodeResult.remaining.text === "")
3300
+ if (!decodeResult.remaining.text)
2840
3301
  decodeResult.decoder.decodeLevel = "full";
2841
3302
  else
2842
3303
  decodeResult.decoder.decodeLevel = "partial";
@@ -2855,33 +3316,13 @@ var Label_QS = class extends DecoderPlugin {
2855
3316
  decode(message, options = {}) {
2856
3317
  const decodeResult = this.defaultResult();
2857
3318
  decodeResult.decoder.name = this.name;
2858
- decodeResult.raw.origin = message.text.substring(0, 4);
2859
- decodeResult.raw.destination = message.text.substring(4, 8);
2860
- decodeResult.raw.gate_in = message.text.substring(8, 12);
2861
- decodeResult.remaining.text = message.text.substring(12);
2862
3319
  decodeResult.formatted.description = "IN Report";
2863
- decodeResult.formatted.items = [
2864
- {
2865
- type: "origin",
2866
- code: "ORG",
2867
- label: "Origin",
2868
- value: decodeResult.raw.origin
2869
- },
2870
- {
2871
- type: "destination",
2872
- code: "DST",
2873
- label: "Destination",
2874
- value: decodeResult.raw.destination
2875
- },
2876
- {
2877
- type: "gate_in",
2878
- code: "GIN",
2879
- label: "Gate IN",
2880
- value: decodeResult.raw.gate_in
2881
- }
2882
- ];
3320
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3321
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3322
+ ResultFormatter.in(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3323
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
2883
3324
  decodeResult.decoded = true;
2884
- if (decodeResult.remaining.text === "")
3325
+ if (!decodeResult.remaining.text)
2885
3326
  decodeResult.decoder.decodeLevel = "full";
2886
3327
  else
2887
3328
  decodeResult.decoder.decodeLevel = "partial";
@@ -2904,46 +3345,33 @@ var Label_QQ = class extends DecoderPlugin {
2904
3345
  decodeResult.formatted.description = "OFF Report";
2905
3346
  ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
2906
3347
  ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
2907
- decodeResult.raw.wheels_off = message.text.substring(8, 12);
2908
3348
  if (message.text.substring(12, 19) === "\r\n001FE") {
2909
3349
  decodeResult.raw.day_of_month = message.text.substring(19, 21);
2910
- decodeResult.raw.wheels_off = message.text.substring(21, 27);
3350
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(21, 27)));
2911
3351
  let latdir = message.text.substring(27, 28);
2912
3352
  let latdeg = Number(message.text.substring(28, 30));
2913
3353
  let latmin = Number(message.text.substring(30, 34));
2914
3354
  let londir = message.text.substring(34, 35);
2915
3355
  let londeg = Number(message.text.substring(35, 38));
2916
3356
  let lonmin = Number(message.text.substring(38, 42));
2917
- decodeResult.raw.position = {
3357
+ let pos = {
2918
3358
  latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
2919
3359
  longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
2920
3360
  };
2921
- decodeResult.remaining.text = message.text.substring(42, 45);
3361
+ ResultFormatter.unknown(decodeResult, message.text.substring(42, 45));
3362
+ ResultFormatter.position(decodeResult, pos);
2922
3363
  if (decodeResult.remaining.text !== "---") {
2923
- ResultFormatter.groundspeed(decodeResult, message.text.substring(45, 48));
3364
+ ResultFormatter.groundspeed(decodeResult, Number(message.text.substring(45, 48)));
2924
3365
  } else {
2925
3366
  ResultFormatter.unknown(decodeResult, message.text.substring(45, 48));
2926
3367
  }
2927
3368
  ResultFormatter.unknown(decodeResult, message.text.substring(48));
2928
3369
  } else {
2929
- decodeResult.remaining.text = message.text.substring(12);
2930
- }
2931
- decodeResult.formatted.items.push({
2932
- type: "wheels_off",
2933
- code: "WOFF",
2934
- label: "Wheels OFF",
2935
- value: decodeResult.raw.wheels_off
2936
- });
2937
- if (decodeResult.raw.position) {
2938
- decodeResult.formatted.items.push({
2939
- type: "aircraft_position",
2940
- code: "POS",
2941
- label: "Aircraft Position",
2942
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
2943
- });
3370
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3371
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
2944
3372
  }
2945
3373
  decodeResult.decoded = true;
2946
- if (decodeResult.remaining.text === "")
3374
+ if (!decodeResult.remaining.text)
2947
3375
  decodeResult.decoder.decodeLevel = "full";
2948
3376
  else
2949
3377
  decodeResult.decoder.decodeLevel = "partial";
@@ -3763,7 +4191,7 @@ var MessageDecoder = class {
3763
4191
  this.plugins = [];
3764
4192
  this.debug = false;
3765
4193
  this.registerPlugin(new Label_ColonComma(this));
3766
- this.registerPlugin(new Label_5Z(this));
4194
+ this.registerPlugin(new Label_5Z_Slash(this));
3767
4195
  this.registerPlugin(new Label_10_LDR(this));
3768
4196
  this.registerPlugin(new Label_10_POS(this));
3769
4197
  this.registerPlugin(new Label_10_Slash(this));
@@ -3772,23 +4200,33 @@ var MessageDecoder = class {
3772
4200
  this.registerPlugin(new Label_15(this));
3773
4201
  this.registerPlugin(new Label_15_FST(this));
3774
4202
  this.registerPlugin(new Label_16_N_Space(this));
4203
+ this.registerPlugin(new Label_1L_3Line(this));
4204
+ this.registerPlugin(new Label_1L_070(this));
4205
+ this.registerPlugin(new Label_1L_660(this));
4206
+ this.registerPlugin(new Label_1L_Slash(this));
3775
4207
  this.registerPlugin(new Label_20_POS(this));
3776
4208
  this.registerPlugin(new Label_21_POS(this));
4209
+ this.registerPlugin(new Label_22_OFF(this));
4210
+ this.registerPlugin(new Label_22_POS(this));
4211
+ this.registerPlugin(new Label_24_Slash(this));
3777
4212
  this.registerPlugin(new Label_30_Slash_EA(this));
3778
4213
  this.registerPlugin(new Label_44_ETA(this));
3779
4214
  this.registerPlugin(new Label_44_IN(this));
3780
4215
  this.registerPlugin(new Label_44_OFF(this));
3781
4216
  this.registerPlugin(new Label_44_ON(this));
3782
4217
  this.registerPlugin(new Label_44_POS(this));
4218
+ this.registerPlugin(new Label_4A(this));
4219
+ this.registerPlugin(new Label_4A_01(this));
4220
+ this.registerPlugin(new Label_4A_DIS(this));
4221
+ this.registerPlugin(new Label_4A_DOOR(this));
4222
+ this.registerPlugin(new Label_4A_Slash_01(this));
3783
4223
  this.registerPlugin(new Label_4N(this));
3784
4224
  this.registerPlugin(new Label_B6_Forwardslash(this));
3785
- this.registerPlugin(new Label_H1_FPN(this));
3786
4225
  this.registerPlugin(new Label_H1_FLR(this));
3787
- this.registerPlugin(new Label_H1_FTX(this));
3788
- this.registerPlugin(new Label_H1_INI(this));
3789
4226
  this.registerPlugin(new Label_H1_OHMA(this));
3790
- this.registerPlugin(new Label_H1_POS(this));
3791
4227
  this.registerPlugin(new Label_H1_WRN(this));
4228
+ this.registerPlugin(new Label_H1(this));
4229
+ this.registerPlugin(new Label_H1_StarPOS(this));
3792
4230
  this.registerPlugin(new Label_HX(this));
3793
4231
  this.registerPlugin(new Label_80(this));
3794
4232
  this.registerPlugin(new Label_83(this));
@@ -3836,29 +4274,30 @@ var MessageDecoder = class {
3836
4274
  console.log("Usable plugins");
3837
4275
  console.log(usablePlugins);
3838
4276
  }
3839
- let result;
3840
- if (usablePlugins.length > 0) {
3841
- const plugin = usablePlugins[0];
4277
+ let result = {
4278
+ decoded: false,
4279
+ error: "No known decoder plugin for this message",
4280
+ decoder: {
4281
+ name: "none",
4282
+ type: "none",
4283
+ decodeLevel: "none"
4284
+ },
4285
+ message,
4286
+ remaining: {
4287
+ text: message.text
4288
+ },
4289
+ raw: {},
4290
+ formatted: {
4291
+ description: "Not Decoded",
4292
+ items: []
4293
+ }
4294
+ };
4295
+ for (let i = 0; i < usablePlugins.length; i++) {
4296
+ const plugin = usablePlugins[i];
3842
4297
  result = plugin.decode(message);
3843
- } else {
3844
- result = {
3845
- decoded: false,
3846
- error: "No known decoder plugin for this message",
3847
- decoder: {
3848
- name: "none",
3849
- type: "none",
3850
- decodeLevel: "none"
3851
- },
3852
- message,
3853
- remaining: {
3854
- text: message.text
3855
- },
3856
- raw: {},
3857
- formatted: {
3858
- description: "Not Decoded",
3859
- items: []
3860
- }
3861
- };
4298
+ if (result.decoded) {
4299
+ break;
4300
+ }
3862
4301
  }
3863
4302
  if (options.debug) {
3864
4303
  console.log("Result");