@airframes/acars-decoder 1.6.9 → 1.6.10

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
@@ -60,6 +60,192 @@ var DecoderPlugin = class {
60
60
  }
61
61
  };
62
62
 
63
+ // lib/utils/coordinate_utils.ts
64
+ var CoordinateUtils = class {
65
+ /**
66
+ * Decode a string of coordinates into an object with latitude and longitude in millidegrees
67
+ * @param stringCoords - The string of coordinates to decode
68
+ *
69
+ * @returns An object with latitude and longitude properties
70
+ */
71
+ static decodeStringCoordinates(stringCoords) {
72
+ var results = {};
73
+ const firstChar = stringCoords.substring(0, 1);
74
+ let middleChar = stringCoords.substring(6, 7);
75
+ let longitudeChars = stringCoords.substring(7, 13);
76
+ if (middleChar == " ") {
77
+ middleChar = stringCoords.substring(7, 8);
78
+ longitudeChars = stringCoords.substring(8, 14);
79
+ }
80
+ 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);
83
+ } else {
84
+ return;
85
+ }
86
+ return results;
87
+ }
88
+ /**
89
+ * Decode a string of coordinates into an object with latitude and longitude in degrees and decimal minutes
90
+ * @param stringCoords - The string of coordinates to decode
91
+ *
92
+ * @returns An object with latitude and longitude properties
93
+ */
94
+ static decodeStringCoordinatesDecimalMinutes(stringCoords) {
95
+ var results = {};
96
+ const firstChar = stringCoords.substring(0, 1);
97
+ let middleChar = stringCoords.substring(6, 7);
98
+ let longitudeChars = stringCoords.substring(7, 13);
99
+ if (middleChar == " ") {
100
+ middleChar = stringCoords.substring(7, 8);
101
+ longitudeChars = stringCoords.substring(8, 14);
102
+ }
103
+ const latDeg = Math.trunc(Number(stringCoords.substring(1, 6)) / 1e3);
104
+ const latMin = Number(stringCoords.substring(1, 6)) % 1e3 / 10;
105
+ const lonDeg = Math.trunc(Number(longitudeChars) / 1e3);
106
+ const lonMin = Number(longitudeChars) % 1e3 / 10;
107
+ 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);
110
+ } else {
111
+ return;
112
+ }
113
+ return results;
114
+ }
115
+ static coordinateString(coords) {
116
+ const latDir = coords.latitude > 0 ? "N" : "S";
117
+ const lonDir = coords.longitude > 0 ? "E" : "W";
118
+ return `${Math.abs(coords.latitude).toFixed(3)} ${latDir}, ${Math.abs(coords.longitude).toFixed(3)} ${lonDir}`;
119
+ }
120
+ };
121
+
122
+ // lib/utils/result_formatter.ts
123
+ var ResultFormatter = class {
124
+ static position(decodeResult, value) {
125
+ decodeResult.raw.position = value;
126
+ decodeResult.formatted.items.push({
127
+ type: "aircraft_position",
128
+ code: "POS",
129
+ label: "Aircraft Position",
130
+ value: CoordinateUtils.coordinateString(value)
131
+ });
132
+ }
133
+ static altitude(decodeResult, value) {
134
+ decodeResult.raw.altitude = value;
135
+ decodeResult.formatted.items.push({
136
+ type: "altitude",
137
+ code: "ALT",
138
+ label: "Altitude",
139
+ value: `${decodeResult.raw.altitude} feet`
140
+ });
141
+ }
142
+ static flightNumber(decodeResult, value) {
143
+ decodeResult.raw.flight_number = value;
144
+ }
145
+ static departureAirport(decodeResult, value) {
146
+ decodeResult.raw.departure_icao = value;
147
+ decodeResult.formatted.items.push({
148
+ type: "origin",
149
+ code: "ORG",
150
+ label: "Origin",
151
+ value: decodeResult.raw.departure_icao
152
+ });
153
+ }
154
+ static departureRunway(decodeResult, value) {
155
+ decodeResult.raw.departure_runway = value;
156
+ decodeResult.formatted.items.push({
157
+ type: "runway",
158
+ code: "DEPRWY",
159
+ label: "Departure Runway",
160
+ value: decodeResult.raw.departure_runway
161
+ });
162
+ }
163
+ static arrivalAirport(decodeResult, value) {
164
+ decodeResult.raw.arrival_icao = value;
165
+ decodeResult.formatted.items.push({
166
+ type: "destination",
167
+ code: "DST",
168
+ label: "Destination",
169
+ value: decodeResult.raw.arrival_icao
170
+ });
171
+ }
172
+ static eta(decodeResult, value) {
173
+ decodeResult.raw.eta_time = value;
174
+ decodeResult.formatted.items.push({
175
+ type: "eta",
176
+ code: "ETA",
177
+ label: "Estimated Time of Arrival",
178
+ value: value.substring(0, 2) + ":" + value.substring(2, 4) + ":" + value.substring(4, 6)
179
+ });
180
+ }
181
+ static arrivalRunway(decodeResult, value) {
182
+ decodeResult.raw.arrival_runway = value;
183
+ decodeResult.formatted.items.push({
184
+ type: "runway",
185
+ code: "ARWY",
186
+ label: "Arrival Runway",
187
+ value: decodeResult.raw.arrival_runway
188
+ });
189
+ }
190
+ static currentFuel(decodeResult, value) {
191
+ decodeResult.raw.fuel_on_board = value;
192
+ decodeResult.formatted.items.push({
193
+ type: "fuel_on_board",
194
+ code: "FOB",
195
+ label: "Fuel On Board",
196
+ value: decodeResult.raw.fuel_on_board.toString()
197
+ });
198
+ }
199
+ static remainingFuel(decodeResult, value) {
200
+ decodeResult.raw.fuel_remaining = value;
201
+ decodeResult.formatted.items.push({
202
+ type: "fuel_remaining",
203
+ code: "FUEL",
204
+ label: "Fuel Remaining",
205
+ value: decodeResult.raw.fuel_remaining.toString()
206
+ });
207
+ }
208
+ static checksum(decodeResult, value) {
209
+ decodeResult.raw.checksum = Number("0x" + value);
210
+ decodeResult.formatted.items.push({
211
+ type: "message_checksum",
212
+ code: "CHECKSUM",
213
+ label: "Message Checksum",
214
+ value: "0x" + ("0000" + decodeResult.raw.checksum.toString(16)).slice(-4)
215
+ });
216
+ }
217
+ static groundspeed(decodeResult, value) {
218
+ decodeResult.raw.groundspeed = value;
219
+ decodeResult.formatted.items.push({
220
+ type: "aircraft_groundspeed",
221
+ code: "GSPD",
222
+ label: "Aircraft Groundspeed",
223
+ value: `${decodeResult.raw.groundspeed}`
224
+ });
225
+ }
226
+ static temperature(decodeResult, value) {
227
+ decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
228
+ decodeResult.formatted.items.push({
229
+ type: "outside_air_temperature",
230
+ code: "OATEMP",
231
+ label: "Outside Air Temperature (C)",
232
+ value: `${decodeResult.raw.outside_air_temperature}`
233
+ });
234
+ }
235
+ static heading(decodeResult, value) {
236
+ decodeResult.raw.heading = value;
237
+ decodeResult.formatted.items.push({
238
+ type: "heading",
239
+ code: "HDG",
240
+ label: "Heading",
241
+ value: `${decodeResult.raw.heading}`
242
+ });
243
+ }
244
+ static unknown(decodeResult, value) {
245
+ decodeResult.remaining.text += "," + value;
246
+ }
247
+ };
248
+
63
249
  // lib/plugins/Label_5Z.ts
64
250
  var Label_5Z = class extends DecoderPlugin {
65
251
  name = "label-5z";
@@ -90,141 +276,327 @@ var Label_5Z = class extends DecoderPlugin {
90
276
  };
91
277
  qualifiers() {
92
278
  return {
93
- labels: ["5Z"]
279
+ labels: ["5Z"]
280
+ };
281
+ }
282
+ decode(message, options = {}) {
283
+ const decodeResult = this.defaultResult();
284
+ decodeResult.decoder.name = this.name;
285
+ decodeResult.formatted.description = "Airline Designated Downlink";
286
+ const uaRegex = /^\/(?<type>\w+) (?<remainder>.+)/;
287
+ let results = message.text.match(uaRegex);
288
+ if (results && results.length >= 2) {
289
+ const type = results.groups.type.split("/")[0];
290
+ const { remainder } = results.groups;
291
+ const typeDescription = this.descriptions[type] ? this.descriptions[type] : "Unknown";
292
+ decodeResult.raw.airline = "United Airlines";
293
+ decodeResult.formatted.items.push({
294
+ type: "airline",
295
+ label: "Airline",
296
+ value: "United Airlines"
297
+ });
298
+ decodeResult.raw.message_type = type;
299
+ decodeResult.formatted.items.push({
300
+ type: "message_type",
301
+ label: "Message Type",
302
+ value: `${typeDescription} (${type})`
303
+ });
304
+ if (type === "B3") {
305
+ const rdcRegex = /^(?<from>\w\w\w)(?<to>\w\w\w) (?<unknown1>\d\d) R(?<runway>.+) G(?<unknown2>.+)$/;
306
+ results = remainder.match(rdcRegex);
307
+ if (results) {
308
+ ResultFormatter.departureAirport(decodeResult, results.groups.from);
309
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.to);
310
+ ResultFormatter.arrivalRunway(decodeResult, results.groups.runway);
311
+ } else {
312
+ if (options.debug) {
313
+ console.log(`Decoder: Unkown 5Z RDC format: ${remainder}`);
314
+ }
315
+ }
316
+ } else {
317
+ decodeResult.remaining.text = remainder;
318
+ }
319
+ decodeResult.decoded = true;
320
+ decodeResult.decoder.decodeLevel = "partial";
321
+ } else {
322
+ if (options.debug) {
323
+ console.log(`Decoder: Unknown 5Z message: ${message.text}`);
324
+ }
325
+ decodeResult.remaining.text = message.text;
326
+ decodeResult.decoded = false;
327
+ decodeResult.decoder.decodeLevel = "none";
328
+ }
329
+ return decodeResult;
330
+ }
331
+ };
332
+
333
+ // lib/plugins/Label_10_LDR.ts
334
+ var Label_10_LDR = class extends DecoderPlugin {
335
+ // eslint-disable-line camelcase
336
+ name = "label-10-ldr";
337
+ qualifiers() {
338
+ return {
339
+ labels: ["10"],
340
+ preambles: ["LDR"]
341
+ };
342
+ }
343
+ decode(message, options = {}) {
344
+ const decodeResult = this.defaultResult();
345
+ decodeResult.decoder.name = this.name;
346
+ decodeResult.formatted.description = "Position Report";
347
+ decodeResult.message = message;
348
+ const parts = message.text.split(",");
349
+ if (parts.length < 17) {
350
+ if (options?.debug) {
351
+ console.log(`Decoder: Unknown 10 message: ${message.text}`);
352
+ }
353
+ decodeResult.remaining.text = message.text;
354
+ decodeResult.decoded = false;
355
+ decodeResult.decoder.decodeLevel = "none";
356
+ return decodeResult;
357
+ }
358
+ const lat = parts[5];
359
+ const lon = parts[6];
360
+ const position = {
361
+ latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1).trim()),
362
+ longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1).trim())
363
+ };
364
+ ResultFormatter.position(decodeResult, position);
365
+ ResultFormatter.altitude(decodeResult, Number(parts[7]));
366
+ ResultFormatter.departureAirport(decodeResult, parts[9]);
367
+ ResultFormatter.arrivalAirport(decodeResult, parts[10]);
368
+ ResultFormatter.arrivalRunway(decodeResult, parts[12].split("/")[0]);
369
+ decodeResult.remaining.text = [...parts.slice(0, 5), parts[11], ...parts.slice(13)].join(",");
370
+ decodeResult.decoded = true;
371
+ decodeResult.decoder.decodeLevel = "partial";
372
+ return decodeResult;
373
+ }
374
+ };
375
+
376
+ // lib/plugins/Label_10_POS.ts
377
+ var Label_10_POS = class extends DecoderPlugin {
378
+ // eslint-disable-line camelcase
379
+ name = "label-10-pos";
380
+ qualifiers() {
381
+ return {
382
+ labels: ["10"],
383
+ preambles: ["POS"]
384
+ };
385
+ }
386
+ decode(message, options = {}) {
387
+ const decodeResult = this.defaultResult();
388
+ decodeResult.decoder.name = this.name;
389
+ decodeResult.formatted.description = "Position Report";
390
+ decodeResult.message = message;
391
+ const parts = message.text.split(",");
392
+ if (parts.length !== 12) {
393
+ if (options?.debug) {
394
+ console.log(`Decoder: Unknown 10 message: ${message.text}`);
395
+ }
396
+ decodeResult.remaining.text = message.text;
397
+ decodeResult.decoded = false;
398
+ decodeResult.decoder.decodeLevel = "none";
399
+ return decodeResult;
400
+ }
401
+ const lat = parts[1].trim();
402
+ const lon = parts[2].trim();
403
+ const position = {
404
+ latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1).trim()) / 100,
405
+ longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1).trim()) / 100
406
+ };
407
+ ResultFormatter.position(decodeResult, position);
408
+ ResultFormatter.altitude(decodeResult, Number(parts[7]));
409
+ decodeResult.remaining.text = [parts[0], ...parts.slice(3, 7), ...parts.slice(8)].join(",");
410
+ decodeResult.decoded = true;
411
+ decodeResult.decoder.decodeLevel = "partial";
412
+ return decodeResult;
413
+ }
414
+ };
415
+
416
+ // lib/DateTimeUtils.ts
417
+ var DateTimeUtils = class {
418
+ // Expects a four digit UTC time string (HHMM)
419
+ static UTCToString(UTCString) {
420
+ let utcDate = /* @__PURE__ */ new Date();
421
+ utcDate.setUTCHours(+UTCString.substr(0, 2), +UTCString.substr(2, 2), 0);
422
+ return utcDate.toTimeString();
423
+ }
424
+ // Expects a six digit date string and a four digit UTC time string
425
+ // (DDMMYY) (HHMM)
426
+ static UTCDateTimeToString(dateString, timeString) {
427
+ let utcDate = /* @__PURE__ */ new Date();
428
+ utcDate.setUTCDate(+dateString.substr(0, 2));
429
+ utcDate.setUTCMonth(+dateString.substr(2, 2));
430
+ if (dateString.length === 6) {
431
+ utcDate.setUTCFullYear(2e3 + +dateString.substr(4, 2));
432
+ }
433
+ if (timeString.length === 6) {
434
+ utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), +timeString.substr(4, 2));
435
+ } else {
436
+ utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), 0);
437
+ }
438
+ return utcDate.toUTCString();
439
+ }
440
+ /**
441
+ *
442
+ * @param time HHMMSS
443
+ * @returns seconds since midnight
444
+ */
445
+ static convertHHMMSSToTod(time) {
446
+ const h = Number(time.substring(0, 2));
447
+ const m = Number(time.substring(2, 4));
448
+ const s = Number(time.substring(4, 6));
449
+ const tod = h * 3600 + m * 60 + s;
450
+ return tod;
451
+ }
452
+ /**
453
+ *
454
+ * @param time HHMMSS
455
+ * @param date MMDDYY or MMDDYYYY
456
+ * @returns seconds since epoch
457
+ */
458
+ static convertDateTimeToEpoch(time, date) {
459
+ if (date.length === 6) {
460
+ date = date.substring(0, 4) + `20${date.substring(4, 6)}`;
461
+ }
462
+ const timestamp = `${date.substring(4, 8)}-${date.substring(0, 2)}-${date.substring(2, 4)}T${time.substring(0, 2)}:${time.substring(2, 4)}:${time.substring(4, 6)}.000Z`;
463
+ const millis = Date.parse(timestamp);
464
+ return millis / 1e3;
465
+ }
466
+ };
467
+
468
+ // lib/utils/route_utils.ts
469
+ var RouteUtils = class _RouteUtils {
470
+ static routeToString(route) {
471
+ let str = "";
472
+ if (route.name) {
473
+ str += route.name;
474
+ }
475
+ if (route.runway) {
476
+ str += `(${route.runway})`;
477
+ }
478
+ if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
479
+ str += " starting at ";
480
+ } else if (str.length !== 0 && route.waypoints) {
481
+ str += ": ";
482
+ }
483
+ if (route.waypoints) {
484
+ str += _RouteUtils.waypointsToString(route.waypoints);
485
+ }
486
+ return str;
487
+ }
488
+ static waypointToString(waypoint) {
489
+ let s = waypoint.name;
490
+ if (waypoint.latitude && waypoint.longitude) {
491
+ s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
492
+ }
493
+ if (waypoint.offset) {
494
+ s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
495
+ }
496
+ if (waypoint.time && waypoint.timeFormat) {
497
+ s += `@${_RouteUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
498
+ }
499
+ return s;
500
+ }
501
+ static getWaypoint(leg) {
502
+ const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
503
+ if (regex?.length == 4) {
504
+ return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
505
+ }
506
+ const waypoint = leg.split(",");
507
+ if (waypoint.length == 2) {
508
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
509
+ if (position) {
510
+ return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
511
+ }
512
+ }
513
+ if (leg.length == 13 || leg.length == 14) {
514
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
515
+ const name = waypoint.length == 2 ? waypoint[0] : "";
516
+ if (position) {
517
+ return { name, latitude: position.latitude, longitude: position.longitude };
518
+ }
519
+ }
520
+ return { name: leg };
521
+ }
522
+ // move out if we want public
523
+ static timestampToString(time, format) {
524
+ const date = new Date(time * 1e3);
525
+ if (format == "tod") {
526
+ return date.toISOString().slice(11, 19);
527
+ }
528
+ return date.toISOString().slice(0, -5) + "Z";
529
+ }
530
+ static waypointsToString(waypoints) {
531
+ let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
532
+ if (str.startsWith(" > ")) {
533
+ str = ">>" + str.slice(2);
534
+ }
535
+ return str;
536
+ }
537
+ };
538
+
539
+ // lib/plugins/Label_10_Slash.ts
540
+ var Label_10_Slash = class extends DecoderPlugin {
541
+ // eslint-disable-line camelcase
542
+ name = "label-10-slash";
543
+ qualifiers() {
544
+ return {
545
+ labels: ["10"],
546
+ preambles: ["/"]
94
547
  };
95
548
  }
96
549
  decode(message, options = {}) {
97
550
  const decodeResult = this.defaultResult();
98
551
  decodeResult.decoder.name = this.name;
99
- decodeResult.formatted.description = "Airline Designated Downlink";
100
- const uaRegex = /^\/(?<type>\w+) (?<remainder>.+)/;
101
- let results = message.text.match(uaRegex);
102
- if (results && results.length >= 2) {
103
- const type = results.groups.type.split("/")[0];
104
- const { remainder } = results.groups;
105
- const typeDescription = this.descriptions[type] ? this.descriptions[type] : "Unknown";
106
- decodeResult.raw.airline = "United Airlines";
107
- decodeResult.formatted.items.push({
108
- type: "airline",
109
- label: "Airline",
110
- value: "United Airlines"
111
- });
112
- decodeResult.raw.message_type = type;
113
- decodeResult.formatted.items.push({
114
- type: "message_type",
115
- label: "Message Type",
116
- value: `${typeDescription} (${type})`
117
- });
118
- if (type === "B3") {
119
- const rdcRegex = /^(?<from>\w\w\w)(?<to>\w\w\w) (?<unknown1>\d\d) R(?<runway>.+) G(?<unknown2>.+)$/;
120
- results = remainder.match(rdcRegex);
121
- if (results) {
122
- decodeResult.raw.origin = results.groups.from;
123
- decodeResult.formatted.items.push({
124
- type: "origin",
125
- label: "Origin",
126
- value: `${results.groups.from}`
127
- });
128
- decodeResult.raw.destination = results.groups.to;
129
- decodeResult.formatted.items.push({
130
- type: "destination",
131
- label: "Destination",
132
- value: `${results.groups.to}`
133
- });
134
- decodeResult.formatted.items.push({
135
- type: "unknown1",
136
- label: "Unknown Field 1",
137
- value: `${results.groups.unknown1}`
138
- });
139
- decodeResult.raw.runway = results.groups.runway;
140
- decodeResult.formatted.items.push({
141
- type: "runway",
142
- label: "Runway",
143
- value: `${results.groups.runway}`
144
- });
145
- decodeResult.formatted.items.push({
146
- type: "unknown2",
147
- label: "Unknown Field 2",
148
- value: `${results.groups.unknown2}`
149
- });
150
- } else {
151
- if (options.debug) {
152
- console.log(`Decoder: Unkown 5Z RDC format: ${remainder}`);
153
- }
154
- }
155
- } else {
156
- decodeResult.remaining.text = remainder;
157
- }
158
- decodeResult.decoded = true;
159
- decodeResult.decoder.decodeLevel = "partial";
160
- } else {
161
- if (options.debug) {
162
- console.log(`Decoder: Unknown 5Z message: ${message.text}`);
552
+ decodeResult.formatted.description = "Position Report";
553
+ decodeResult.message = message;
554
+ const parts = message.text.split("/");
555
+ if (parts.length < 17) {
556
+ if (options?.debug) {
557
+ console.log(`Decoder: Unknown 10 message: ${message.text}`);
163
558
  }
164
559
  decodeResult.remaining.text = message.text;
165
560
  decodeResult.decoded = false;
166
561
  decodeResult.decoder.decodeLevel = "none";
562
+ return decodeResult;
167
563
  }
168
- return decodeResult;
169
- }
170
- };
171
-
172
- // lib/utils/coordinate_utils.ts
173
- var CoordinateUtils = class {
174
- /**
175
- * Decode a string of coordinates into an object with latitude and longitude in millidegrees
176
- * @param stringCoords - The string of coordinates to decode
177
- *
178
- * @returns An object with latitude and longitude properties
179
- */
180
- static decodeStringCoordinates(stringCoords) {
181
- var results = {};
182
- const firstChar = stringCoords.substring(0, 1);
183
- let middleChar = stringCoords.substring(6, 7);
184
- let longitudeChars = stringCoords.substring(7, 13);
185
- if (middleChar == " ") {
186
- middleChar = stringCoords.substring(7, 8);
187
- longitudeChars = stringCoords.substring(8, 14);
188
- }
189
- if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
190
- results.latitude = Number(stringCoords.substring(1, 6)) / 1e3 * (firstChar === "S" ? -1 : 1);
191
- results.longitude = Number(longitudeChars) / 1e3 * (middleChar === "W" ? -1 : 1);
192
- } else {
193
- return;
194
- }
195
- return results;
196
- }
197
- /**
198
- * Decode a string of coordinates into an object with latitude and longitude in degrees and decimal minutes
199
- * @param stringCoords - The string of coordinates to decode
200
- *
201
- * @returns An object with latitude and longitude properties
202
- */
203
- static decodeStringCoordinatesDecimalMinutes(stringCoords) {
204
- var results = {};
205
- const firstChar = stringCoords.substring(0, 1);
206
- let middleChar = stringCoords.substring(6, 7);
207
- let longitudeChars = stringCoords.substring(7, 13);
208
- if (middleChar == " ") {
209
- middleChar = stringCoords.substring(7, 8);
210
- longitudeChars = stringCoords.substring(8, 14);
211
- }
212
- const latDeg = Math.trunc(Number(stringCoords.substring(1, 6)) / 1e3);
213
- const latMin = Number(stringCoords.substring(1, 6)) % 1e3 / 10;
214
- const lonDeg = Math.trunc(Number(longitudeChars) / 1e3);
215
- const lonMin = Number(longitudeChars) % 1e3 / 10;
216
- if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
217
- results.latitude = (latDeg + latMin / 60) * (firstChar === "S" ? -1 : 1);
218
- results.longitude = (lonDeg + lonMin / 60) * (middleChar === "W" ? -1 : 1);
219
- } else {
220
- return;
564
+ const lat = parts[1];
565
+ const lon = parts[2];
566
+ const position = {
567
+ latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1)),
568
+ longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1))
569
+ };
570
+ ResultFormatter.position(decodeResult, position);
571
+ ResultFormatter.heading(decodeResult, Number(parts[5]));
572
+ ResultFormatter.altitude(decodeResult, 100 * Number(parts[6]));
573
+ ResultFormatter.arrivalAirport(decodeResult, parts[7]);
574
+ ResultFormatter.eta(decodeResult, parts[8] + "00");
575
+ const waypoints = [{
576
+ name: parts[11]
577
+ }, {
578
+ name: parts[12],
579
+ time: DateTimeUtils.convertHHMMSSToTod(parts[13] + "00"),
580
+ timeFormat: "tod"
581
+ }, {
582
+ name: parts[14],
583
+ time: DateTimeUtils.convertHHMMSSToTod(parts[15] + "00"),
584
+ timeFormat: "tod"
585
+ }];
586
+ decodeResult.raw.route = { waypoints };
587
+ decodeResult.formatted.items.push({
588
+ type: "aircraft_route",
589
+ code: "ROUTE",
590
+ label: "Aircraft Route",
591
+ value: RouteUtils.routeToString(decodeResult.raw.route)
592
+ });
593
+ if (parts[16]) {
594
+ ResultFormatter.departureAirport(decodeResult, parts[16]);
221
595
  }
222
- return results;
223
- }
224
- static coordinateString(coords) {
225
- const latDir = coords.latitude > 0 ? "N" : "S";
226
- const lonDir = coords.longitude > 0 ? "E" : "W";
227
- return `${Math.abs(coords.latitude).toFixed(3)} ${latDir}, ${Math.abs(coords.longitude).toFixed(3)} ${lonDir}`;
596
+ decodeResult.remaining.text = [parts[3], parts[4], ...parts.slice(9, 11), ...parts.slice(17)].join("/");
597
+ decodeResult.decoded = true;
598
+ decodeResult.decoder.decodeLevel = "partial";
599
+ return decodeResult;
228
600
  }
229
601
  };
230
602
 
@@ -253,19 +625,14 @@ var Label_12_N_Space = class extends DecoderPlugin {
253
625
  latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
254
626
  longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
255
627
  };
256
- decodeResult.raw.flight_level = results.groups.alt == "GRD" || results.groups.alt == "***" ? "0" : Number(results.groups.alt);
628
+ const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
257
629
  decodeResult.formatted.items.push({
258
630
  type: "aircraft_position",
259
631
  code: "POS",
260
632
  label: "Aircraft Position",
261
633
  value: CoordinateUtils.coordinateString(decodeResult.raw.position)
262
634
  });
263
- decodeResult.formatted.items.push({
264
- type: "flight_level",
265
- code: "FL",
266
- label: "Flight Level",
267
- value: decodeResult.raw.flight_level
268
- });
635
+ ResultFormatter.altitude(decodeResult, altitude);
269
636
  decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}, ${results.groups.unkwn3}`;
270
637
  decodeResult.decoded = true;
271
638
  decodeResult.decoder.decodeLevel = "partial";
@@ -327,39 +694,35 @@ var Label_15_FST = class extends DecoderPlugin {
327
694
  decodeResult.decoder.name = this.name;
328
695
  decodeResult.formatted.description = "Position Report";
329
696
  decodeResult.message = message;
330
- decodeResult.raw.departure_icao = message.text.substring(5, 9);
331
- decodeResult.raw.arrival_icao = message.text.substring(9, 13);
332
- const stringCoords = message.text.substring(13);
697
+ const parts = message.text.split(" ");
698
+ const header = parts[0];
699
+ decodeResult.raw.departure_icao = header.substring(5, 9);
700
+ decodeResult.raw.arrival_icao = header.substring(9, 13);
701
+ const stringCoords = header.substring(13);
333
702
  const firstChar = stringCoords.substring(0, 1);
334
703
  const middleChar = stringCoords.substring(7, 8);
335
704
  decodeResult.raw.position = {};
336
705
  if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
337
706
  decodeResult.raw.position.latitude = Number(stringCoords.substring(1, 7)) / 1e4 * (firstChar === "S" ? -1 : 1);
338
- decodeResult.raw.position.longitude = Number(stringCoords.substring(8, 26)) / 1e5 * (middleChar === "W" ? -1 : 1);
707
+ decodeResult.raw.position.longitude = Number(stringCoords.substring(8, 15)) / 1e4 * (middleChar === "W" ? -1 : 1);
708
+ decodeResult.raw.altitude = Number(stringCoords.substring(15)) * 100;
339
709
  } else {
340
710
  decodeResult.decoded = false;
341
711
  decodeResult.decoder.decodeLevel = "none";
342
712
  return decodeResult;
343
713
  }
344
714
  decodeResult.formatted.items.push({
345
- type: "position",
346
- label: "Position",
715
+ type: "aircraft_position",
716
+ code: "POS",
717
+ label: "Aircraft Position",
347
718
  value: CoordinateUtils.coordinateString(decodeResult.raw.position)
348
719
  });
349
- decodeResult.formatted.items.push({
350
- type: "origin",
351
- code: "ORG",
352
- label: "Origin",
353
- value: decodeResult.raw.departure_icao
354
- });
355
- decodeResult.formatted.items.push({
356
- type: "destination",
357
- code: "DST",
358
- label: "Destination",
359
- value: decodeResult.raw.arrival_icao
360
- });
720
+ ResultFormatter.altitude(decodeResult, decodeResult.raw.altitude);
721
+ ResultFormatter.departureAirport(decodeResult, decodeResult.raw.departure_icao);
722
+ ResultFormatter.arrivalAirport(decodeResult, decodeResult.raw.arrival_icao);
723
+ decodeResult.remaining.text = parts.slice(1).join(" ");
361
724
  decodeResult.decoded = true;
362
- decodeResult.decoder.decodeLevel = "full";
725
+ decodeResult.decoder.decodeLevel = "partial";
363
726
  return decodeResult;
364
727
  }
365
728
  };
@@ -390,19 +753,14 @@ var Label_16_N_Space = class extends DecoderPlugin {
390
753
  latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
391
754
  longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
392
755
  };
393
- decodeResult.raw.flight_level = results.groups.alt == "GRD" || results.groups.alt == "***" ? "0" : Number(results.groups.alt);
756
+ const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
394
757
  decodeResult.formatted.items.push({
395
758
  type: "aircraft_position",
396
759
  code: "POS",
397
760
  label: "Aircraft Position",
398
761
  value: CoordinateUtils.coordinateString(decodeResult.raw.position)
399
762
  });
400
- decodeResult.formatted.items.push({
401
- type: "flight_level",
402
- code: "FL",
403
- label: "Flight Level",
404
- value: decodeResult.raw.flight_level
405
- });
763
+ ResultFormatter.altitude(decodeResult, altitude);
406
764
  decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}`;
407
765
  decodeResult.decoded = true;
408
766
  decodeResult.decoder.decodeLevel = "partial";
@@ -435,58 +793,6 @@ var Label_16_N_Space = class extends DecoderPlugin {
435
793
  }
436
794
  };
437
795
 
438
- // lib/DateTimeUtils.ts
439
- var DateTimeUtils = class {
440
- // Expects a four digit UTC time string (HHMM)
441
- static UTCToString(UTCString) {
442
- let utcDate = /* @__PURE__ */ new Date();
443
- utcDate.setUTCHours(+UTCString.substr(0, 2), +UTCString.substr(2, 2), 0);
444
- return utcDate.toTimeString();
445
- }
446
- // Expects a six digit date string and a four digit UTC time string
447
- // (DDMMYY) (HHMM)
448
- static UTCDateTimeToString(dateString, timeString) {
449
- let utcDate = /* @__PURE__ */ new Date();
450
- utcDate.setUTCDate(+dateString.substr(0, 2));
451
- utcDate.setUTCMonth(+dateString.substr(2, 2));
452
- if (dateString.length === 6) {
453
- utcDate.setUTCFullYear(2e3 + +dateString.substr(4, 2));
454
- }
455
- if (timeString.length === 6) {
456
- utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), +timeString.substr(4, 2));
457
- } else {
458
- utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), 0);
459
- }
460
- return utcDate.toUTCString();
461
- }
462
- /**
463
- *
464
- * @param time HHMMSS
465
- * @returns seconds since midnight
466
- */
467
- static convertHHMMSSToTod(time) {
468
- const h = Number(time.substring(0, 2));
469
- const m = Number(time.substring(2, 4));
470
- const s = Number(time.substring(4, 6));
471
- const tod = h * 3600 + m * 60 + s;
472
- return tod;
473
- }
474
- /**
475
- *
476
- * @param time HHMMSS
477
- * @param date MMDDYY or MMDDYYYY
478
- * @returns seconds since epoch
479
- */
480
- static convertDateTimeToEpoch(time, date) {
481
- if (date.length === 6) {
482
- date = date.substring(0, 4) + `20${date.substring(4, 6)}`;
483
- }
484
- 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`;
485
- const millis = Date.parse(timestamp);
486
- return millis / 1e3;
487
- }
488
- };
489
-
490
796
  // lib/plugins/Label_1M_Slash.ts
491
797
  var Label_1M_Slash = class extends DecoderPlugin {
492
798
  name = "label-1m-slash";
@@ -563,6 +869,7 @@ var Label_20_POS = class extends DecoderPlugin {
563
869
  if (decodeResult.raw.position) {
564
870
  decodeResult.formatted.items.push({
565
871
  type: "position",
872
+ code: "POS",
566
873
  label: "Position",
567
874
  value: CoordinateUtils.coordinateString(decodeResult.raw.position)
568
875
  });
@@ -576,6 +883,7 @@ var Label_20_POS = class extends DecoderPlugin {
576
883
  if (decodeResult.raw.position) {
577
884
  decodeResult.formatted.items.push({
578
885
  type: "position",
886
+ code: "POS",
579
887
  label: "Position",
580
888
  value: CoordinateUtils.coordinateString(decodeResult.raw.position)
581
889
  });
@@ -615,7 +923,7 @@ var Label_21_POS = class extends DecoderPlugin {
615
923
  processAlt(decodeResult, fields[3]);
616
924
  processTemp(decodeResult, fields[6]);
617
925
  processArrvApt(decodeResult, fields[8]);
618
- decodeResult.raw.remaining = [
926
+ decodeResult.remaining.text = [
619
927
  fields[1],
620
928
  fields[2],
621
929
  fields[4],
@@ -979,44 +1287,27 @@ var Label_44_POS = class extends DecoderPlugin {
979
1287
  console.log(results.groups);
980
1288
  }
981
1289
  decodeResult.raw.position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(results.groups.unsplit_coords);
982
- decodeResult.raw.flight_level = results.groups.flight_level_or_ground == "GRD" || results.groups.flight_level_or_ground == "***" ? "0" : Number(results.groups.flight_level_or_ground);
983
- decodeResult.raw.departure_icao = results.groups.departure_icao;
984
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1290
+ const flight_level = results.groups.flight_level_or_ground == "GRD" || results.groups.flight_level_or_ground == "***" ? 0 : Number(results.groups.flight_level_or_ground);
985
1291
  decodeResult.raw.current_time = Date.parse(
986
1292
  (/* @__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"
987
1293
  );
988
1294
  decodeResult.raw.eta_time = Date.parse(
989
- (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.eta_time.substr(0, 2) + ":" + results.groups.eta_time.substr(2, 2) + ":00Z"
990
- );
991
- if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
992
- decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
993
- }
994
- if (decodeResult.raw.position) {
995
- decodeResult.formatted.items.push({
996
- type: "aircraft_position",
997
- code: "POS",
998
- label: "Aircraft Position",
999
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1000
- });
1001
- }
1002
- decodeResult.formatted.items.push({
1003
- type: "origin",
1004
- code: "ORG",
1005
- label: "Origin",
1006
- value: decodeResult.raw.departure_icao
1007
- });
1008
- decodeResult.formatted.items.push({
1009
- type: "destination",
1010
- code: "DST",
1011
- label: "Destination",
1012
- value: decodeResult.raw.arrival_icao
1013
- });
1014
- decodeResult.formatted.items.push({
1015
- type: "flight_level",
1016
- code: "FL",
1017
- label: "Flight Level",
1018
- value: decodeResult.raw.flight_level
1019
- });
1295
+ (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.eta_time.substr(0, 2) + ":" + results.groups.eta_time.substr(2, 2) + ":00Z"
1296
+ );
1297
+ if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1298
+ decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1299
+ }
1300
+ if (decodeResult.raw.position) {
1301
+ decodeResult.formatted.items.push({
1302
+ type: "aircraft_position",
1303
+ code: "POS",
1304
+ label: "Aircraft Position",
1305
+ value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1306
+ });
1307
+ }
1308
+ ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1309
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1310
+ ResultFormatter.altitude(decodeResult, flight_level * 100);
1020
1311
  }
1021
1312
  decodeResult.decoded = true;
1022
1313
  decodeResult.decoder.decodeLevel = "full";
@@ -1119,13 +1410,9 @@ var Label_80 = class extends DecoderPlugin {
1119
1410
  break;
1120
1411
  }
1121
1412
  case "FL": {
1122
- decodeResult.raw.flight_level = match.groups.value;
1123
- decodeResult.formatted.items.push({
1124
- type: "flight_level",
1125
- code: "FL",
1126
- label: this.descriptions[match.groups.field],
1127
- value: decodeResult.raw.flight_level
1128
- });
1413
+ const flight_level = match.groups.value;
1414
+ decodeResult.raw.altitude = flight_level * 100;
1415
+ ResultFormatter.altitude(decodeResult, decodeResult.raw.altitude);
1129
1416
  break;
1130
1417
  }
1131
1418
  case "FOB": {
@@ -1359,183 +1646,6 @@ function processUnknown(decodeResult, value) {
1359
1646
  decodeResult.remaining.text += value;
1360
1647
  }
1361
1648
 
1362
- // lib/utils/result_formatter.ts
1363
- var ResultFormatter = class {
1364
- static altitude(decodeResult, value) {
1365
- decodeResult.raw.altitude = value;
1366
- decodeResult.formatted.items.push({
1367
- type: "altitude",
1368
- code: "ALT",
1369
- label: "Altitude",
1370
- value: `${decodeResult.raw.altitude} feet`
1371
- });
1372
- }
1373
- static flightNumber(decodeResult, value) {
1374
- decodeResult.raw.flight_number = value;
1375
- }
1376
- static departureAirport(decodeResult, value) {
1377
- decodeResult.raw.departure_icao = value;
1378
- decodeResult.formatted.items.push({
1379
- type: "origin",
1380
- code: "ORG",
1381
- label: "Origin",
1382
- value: decodeResult.raw.departure_icao
1383
- });
1384
- }
1385
- static departureRunway(decodeResult, value) {
1386
- decodeResult.raw.departure_runway = value;
1387
- decodeResult.formatted.items.push({
1388
- type: "runway",
1389
- code: "DEPRWY",
1390
- label: "Departure Runway",
1391
- value: decodeResult.raw.departure_runway
1392
- });
1393
- }
1394
- static arrivalAirport(decodeResult, value) {
1395
- decodeResult.raw.arrival_icao = value;
1396
- decodeResult.formatted.items.push({
1397
- type: "destination",
1398
- code: "DST",
1399
- label: "Destination",
1400
- value: decodeResult.raw.arrival_icao
1401
- });
1402
- }
1403
- static eta(decodeResult, value) {
1404
- decodeResult.formatted.items.push({
1405
- type: "eta",
1406
- code: "ETA",
1407
- label: "Estimated Time of Arrival",
1408
- value: value.substring(0, 2) + ":" + value.substring(2, 4) + ":" + value.substring(4, 6)
1409
- });
1410
- }
1411
- static arrivalRunway(decodeResult, value) {
1412
- decodeResult.raw.arrival_runway = value;
1413
- decodeResult.formatted.items.push({
1414
- type: "runway",
1415
- label: "Arrival Runway",
1416
- value: decodeResult.raw.arrival_runway
1417
- });
1418
- }
1419
- static currentFuel(decodeResult, value) {
1420
- decodeResult.raw.fuel_on_board = value;
1421
- decodeResult.formatted.items.push({
1422
- type: "fuel_on_board",
1423
- code: "FOB",
1424
- label: "Fuel On Board",
1425
- value: decodeResult.raw.fuel_on_board.toString()
1426
- });
1427
- }
1428
- static remainingFuel(decodeResult, value) {
1429
- decodeResult.raw.fuel_remaining = value;
1430
- decodeResult.formatted.items.push({
1431
- type: "fuel_remaining",
1432
- label: "Fuel Remaining",
1433
- value: decodeResult.raw.fuel_remaining.toString()
1434
- });
1435
- }
1436
- static checksum(decodeResult, value) {
1437
- decodeResult.raw.checksum = Number("0x" + value);
1438
- decodeResult.formatted.items.push({
1439
- type: "message_checksum",
1440
- code: "CHECKSUM",
1441
- label: "Message Checksum",
1442
- value: "0x" + ("0000" + decodeResult.raw.checksum.toString(16)).slice(-4)
1443
- });
1444
- }
1445
- static groundspeed(decodeResult, value) {
1446
- decodeResult.raw.groundspeed = value;
1447
- decodeResult.formatted.items.push({
1448
- type: "aircraft_groundspeed",
1449
- code: "GSPD",
1450
- label: "Aircraft Groundspeed",
1451
- value: `${decodeResult.raw.groundspeed}`
1452
- });
1453
- }
1454
- static temperature(decodeResult, value) {
1455
- decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
1456
- decodeResult.formatted.items.push({
1457
- type: "outside_air_temperature",
1458
- code: "OATEMP",
1459
- label: "Outside Air Temperature (C)",
1460
- value: `${decodeResult.raw.outside_air_temperature}`
1461
- });
1462
- }
1463
- static unknown(decodeResult, value) {
1464
- decodeResult.remaining.text += "," + value;
1465
- }
1466
- };
1467
-
1468
- // lib/utils/route_utils.ts
1469
- var RouteUtils = class _RouteUtils {
1470
- static routeToString(route) {
1471
- let str = "";
1472
- if (route.name) {
1473
- str += route.name;
1474
- }
1475
- if (route.runway) {
1476
- str += `(${route.runway})`;
1477
- }
1478
- if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
1479
- str += " starting at ";
1480
- } else if (str.length !== 0 && route.waypoints) {
1481
- str += ": ";
1482
- }
1483
- if (route.waypoints) {
1484
- str += _RouteUtils.waypointsToString(route.waypoints);
1485
- }
1486
- return str;
1487
- }
1488
- static waypointToString(waypoint) {
1489
- let s = waypoint.name;
1490
- if (waypoint.latitude && waypoint.longitude) {
1491
- s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
1492
- }
1493
- if (waypoint.offset) {
1494
- s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
1495
- }
1496
- if (waypoint.time && waypoint.timeFormat) {
1497
- s += `@${_RouteUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
1498
- }
1499
- return s;
1500
- }
1501
- static getWaypoint(leg) {
1502
- const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
1503
- if (regex?.length == 4) {
1504
- return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
1505
- }
1506
- const waypoint = leg.split(",");
1507
- if (waypoint.length == 2) {
1508
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
1509
- if (position) {
1510
- return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
1511
- }
1512
- }
1513
- if (leg.length == 13 || leg.length == 14) {
1514
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
1515
- const name = waypoint.length == 2 ? waypoint[0] : "";
1516
- if (position) {
1517
- return { name, latitude: position.latitude, longitude: position.longitude };
1518
- }
1519
- }
1520
- return { name: leg };
1521
- }
1522
- // move out if we want public
1523
- static timestampToString(time, format) {
1524
- const date = new Date(time * 1e3);
1525
- if (format == "tod") {
1526
- return date.toISOString().slice(11, 19);
1527
- }
1528
- return date.toISOString().slice(0, -5) + "Z";
1529
- }
1530
- static waypointsToString(waypoints) {
1531
- let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
1532
- if (str.startsWith(" > ")) {
1533
- str = ">>" + str.slice(2);
1534
- }
1535
- return str;
1536
- }
1537
- };
1538
-
1539
1649
  // lib/utils/flight_plan_utils.ts
1540
1650
  var FlightPlanUtils = class _FlightPlanUtils {
1541
1651
  /**
@@ -2212,6 +2322,60 @@ function processUnknown2(decodeResult, value) {
2212
2322
  decodeResult.remaining.text += value;
2213
2323
  }
2214
2324
 
2325
+ // lib/plugins/Label_HX.ts
2326
+ var Label_HX = class extends DecoderPlugin {
2327
+ name = "label-hx";
2328
+ qualifiers() {
2329
+ return {
2330
+ labels: ["HX"],
2331
+ preambles: ["RA FMT LOCATION", "RA FMT 43"]
2332
+ };
2333
+ }
2334
+ decode(message, options = {}) {
2335
+ const decodeResult = this.defaultResult();
2336
+ decodeResult.decoder.name = this.name;
2337
+ decodeResult.message = message;
2338
+ decodeResult.formatted.description = "Undelivered Uplink Report";
2339
+ const parts = message.text.split(" ");
2340
+ decodeResult.decoded = true;
2341
+ if (parts[2] === "LOCATION") {
2342
+ let latdir = parts[3].substring(0, 1);
2343
+ let latdeg = Number(parts[3].substring(1, 3));
2344
+ let latmin = Number(parts[3].substring(3, 7));
2345
+ let londir = parts[4].substring(0, 1);
2346
+ let londeg = Number(parts[4].substring(1, 4));
2347
+ let lonmin = Number(parts[4].substring(4, 8));
2348
+ decodeResult.raw.position = {
2349
+ latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
2350
+ longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
2351
+ };
2352
+ decodeResult.remaining.text = parts.slice(5).join(" ");
2353
+ } else if (parts[2] === "43") {
2354
+ ResultFormatter.departureAirport(decodeResult, parts[3]);
2355
+ decodeResult.remaining.text = parts.slice(4).join(" ");
2356
+ } else {
2357
+ decodeResult.decoded = false;
2358
+ }
2359
+ if (decodeResult.raw.position) {
2360
+ decodeResult.formatted.items.push({
2361
+ type: "aircraft_position",
2362
+ code: "POS",
2363
+ label: "Aircraft Position",
2364
+ value: CoordinateUtils.coordinateString(decodeResult.raw.position)
2365
+ });
2366
+ }
2367
+ if (decodeResult.decoded) {
2368
+ if (decodeResult.remaining.text === "")
2369
+ decodeResult.decoder.decodeLevel = "full";
2370
+ else
2371
+ decodeResult.decoder.decodeLevel = "partial";
2372
+ } else {
2373
+ decodeResult.decoder.decodeLevel = "none";
2374
+ }
2375
+ return decodeResult;
2376
+ }
2377
+ };
2378
+
2215
2379
  // lib/plugins/Label_SQ.ts
2216
2380
  var Label_SQ = class extends DecoderPlugin {
2217
2381
  name = "label-sq";
@@ -2252,11 +2416,13 @@ var Label_SQ = class extends DecoderPlugin {
2252
2416
  decodeResult.formatted.items = [
2253
2417
  {
2254
2418
  type: "network",
2419
+ code: "NETT",
2255
2420
  label: "Network",
2256
2421
  value: formattedNetwork
2257
2422
  },
2258
2423
  {
2259
2424
  type: "version",
2425
+ code: "VER",
2260
2426
  label: "Version",
2261
2427
  value: decodeResult.raw.version
2262
2428
  }
@@ -2265,6 +2431,7 @@ var Label_SQ = class extends DecoderPlugin {
2265
2431
  if (decodeResult.raw.groundStation.icaoCode && decodeResult.raw.groundStation.number) {
2266
2432
  decodeResult.formatted.items.push({
2267
2433
  type: "ground_station",
2434
+ code: "GNDSTN",
2268
2435
  label: "Ground Station",
2269
2436
  value: `${decodeResult.raw.groundStation.icaoCode}${decodeResult.raw.groundStation.number}`
2270
2437
  });
@@ -2272,6 +2439,7 @@ var Label_SQ = class extends DecoderPlugin {
2272
2439
  if (decodeResult.raw.groundStation.iataCode) {
2273
2440
  decodeResult.formatted.items.push({
2274
2441
  type: "iataCode",
2442
+ code: "IATA",
2275
2443
  label: "IATA",
2276
2444
  value: decodeResult.raw.groundStation.iataCode
2277
2445
  });
@@ -2279,6 +2447,7 @@ var Label_SQ = class extends DecoderPlugin {
2279
2447
  if (decodeResult.raw.groundStation.icaoCode) {
2280
2448
  decodeResult.formatted.items.push({
2281
2449
  type: "icaoCode",
2450
+ code: "ICAO",
2282
2451
  label: "ICAO",
2283
2452
  value: decodeResult.raw.groundStation.icaoCode
2284
2453
  });
@@ -2286,6 +2455,7 @@ var Label_SQ = class extends DecoderPlugin {
2286
2455
  if (decodeResult.raw.groundStation.coordinates.latitude) {
2287
2456
  decodeResult.formatted.items.push({
2288
2457
  type: "coordinates",
2458
+ code: "COORD",
2289
2459
  label: "Ground Station Location",
2290
2460
  value: `${decodeResult.raw.groundStation.coordinates.latitude}, ${decodeResult.raw.groundStation.coordinates.longitude}`
2291
2461
  });
@@ -2293,6 +2463,7 @@ var Label_SQ = class extends DecoderPlugin {
2293
2463
  if (decodeResult.raw.groundStation.airport) {
2294
2464
  decodeResult.formatted.items.push({
2295
2465
  type: "airport",
2466
+ code: "APT",
2296
2467
  label: "Airport",
2297
2468
  value: `${decodeResult.raw.groundStation.airport.name} (${decodeResult.raw.groundStation.airport.icao}) in ${decodeResult.raw.groundStation.airport.location}`
2298
2469
  });
@@ -2301,6 +2472,7 @@ var Label_SQ = class extends DecoderPlugin {
2301
2472
  if (decodeResult.raw.vdlFrequency) {
2302
2473
  decodeResult.formatted.items.push({
2303
2474
  type: "vdlFrequency",
2475
+ code: "VDLFRQ",
2304
2476
  label: "VDL Frequency",
2305
2477
  value: `${decodeResult.raw.vdlFrequency} MHz`
2306
2478
  });
@@ -2457,31 +2629,48 @@ var Label_QQ = class extends DecoderPlugin {
2457
2629
  decode(message, options = {}) {
2458
2630
  const decodeResult = this.defaultResult();
2459
2631
  decodeResult.decoder.name = this.name;
2460
- decodeResult.raw.origin = message.text.substring(0, 4);
2461
- decodeResult.raw.destination = message.text.substring(4, 8);
2462
- decodeResult.raw.wheels_off = message.text.substring(8, 12);
2463
- decodeResult.remaining.text = message.text.substring(12);
2632
+ decodeResult.message = message;
2464
2633
  decodeResult.formatted.description = "OFF Report";
2465
- decodeResult.formatted.items = [
2466
- {
2467
- type: "origin",
2468
- code: "ORG",
2469
- label: "Origin",
2470
- value: decodeResult.raw.origin
2471
- },
2472
- {
2473
- type: "destination",
2474
- code: "DST",
2475
- label: "Destination",
2476
- value: decodeResult.raw.destination
2477
- },
2478
- {
2479
- type: "wheels_off",
2480
- code: "WOFF",
2481
- label: "Wheels OFF",
2482
- value: decodeResult.raw.wheels_off
2634
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
2635
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
2636
+ decodeResult.raw.wheels_off = message.text.substring(8, 12);
2637
+ if (message.text.substring(12, 19) === "\r\n001FE") {
2638
+ decodeResult.raw.day_of_month = message.text.substring(19, 21);
2639
+ decodeResult.raw.wheels_off = message.text.substring(21, 27);
2640
+ let latdir = message.text.substring(27, 28);
2641
+ let latdeg = Number(message.text.substring(28, 30));
2642
+ let latmin = Number(message.text.substring(30, 34));
2643
+ let londir = message.text.substring(34, 35);
2644
+ let londeg = Number(message.text.substring(35, 38));
2645
+ let lonmin = Number(message.text.substring(38, 42));
2646
+ decodeResult.raw.position = {
2647
+ latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
2648
+ longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
2649
+ };
2650
+ decodeResult.remaining.text = message.text.substring(42, 45);
2651
+ if (decodeResult.remaining.text !== "---") {
2652
+ ResultFormatter.groundspeed(decodeResult, message.text.substring(45, 48));
2653
+ } else {
2654
+ ResultFormatter.unknown(decodeResult, message.text.substring(45, 48));
2483
2655
  }
2484
- ];
2656
+ ResultFormatter.unknown(decodeResult, message.text.substring(48));
2657
+ } else {
2658
+ decodeResult.remaining.text = message.text.substring(12);
2659
+ }
2660
+ decodeResult.formatted.items.push({
2661
+ type: "wheels_off",
2662
+ code: "WOFF",
2663
+ label: "Wheels OFF",
2664
+ value: decodeResult.raw.wheels_off
2665
+ });
2666
+ if (decodeResult.raw.position) {
2667
+ decodeResult.formatted.items.push({
2668
+ type: "aircraft_position",
2669
+ code: "POS",
2670
+ label: "Aircraft Position",
2671
+ value: CoordinateUtils.coordinateString(decodeResult.raw.position)
2672
+ });
2673
+ }
2485
2674
  decodeResult.decoded = true;
2486
2675
  if (decodeResult.remaining.text === "")
2487
2676
  decodeResult.decoder.decodeLevel = "full";
@@ -3304,6 +3493,9 @@ var MessageDecoder = class {
3304
3493
  this.debug = false;
3305
3494
  this.registerPlugin(new Label_ColonComma(this));
3306
3495
  this.registerPlugin(new Label_5Z(this));
3496
+ this.registerPlugin(new Label_10_LDR(this));
3497
+ this.registerPlugin(new Label_10_POS(this));
3498
+ this.registerPlugin(new Label_10_Slash(this));
3307
3499
  this.registerPlugin(new Label_12_N_Space(this));
3308
3500
  this.registerPlugin(new Label_15(this));
3309
3501
  this.registerPlugin(new Label_15_FST(this));
@@ -3324,6 +3516,7 @@ var MessageDecoder = class {
3324
3516
  this.registerPlugin(new Label_H1_OHMA(this));
3325
3517
  this.registerPlugin(new Label_H1_POS(this));
3326
3518
  this.registerPlugin(new Label_H1_WRN(this));
3519
+ this.registerPlugin(new Label_HX(this));
3327
3520
  this.registerPlugin(new Label_80(this));
3328
3521
  this.registerPlugin(new Label_8E(this));
3329
3522
  this.registerPlugin(new Label_1M_Slash(this));