@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.js CHANGED
@@ -97,6 +97,192 @@ var DecoderPlugin = class {
97
97
  }
98
98
  };
99
99
 
100
+ // lib/utils/coordinate_utils.ts
101
+ var CoordinateUtils = class {
102
+ /**
103
+ * Decode a string of coordinates into an object with latitude and longitude in millidegrees
104
+ * @param stringCoords - The string of coordinates to decode
105
+ *
106
+ * @returns An object with latitude and longitude properties
107
+ */
108
+ static decodeStringCoordinates(stringCoords) {
109
+ var results = {};
110
+ const firstChar = stringCoords.substring(0, 1);
111
+ let middleChar = stringCoords.substring(6, 7);
112
+ let longitudeChars = stringCoords.substring(7, 13);
113
+ if (middleChar == " ") {
114
+ middleChar = stringCoords.substring(7, 8);
115
+ longitudeChars = stringCoords.substring(8, 14);
116
+ }
117
+ if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
118
+ results.latitude = Number(stringCoords.substring(1, 6)) / 1e3 * (firstChar === "S" ? -1 : 1);
119
+ results.longitude = Number(longitudeChars) / 1e3 * (middleChar === "W" ? -1 : 1);
120
+ } else {
121
+ return;
122
+ }
123
+ return results;
124
+ }
125
+ /**
126
+ * Decode a string of coordinates into an object with latitude and longitude in degrees and decimal minutes
127
+ * @param stringCoords - The string of coordinates to decode
128
+ *
129
+ * @returns An object with latitude and longitude properties
130
+ */
131
+ static decodeStringCoordinatesDecimalMinutes(stringCoords) {
132
+ var results = {};
133
+ const firstChar = stringCoords.substring(0, 1);
134
+ let middleChar = stringCoords.substring(6, 7);
135
+ let longitudeChars = stringCoords.substring(7, 13);
136
+ if (middleChar == " ") {
137
+ middleChar = stringCoords.substring(7, 8);
138
+ longitudeChars = stringCoords.substring(8, 14);
139
+ }
140
+ const latDeg = Math.trunc(Number(stringCoords.substring(1, 6)) / 1e3);
141
+ const latMin = Number(stringCoords.substring(1, 6)) % 1e3 / 10;
142
+ const lonDeg = Math.trunc(Number(longitudeChars) / 1e3);
143
+ const lonMin = Number(longitudeChars) % 1e3 / 10;
144
+ if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
145
+ results.latitude = (latDeg + latMin / 60) * (firstChar === "S" ? -1 : 1);
146
+ results.longitude = (lonDeg + lonMin / 60) * (middleChar === "W" ? -1 : 1);
147
+ } else {
148
+ return;
149
+ }
150
+ return results;
151
+ }
152
+ static coordinateString(coords) {
153
+ const latDir = coords.latitude > 0 ? "N" : "S";
154
+ const lonDir = coords.longitude > 0 ? "E" : "W";
155
+ return `${Math.abs(coords.latitude).toFixed(3)} ${latDir}, ${Math.abs(coords.longitude).toFixed(3)} ${lonDir}`;
156
+ }
157
+ };
158
+
159
+ // lib/utils/result_formatter.ts
160
+ var ResultFormatter = class {
161
+ static position(decodeResult, value) {
162
+ decodeResult.raw.position = value;
163
+ decodeResult.formatted.items.push({
164
+ type: "aircraft_position",
165
+ code: "POS",
166
+ label: "Aircraft Position",
167
+ value: CoordinateUtils.coordinateString(value)
168
+ });
169
+ }
170
+ static altitude(decodeResult, value) {
171
+ decodeResult.raw.altitude = value;
172
+ decodeResult.formatted.items.push({
173
+ type: "altitude",
174
+ code: "ALT",
175
+ label: "Altitude",
176
+ value: `${decodeResult.raw.altitude} feet`
177
+ });
178
+ }
179
+ static flightNumber(decodeResult, value) {
180
+ decodeResult.raw.flight_number = value;
181
+ }
182
+ static departureAirport(decodeResult, value) {
183
+ decodeResult.raw.departure_icao = value;
184
+ decodeResult.formatted.items.push({
185
+ type: "origin",
186
+ code: "ORG",
187
+ label: "Origin",
188
+ value: decodeResult.raw.departure_icao
189
+ });
190
+ }
191
+ static departureRunway(decodeResult, value) {
192
+ decodeResult.raw.departure_runway = value;
193
+ decodeResult.formatted.items.push({
194
+ type: "runway",
195
+ code: "DEPRWY",
196
+ label: "Departure Runway",
197
+ value: decodeResult.raw.departure_runway
198
+ });
199
+ }
200
+ static arrivalAirport(decodeResult, value) {
201
+ decodeResult.raw.arrival_icao = value;
202
+ decodeResult.formatted.items.push({
203
+ type: "destination",
204
+ code: "DST",
205
+ label: "Destination",
206
+ value: decodeResult.raw.arrival_icao
207
+ });
208
+ }
209
+ static eta(decodeResult, value) {
210
+ decodeResult.raw.eta_time = value;
211
+ decodeResult.formatted.items.push({
212
+ type: "eta",
213
+ code: "ETA",
214
+ label: "Estimated Time of Arrival",
215
+ value: value.substring(0, 2) + ":" + value.substring(2, 4) + ":" + value.substring(4, 6)
216
+ });
217
+ }
218
+ static arrivalRunway(decodeResult, value) {
219
+ decodeResult.raw.arrival_runway = value;
220
+ decodeResult.formatted.items.push({
221
+ type: "runway",
222
+ code: "ARWY",
223
+ label: "Arrival Runway",
224
+ value: decodeResult.raw.arrival_runway
225
+ });
226
+ }
227
+ static currentFuel(decodeResult, value) {
228
+ decodeResult.raw.fuel_on_board = value;
229
+ decodeResult.formatted.items.push({
230
+ type: "fuel_on_board",
231
+ code: "FOB",
232
+ label: "Fuel On Board",
233
+ value: decodeResult.raw.fuel_on_board.toString()
234
+ });
235
+ }
236
+ static remainingFuel(decodeResult, value) {
237
+ decodeResult.raw.fuel_remaining = value;
238
+ decodeResult.formatted.items.push({
239
+ type: "fuel_remaining",
240
+ code: "FUEL",
241
+ label: "Fuel Remaining",
242
+ value: decodeResult.raw.fuel_remaining.toString()
243
+ });
244
+ }
245
+ static checksum(decodeResult, value) {
246
+ decodeResult.raw.checksum = Number("0x" + value);
247
+ decodeResult.formatted.items.push({
248
+ type: "message_checksum",
249
+ code: "CHECKSUM",
250
+ label: "Message Checksum",
251
+ value: "0x" + ("0000" + decodeResult.raw.checksum.toString(16)).slice(-4)
252
+ });
253
+ }
254
+ static groundspeed(decodeResult, value) {
255
+ decodeResult.raw.groundspeed = value;
256
+ decodeResult.formatted.items.push({
257
+ type: "aircraft_groundspeed",
258
+ code: "GSPD",
259
+ label: "Aircraft Groundspeed",
260
+ value: `${decodeResult.raw.groundspeed}`
261
+ });
262
+ }
263
+ static temperature(decodeResult, value) {
264
+ decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
265
+ decodeResult.formatted.items.push({
266
+ type: "outside_air_temperature",
267
+ code: "OATEMP",
268
+ label: "Outside Air Temperature (C)",
269
+ value: `${decodeResult.raw.outside_air_temperature}`
270
+ });
271
+ }
272
+ static heading(decodeResult, value) {
273
+ decodeResult.raw.heading = value;
274
+ decodeResult.formatted.items.push({
275
+ type: "heading",
276
+ code: "HDG",
277
+ label: "Heading",
278
+ value: `${decodeResult.raw.heading}`
279
+ });
280
+ }
281
+ static unknown(decodeResult, value) {
282
+ decodeResult.remaining.text += "," + value;
283
+ }
284
+ };
285
+
100
286
  // lib/plugins/Label_5Z.ts
101
287
  var Label_5Z = class extends DecoderPlugin {
102
288
  name = "label-5z";
@@ -127,141 +313,327 @@ var Label_5Z = class extends DecoderPlugin {
127
313
  };
128
314
  qualifiers() {
129
315
  return {
130
- labels: ["5Z"]
316
+ labels: ["5Z"]
317
+ };
318
+ }
319
+ decode(message, options = {}) {
320
+ const decodeResult = this.defaultResult();
321
+ decodeResult.decoder.name = this.name;
322
+ decodeResult.formatted.description = "Airline Designated Downlink";
323
+ const uaRegex = /^\/(?<type>\w+) (?<remainder>.+)/;
324
+ let results = message.text.match(uaRegex);
325
+ if (results && results.length >= 2) {
326
+ const type = results.groups.type.split("/")[0];
327
+ const { remainder } = results.groups;
328
+ const typeDescription = this.descriptions[type] ? this.descriptions[type] : "Unknown";
329
+ decodeResult.raw.airline = "United Airlines";
330
+ decodeResult.formatted.items.push({
331
+ type: "airline",
332
+ label: "Airline",
333
+ value: "United Airlines"
334
+ });
335
+ decodeResult.raw.message_type = type;
336
+ decodeResult.formatted.items.push({
337
+ type: "message_type",
338
+ label: "Message Type",
339
+ value: `${typeDescription} (${type})`
340
+ });
341
+ if (type === "B3") {
342
+ const rdcRegex = /^(?<from>\w\w\w)(?<to>\w\w\w) (?<unknown1>\d\d) R(?<runway>.+) G(?<unknown2>.+)$/;
343
+ results = remainder.match(rdcRegex);
344
+ if (results) {
345
+ ResultFormatter.departureAirport(decodeResult, results.groups.from);
346
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.to);
347
+ ResultFormatter.arrivalRunway(decodeResult, results.groups.runway);
348
+ } else {
349
+ if (options.debug) {
350
+ console.log(`Decoder: Unkown 5Z RDC format: ${remainder}`);
351
+ }
352
+ }
353
+ } else {
354
+ decodeResult.remaining.text = remainder;
355
+ }
356
+ decodeResult.decoded = true;
357
+ decodeResult.decoder.decodeLevel = "partial";
358
+ } else {
359
+ if (options.debug) {
360
+ console.log(`Decoder: Unknown 5Z message: ${message.text}`);
361
+ }
362
+ decodeResult.remaining.text = message.text;
363
+ decodeResult.decoded = false;
364
+ decodeResult.decoder.decodeLevel = "none";
365
+ }
366
+ return decodeResult;
367
+ }
368
+ };
369
+
370
+ // lib/plugins/Label_10_LDR.ts
371
+ var Label_10_LDR = class extends DecoderPlugin {
372
+ // eslint-disable-line camelcase
373
+ name = "label-10-ldr";
374
+ qualifiers() {
375
+ return {
376
+ labels: ["10"],
377
+ preambles: ["LDR"]
378
+ };
379
+ }
380
+ decode(message, options = {}) {
381
+ const decodeResult = this.defaultResult();
382
+ decodeResult.decoder.name = this.name;
383
+ decodeResult.formatted.description = "Position Report";
384
+ decodeResult.message = message;
385
+ const parts = message.text.split(",");
386
+ if (parts.length < 17) {
387
+ if (options?.debug) {
388
+ console.log(`Decoder: Unknown 10 message: ${message.text}`);
389
+ }
390
+ decodeResult.remaining.text = message.text;
391
+ decodeResult.decoded = false;
392
+ decodeResult.decoder.decodeLevel = "none";
393
+ return decodeResult;
394
+ }
395
+ const lat = parts[5];
396
+ const lon = parts[6];
397
+ const position = {
398
+ latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1).trim()),
399
+ longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1).trim())
400
+ };
401
+ ResultFormatter.position(decodeResult, position);
402
+ ResultFormatter.altitude(decodeResult, Number(parts[7]));
403
+ ResultFormatter.departureAirport(decodeResult, parts[9]);
404
+ ResultFormatter.arrivalAirport(decodeResult, parts[10]);
405
+ ResultFormatter.arrivalRunway(decodeResult, parts[12].split("/")[0]);
406
+ decodeResult.remaining.text = [...parts.slice(0, 5), parts[11], ...parts.slice(13)].join(",");
407
+ decodeResult.decoded = true;
408
+ decodeResult.decoder.decodeLevel = "partial";
409
+ return decodeResult;
410
+ }
411
+ };
412
+
413
+ // lib/plugins/Label_10_POS.ts
414
+ var Label_10_POS = class extends DecoderPlugin {
415
+ // eslint-disable-line camelcase
416
+ name = "label-10-pos";
417
+ qualifiers() {
418
+ return {
419
+ labels: ["10"],
420
+ preambles: ["POS"]
421
+ };
422
+ }
423
+ decode(message, options = {}) {
424
+ const decodeResult = this.defaultResult();
425
+ decodeResult.decoder.name = this.name;
426
+ decodeResult.formatted.description = "Position Report";
427
+ decodeResult.message = message;
428
+ const parts = message.text.split(",");
429
+ if (parts.length !== 12) {
430
+ if (options?.debug) {
431
+ console.log(`Decoder: Unknown 10 message: ${message.text}`);
432
+ }
433
+ decodeResult.remaining.text = message.text;
434
+ decodeResult.decoded = false;
435
+ decodeResult.decoder.decodeLevel = "none";
436
+ return decodeResult;
437
+ }
438
+ const lat = parts[1].trim();
439
+ const lon = parts[2].trim();
440
+ const position = {
441
+ latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1).trim()) / 100,
442
+ longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1).trim()) / 100
443
+ };
444
+ ResultFormatter.position(decodeResult, position);
445
+ ResultFormatter.altitude(decodeResult, Number(parts[7]));
446
+ decodeResult.remaining.text = [parts[0], ...parts.slice(3, 7), ...parts.slice(8)].join(",");
447
+ decodeResult.decoded = true;
448
+ decodeResult.decoder.decodeLevel = "partial";
449
+ return decodeResult;
450
+ }
451
+ };
452
+
453
+ // lib/DateTimeUtils.ts
454
+ var DateTimeUtils = class {
455
+ // Expects a four digit UTC time string (HHMM)
456
+ static UTCToString(UTCString) {
457
+ let utcDate = /* @__PURE__ */ new Date();
458
+ utcDate.setUTCHours(+UTCString.substr(0, 2), +UTCString.substr(2, 2), 0);
459
+ return utcDate.toTimeString();
460
+ }
461
+ // Expects a six digit date string and a four digit UTC time string
462
+ // (DDMMYY) (HHMM)
463
+ static UTCDateTimeToString(dateString, timeString) {
464
+ let utcDate = /* @__PURE__ */ new Date();
465
+ utcDate.setUTCDate(+dateString.substr(0, 2));
466
+ utcDate.setUTCMonth(+dateString.substr(2, 2));
467
+ if (dateString.length === 6) {
468
+ utcDate.setUTCFullYear(2e3 + +dateString.substr(4, 2));
469
+ }
470
+ if (timeString.length === 6) {
471
+ utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), +timeString.substr(4, 2));
472
+ } else {
473
+ utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), 0);
474
+ }
475
+ return utcDate.toUTCString();
476
+ }
477
+ /**
478
+ *
479
+ * @param time HHMMSS
480
+ * @returns seconds since midnight
481
+ */
482
+ static convertHHMMSSToTod(time) {
483
+ const h = Number(time.substring(0, 2));
484
+ const m = Number(time.substring(2, 4));
485
+ const s = Number(time.substring(4, 6));
486
+ const tod = h * 3600 + m * 60 + s;
487
+ return tod;
488
+ }
489
+ /**
490
+ *
491
+ * @param time HHMMSS
492
+ * @param date MMDDYY or MMDDYYYY
493
+ * @returns seconds since epoch
494
+ */
495
+ static convertDateTimeToEpoch(time, date) {
496
+ if (date.length === 6) {
497
+ date = date.substring(0, 4) + `20${date.substring(4, 6)}`;
498
+ }
499
+ 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`;
500
+ const millis = Date.parse(timestamp);
501
+ return millis / 1e3;
502
+ }
503
+ };
504
+
505
+ // lib/utils/route_utils.ts
506
+ var RouteUtils = class _RouteUtils {
507
+ static routeToString(route) {
508
+ let str = "";
509
+ if (route.name) {
510
+ str += route.name;
511
+ }
512
+ if (route.runway) {
513
+ str += `(${route.runway})`;
514
+ }
515
+ if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
516
+ str += " starting at ";
517
+ } else if (str.length !== 0 && route.waypoints) {
518
+ str += ": ";
519
+ }
520
+ if (route.waypoints) {
521
+ str += _RouteUtils.waypointsToString(route.waypoints);
522
+ }
523
+ return str;
524
+ }
525
+ static waypointToString(waypoint) {
526
+ let s = waypoint.name;
527
+ if (waypoint.latitude && waypoint.longitude) {
528
+ s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
529
+ }
530
+ if (waypoint.offset) {
531
+ s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
532
+ }
533
+ if (waypoint.time && waypoint.timeFormat) {
534
+ s += `@${_RouteUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
535
+ }
536
+ return s;
537
+ }
538
+ static getWaypoint(leg) {
539
+ const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
540
+ if (regex?.length == 4) {
541
+ return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
542
+ }
543
+ const waypoint = leg.split(",");
544
+ if (waypoint.length == 2) {
545
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
546
+ if (position) {
547
+ return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
548
+ }
549
+ }
550
+ if (leg.length == 13 || leg.length == 14) {
551
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
552
+ const name = waypoint.length == 2 ? waypoint[0] : "";
553
+ if (position) {
554
+ return { name, latitude: position.latitude, longitude: position.longitude };
555
+ }
556
+ }
557
+ return { name: leg };
558
+ }
559
+ // move out if we want public
560
+ static timestampToString(time, format) {
561
+ const date = new Date(time * 1e3);
562
+ if (format == "tod") {
563
+ return date.toISOString().slice(11, 19);
564
+ }
565
+ return date.toISOString().slice(0, -5) + "Z";
566
+ }
567
+ static waypointsToString(waypoints) {
568
+ let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
569
+ if (str.startsWith(" > ")) {
570
+ str = ">>" + str.slice(2);
571
+ }
572
+ return str;
573
+ }
574
+ };
575
+
576
+ // lib/plugins/Label_10_Slash.ts
577
+ var Label_10_Slash = class extends DecoderPlugin {
578
+ // eslint-disable-line camelcase
579
+ name = "label-10-slash";
580
+ qualifiers() {
581
+ return {
582
+ labels: ["10"],
583
+ preambles: ["/"]
131
584
  };
132
585
  }
133
586
  decode(message, options = {}) {
134
587
  const decodeResult = this.defaultResult();
135
588
  decodeResult.decoder.name = this.name;
136
- decodeResult.formatted.description = "Airline Designated Downlink";
137
- const uaRegex = /^\/(?<type>\w+) (?<remainder>.+)/;
138
- let results = message.text.match(uaRegex);
139
- if (results && results.length >= 2) {
140
- const type = results.groups.type.split("/")[0];
141
- const { remainder } = results.groups;
142
- const typeDescription = this.descriptions[type] ? this.descriptions[type] : "Unknown";
143
- decodeResult.raw.airline = "United Airlines";
144
- decodeResult.formatted.items.push({
145
- type: "airline",
146
- label: "Airline",
147
- value: "United Airlines"
148
- });
149
- decodeResult.raw.message_type = type;
150
- decodeResult.formatted.items.push({
151
- type: "message_type",
152
- label: "Message Type",
153
- value: `${typeDescription} (${type})`
154
- });
155
- if (type === "B3") {
156
- const rdcRegex = /^(?<from>\w\w\w)(?<to>\w\w\w) (?<unknown1>\d\d) R(?<runway>.+) G(?<unknown2>.+)$/;
157
- results = remainder.match(rdcRegex);
158
- if (results) {
159
- decodeResult.raw.origin = results.groups.from;
160
- decodeResult.formatted.items.push({
161
- type: "origin",
162
- label: "Origin",
163
- value: `${results.groups.from}`
164
- });
165
- decodeResult.raw.destination = results.groups.to;
166
- decodeResult.formatted.items.push({
167
- type: "destination",
168
- label: "Destination",
169
- value: `${results.groups.to}`
170
- });
171
- decodeResult.formatted.items.push({
172
- type: "unknown1",
173
- label: "Unknown Field 1",
174
- value: `${results.groups.unknown1}`
175
- });
176
- decodeResult.raw.runway = results.groups.runway;
177
- decodeResult.formatted.items.push({
178
- type: "runway",
179
- label: "Runway",
180
- value: `${results.groups.runway}`
181
- });
182
- decodeResult.formatted.items.push({
183
- type: "unknown2",
184
- label: "Unknown Field 2",
185
- value: `${results.groups.unknown2}`
186
- });
187
- } else {
188
- if (options.debug) {
189
- console.log(`Decoder: Unkown 5Z RDC format: ${remainder}`);
190
- }
191
- }
192
- } else {
193
- decodeResult.remaining.text = remainder;
194
- }
195
- decodeResult.decoded = true;
196
- decodeResult.decoder.decodeLevel = "partial";
197
- } else {
198
- if (options.debug) {
199
- console.log(`Decoder: Unknown 5Z message: ${message.text}`);
589
+ decodeResult.formatted.description = "Position Report";
590
+ decodeResult.message = message;
591
+ const parts = message.text.split("/");
592
+ if (parts.length < 17) {
593
+ if (options?.debug) {
594
+ console.log(`Decoder: Unknown 10 message: ${message.text}`);
200
595
  }
201
596
  decodeResult.remaining.text = message.text;
202
597
  decodeResult.decoded = false;
203
598
  decodeResult.decoder.decodeLevel = "none";
599
+ return decodeResult;
204
600
  }
205
- return decodeResult;
206
- }
207
- };
208
-
209
- // lib/utils/coordinate_utils.ts
210
- var CoordinateUtils = class {
211
- /**
212
- * Decode a string of coordinates into an object with latitude and longitude in millidegrees
213
- * @param stringCoords - The string of coordinates to decode
214
- *
215
- * @returns An object with latitude and longitude properties
216
- */
217
- static decodeStringCoordinates(stringCoords) {
218
- var results = {};
219
- const firstChar = stringCoords.substring(0, 1);
220
- let middleChar = stringCoords.substring(6, 7);
221
- let longitudeChars = stringCoords.substring(7, 13);
222
- if (middleChar == " ") {
223
- middleChar = stringCoords.substring(7, 8);
224
- longitudeChars = stringCoords.substring(8, 14);
225
- }
226
- if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
227
- results.latitude = Number(stringCoords.substring(1, 6)) / 1e3 * (firstChar === "S" ? -1 : 1);
228
- results.longitude = Number(longitudeChars) / 1e3 * (middleChar === "W" ? -1 : 1);
229
- } else {
230
- return;
231
- }
232
- return results;
233
- }
234
- /**
235
- * Decode a string of coordinates into an object with latitude and longitude in degrees and decimal minutes
236
- * @param stringCoords - The string of coordinates to decode
237
- *
238
- * @returns An object with latitude and longitude properties
239
- */
240
- static decodeStringCoordinatesDecimalMinutes(stringCoords) {
241
- var results = {};
242
- const firstChar = stringCoords.substring(0, 1);
243
- let middleChar = stringCoords.substring(6, 7);
244
- let longitudeChars = stringCoords.substring(7, 13);
245
- if (middleChar == " ") {
246
- middleChar = stringCoords.substring(7, 8);
247
- longitudeChars = stringCoords.substring(8, 14);
248
- }
249
- const latDeg = Math.trunc(Number(stringCoords.substring(1, 6)) / 1e3);
250
- const latMin = Number(stringCoords.substring(1, 6)) % 1e3 / 10;
251
- const lonDeg = Math.trunc(Number(longitudeChars) / 1e3);
252
- const lonMin = Number(longitudeChars) % 1e3 / 10;
253
- if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
254
- results.latitude = (latDeg + latMin / 60) * (firstChar === "S" ? -1 : 1);
255
- results.longitude = (lonDeg + lonMin / 60) * (middleChar === "W" ? -1 : 1);
256
- } else {
257
- return;
601
+ const lat = parts[1];
602
+ const lon = parts[2];
603
+ const position = {
604
+ latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1)),
605
+ longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1))
606
+ };
607
+ ResultFormatter.position(decodeResult, position);
608
+ ResultFormatter.heading(decodeResult, Number(parts[5]));
609
+ ResultFormatter.altitude(decodeResult, 100 * Number(parts[6]));
610
+ ResultFormatter.arrivalAirport(decodeResult, parts[7]);
611
+ ResultFormatter.eta(decodeResult, parts[8] + "00");
612
+ const waypoints = [{
613
+ name: parts[11]
614
+ }, {
615
+ name: parts[12],
616
+ time: DateTimeUtils.convertHHMMSSToTod(parts[13] + "00"),
617
+ timeFormat: "tod"
618
+ }, {
619
+ name: parts[14],
620
+ time: DateTimeUtils.convertHHMMSSToTod(parts[15] + "00"),
621
+ timeFormat: "tod"
622
+ }];
623
+ decodeResult.raw.route = { waypoints };
624
+ decodeResult.formatted.items.push({
625
+ type: "aircraft_route",
626
+ code: "ROUTE",
627
+ label: "Aircraft Route",
628
+ value: RouteUtils.routeToString(decodeResult.raw.route)
629
+ });
630
+ if (parts[16]) {
631
+ ResultFormatter.departureAirport(decodeResult, parts[16]);
258
632
  }
259
- return results;
260
- }
261
- static coordinateString(coords) {
262
- const latDir = coords.latitude > 0 ? "N" : "S";
263
- const lonDir = coords.longitude > 0 ? "E" : "W";
264
- return `${Math.abs(coords.latitude).toFixed(3)} ${latDir}, ${Math.abs(coords.longitude).toFixed(3)} ${lonDir}`;
633
+ decodeResult.remaining.text = [parts[3], parts[4], ...parts.slice(9, 11), ...parts.slice(17)].join("/");
634
+ decodeResult.decoded = true;
635
+ decodeResult.decoder.decodeLevel = "partial";
636
+ return decodeResult;
265
637
  }
266
638
  };
267
639
 
@@ -290,19 +662,14 @@ var Label_12_N_Space = class extends DecoderPlugin {
290
662
  latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
291
663
  longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
292
664
  };
293
- decodeResult.raw.flight_level = results.groups.alt == "GRD" || results.groups.alt == "***" ? "0" : Number(results.groups.alt);
665
+ const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
294
666
  decodeResult.formatted.items.push({
295
667
  type: "aircraft_position",
296
668
  code: "POS",
297
669
  label: "Aircraft Position",
298
670
  value: CoordinateUtils.coordinateString(decodeResult.raw.position)
299
671
  });
300
- decodeResult.formatted.items.push({
301
- type: "flight_level",
302
- code: "FL",
303
- label: "Flight Level",
304
- value: decodeResult.raw.flight_level
305
- });
672
+ ResultFormatter.altitude(decodeResult, altitude);
306
673
  decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}, ${results.groups.unkwn3}`;
307
674
  decodeResult.decoded = true;
308
675
  decodeResult.decoder.decodeLevel = "partial";
@@ -364,39 +731,35 @@ var Label_15_FST = class extends DecoderPlugin {
364
731
  decodeResult.decoder.name = this.name;
365
732
  decodeResult.formatted.description = "Position Report";
366
733
  decodeResult.message = message;
367
- decodeResult.raw.departure_icao = message.text.substring(5, 9);
368
- decodeResult.raw.arrival_icao = message.text.substring(9, 13);
369
- const stringCoords = message.text.substring(13);
734
+ const parts = message.text.split(" ");
735
+ const header = parts[0];
736
+ decodeResult.raw.departure_icao = header.substring(5, 9);
737
+ decodeResult.raw.arrival_icao = header.substring(9, 13);
738
+ const stringCoords = header.substring(13);
370
739
  const firstChar = stringCoords.substring(0, 1);
371
740
  const middleChar = stringCoords.substring(7, 8);
372
741
  decodeResult.raw.position = {};
373
742
  if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
374
743
  decodeResult.raw.position.latitude = Number(stringCoords.substring(1, 7)) / 1e4 * (firstChar === "S" ? -1 : 1);
375
- decodeResult.raw.position.longitude = Number(stringCoords.substring(8, 26)) / 1e5 * (middleChar === "W" ? -1 : 1);
744
+ decodeResult.raw.position.longitude = Number(stringCoords.substring(8, 15)) / 1e4 * (middleChar === "W" ? -1 : 1);
745
+ decodeResult.raw.altitude = Number(stringCoords.substring(15)) * 100;
376
746
  } else {
377
747
  decodeResult.decoded = false;
378
748
  decodeResult.decoder.decodeLevel = "none";
379
749
  return decodeResult;
380
750
  }
381
751
  decodeResult.formatted.items.push({
382
- type: "position",
383
- label: "Position",
752
+ type: "aircraft_position",
753
+ code: "POS",
754
+ label: "Aircraft Position",
384
755
  value: CoordinateUtils.coordinateString(decodeResult.raw.position)
385
756
  });
386
- decodeResult.formatted.items.push({
387
- type: "origin",
388
- code: "ORG",
389
- label: "Origin",
390
- value: decodeResult.raw.departure_icao
391
- });
392
- decodeResult.formatted.items.push({
393
- type: "destination",
394
- code: "DST",
395
- label: "Destination",
396
- value: decodeResult.raw.arrival_icao
397
- });
757
+ ResultFormatter.altitude(decodeResult, decodeResult.raw.altitude);
758
+ ResultFormatter.departureAirport(decodeResult, decodeResult.raw.departure_icao);
759
+ ResultFormatter.arrivalAirport(decodeResult, decodeResult.raw.arrival_icao);
760
+ decodeResult.remaining.text = parts.slice(1).join(" ");
398
761
  decodeResult.decoded = true;
399
- decodeResult.decoder.decodeLevel = "full";
762
+ decodeResult.decoder.decodeLevel = "partial";
400
763
  return decodeResult;
401
764
  }
402
765
  };
@@ -427,19 +790,14 @@ var Label_16_N_Space = class extends DecoderPlugin {
427
790
  latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
428
791
  longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
429
792
  };
430
- decodeResult.raw.flight_level = results.groups.alt == "GRD" || results.groups.alt == "***" ? "0" : Number(results.groups.alt);
793
+ const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
431
794
  decodeResult.formatted.items.push({
432
795
  type: "aircraft_position",
433
796
  code: "POS",
434
797
  label: "Aircraft Position",
435
798
  value: CoordinateUtils.coordinateString(decodeResult.raw.position)
436
799
  });
437
- decodeResult.formatted.items.push({
438
- type: "flight_level",
439
- code: "FL",
440
- label: "Flight Level",
441
- value: decodeResult.raw.flight_level
442
- });
800
+ ResultFormatter.altitude(decodeResult, altitude);
443
801
  decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}`;
444
802
  decodeResult.decoded = true;
445
803
  decodeResult.decoder.decodeLevel = "partial";
@@ -472,58 +830,6 @@ var Label_16_N_Space = class extends DecoderPlugin {
472
830
  }
473
831
  };
474
832
 
475
- // lib/DateTimeUtils.ts
476
- var DateTimeUtils = class {
477
- // Expects a four digit UTC time string (HHMM)
478
- static UTCToString(UTCString) {
479
- let utcDate = /* @__PURE__ */ new Date();
480
- utcDate.setUTCHours(+UTCString.substr(0, 2), +UTCString.substr(2, 2), 0);
481
- return utcDate.toTimeString();
482
- }
483
- // Expects a six digit date string and a four digit UTC time string
484
- // (DDMMYY) (HHMM)
485
- static UTCDateTimeToString(dateString, timeString) {
486
- let utcDate = /* @__PURE__ */ new Date();
487
- utcDate.setUTCDate(+dateString.substr(0, 2));
488
- utcDate.setUTCMonth(+dateString.substr(2, 2));
489
- if (dateString.length === 6) {
490
- utcDate.setUTCFullYear(2e3 + +dateString.substr(4, 2));
491
- }
492
- if (timeString.length === 6) {
493
- utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), +timeString.substr(4, 2));
494
- } else {
495
- utcDate.setUTCHours(+timeString.substr(0, 2), +timeString.substr(2, 2), 0);
496
- }
497
- return utcDate.toUTCString();
498
- }
499
- /**
500
- *
501
- * @param time HHMMSS
502
- * @returns seconds since midnight
503
- */
504
- static convertHHMMSSToTod(time) {
505
- const h = Number(time.substring(0, 2));
506
- const m = Number(time.substring(2, 4));
507
- const s = Number(time.substring(4, 6));
508
- const tod = h * 3600 + m * 60 + s;
509
- return tod;
510
- }
511
- /**
512
- *
513
- * @param time HHMMSS
514
- * @param date MMDDYY or MMDDYYYY
515
- * @returns seconds since epoch
516
- */
517
- static convertDateTimeToEpoch(time, date) {
518
- if (date.length === 6) {
519
- date = date.substring(0, 4) + `20${date.substring(4, 6)}`;
520
- }
521
- 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`;
522
- const millis = Date.parse(timestamp);
523
- return millis / 1e3;
524
- }
525
- };
526
-
527
833
  // lib/plugins/Label_1M_Slash.ts
528
834
  var Label_1M_Slash = class extends DecoderPlugin {
529
835
  name = "label-1m-slash";
@@ -600,6 +906,7 @@ var Label_20_POS = class extends DecoderPlugin {
600
906
  if (decodeResult.raw.position) {
601
907
  decodeResult.formatted.items.push({
602
908
  type: "position",
909
+ code: "POS",
603
910
  label: "Position",
604
911
  value: CoordinateUtils.coordinateString(decodeResult.raw.position)
605
912
  });
@@ -613,6 +920,7 @@ var Label_20_POS = class extends DecoderPlugin {
613
920
  if (decodeResult.raw.position) {
614
921
  decodeResult.formatted.items.push({
615
922
  type: "position",
923
+ code: "POS",
616
924
  label: "Position",
617
925
  value: CoordinateUtils.coordinateString(decodeResult.raw.position)
618
926
  });
@@ -652,7 +960,7 @@ var Label_21_POS = class extends DecoderPlugin {
652
960
  processAlt(decodeResult, fields[3]);
653
961
  processTemp(decodeResult, fields[6]);
654
962
  processArrvApt(decodeResult, fields[8]);
655
- decodeResult.raw.remaining = [
963
+ decodeResult.remaining.text = [
656
964
  fields[1],
657
965
  fields[2],
658
966
  fields[4],
@@ -1016,44 +1324,27 @@ var Label_44_POS = class extends DecoderPlugin {
1016
1324
  console.log(results.groups);
1017
1325
  }
1018
1326
  decodeResult.raw.position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(results.groups.unsplit_coords);
1019
- 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);
1020
- decodeResult.raw.departure_icao = results.groups.departure_icao;
1021
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1327
+ const flight_level = results.groups.flight_level_or_ground == "GRD" || results.groups.flight_level_or_ground == "***" ? 0 : Number(results.groups.flight_level_or_ground);
1022
1328
  decodeResult.raw.current_time = Date.parse(
1023
1329
  (/* @__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"
1024
1330
  );
1025
1331
  decodeResult.raw.eta_time = Date.parse(
1026
- (/* @__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"
1027
- );
1028
- if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1029
- decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1030
- }
1031
- if (decodeResult.raw.position) {
1032
- decodeResult.formatted.items.push({
1033
- type: "aircraft_position",
1034
- code: "POS",
1035
- label: "Aircraft Position",
1036
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1037
- });
1038
- }
1039
- decodeResult.formatted.items.push({
1040
- type: "origin",
1041
- code: "ORG",
1042
- label: "Origin",
1043
- value: decodeResult.raw.departure_icao
1044
- });
1045
- decodeResult.formatted.items.push({
1046
- type: "destination",
1047
- code: "DST",
1048
- label: "Destination",
1049
- value: decodeResult.raw.arrival_icao
1050
- });
1051
- decodeResult.formatted.items.push({
1052
- type: "flight_level",
1053
- code: "FL",
1054
- label: "Flight Level",
1055
- value: decodeResult.raw.flight_level
1056
- });
1332
+ (/* @__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"
1333
+ );
1334
+ if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1335
+ decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1336
+ }
1337
+ if (decodeResult.raw.position) {
1338
+ decodeResult.formatted.items.push({
1339
+ type: "aircraft_position",
1340
+ code: "POS",
1341
+ label: "Aircraft Position",
1342
+ value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1343
+ });
1344
+ }
1345
+ ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1346
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1347
+ ResultFormatter.altitude(decodeResult, flight_level * 100);
1057
1348
  }
1058
1349
  decodeResult.decoded = true;
1059
1350
  decodeResult.decoder.decodeLevel = "full";
@@ -1156,13 +1447,9 @@ var Label_80 = class extends DecoderPlugin {
1156
1447
  break;
1157
1448
  }
1158
1449
  case "FL": {
1159
- decodeResult.raw.flight_level = match.groups.value;
1160
- decodeResult.formatted.items.push({
1161
- type: "flight_level",
1162
- code: "FL",
1163
- label: this.descriptions[match.groups.field],
1164
- value: decodeResult.raw.flight_level
1165
- });
1450
+ const flight_level = match.groups.value;
1451
+ decodeResult.raw.altitude = flight_level * 100;
1452
+ ResultFormatter.altitude(decodeResult, decodeResult.raw.altitude);
1166
1453
  break;
1167
1454
  }
1168
1455
  case "FOB": {
@@ -1396,183 +1683,6 @@ function processUnknown(decodeResult, value) {
1396
1683
  decodeResult.remaining.text += value;
1397
1684
  }
1398
1685
 
1399
- // lib/utils/result_formatter.ts
1400
- var ResultFormatter = class {
1401
- static altitude(decodeResult, value) {
1402
- decodeResult.raw.altitude = value;
1403
- decodeResult.formatted.items.push({
1404
- type: "altitude",
1405
- code: "ALT",
1406
- label: "Altitude",
1407
- value: `${decodeResult.raw.altitude} feet`
1408
- });
1409
- }
1410
- static flightNumber(decodeResult, value) {
1411
- decodeResult.raw.flight_number = value;
1412
- }
1413
- static departureAirport(decodeResult, value) {
1414
- decodeResult.raw.departure_icao = value;
1415
- decodeResult.formatted.items.push({
1416
- type: "origin",
1417
- code: "ORG",
1418
- label: "Origin",
1419
- value: decodeResult.raw.departure_icao
1420
- });
1421
- }
1422
- static departureRunway(decodeResult, value) {
1423
- decodeResult.raw.departure_runway = value;
1424
- decodeResult.formatted.items.push({
1425
- type: "runway",
1426
- code: "DEPRWY",
1427
- label: "Departure Runway",
1428
- value: decodeResult.raw.departure_runway
1429
- });
1430
- }
1431
- static arrivalAirport(decodeResult, value) {
1432
- decodeResult.raw.arrival_icao = value;
1433
- decodeResult.formatted.items.push({
1434
- type: "destination",
1435
- code: "DST",
1436
- label: "Destination",
1437
- value: decodeResult.raw.arrival_icao
1438
- });
1439
- }
1440
- static eta(decodeResult, value) {
1441
- decodeResult.formatted.items.push({
1442
- type: "eta",
1443
- code: "ETA",
1444
- label: "Estimated Time of Arrival",
1445
- value: value.substring(0, 2) + ":" + value.substring(2, 4) + ":" + value.substring(4, 6)
1446
- });
1447
- }
1448
- static arrivalRunway(decodeResult, value) {
1449
- decodeResult.raw.arrival_runway = value;
1450
- decodeResult.formatted.items.push({
1451
- type: "runway",
1452
- label: "Arrival Runway",
1453
- value: decodeResult.raw.arrival_runway
1454
- });
1455
- }
1456
- static currentFuel(decodeResult, value) {
1457
- decodeResult.raw.fuel_on_board = value;
1458
- decodeResult.formatted.items.push({
1459
- type: "fuel_on_board",
1460
- code: "FOB",
1461
- label: "Fuel On Board",
1462
- value: decodeResult.raw.fuel_on_board.toString()
1463
- });
1464
- }
1465
- static remainingFuel(decodeResult, value) {
1466
- decodeResult.raw.fuel_remaining = value;
1467
- decodeResult.formatted.items.push({
1468
- type: "fuel_remaining",
1469
- label: "Fuel Remaining",
1470
- value: decodeResult.raw.fuel_remaining.toString()
1471
- });
1472
- }
1473
- static checksum(decodeResult, value) {
1474
- decodeResult.raw.checksum = Number("0x" + value);
1475
- decodeResult.formatted.items.push({
1476
- type: "message_checksum",
1477
- code: "CHECKSUM",
1478
- label: "Message Checksum",
1479
- value: "0x" + ("0000" + decodeResult.raw.checksum.toString(16)).slice(-4)
1480
- });
1481
- }
1482
- static groundspeed(decodeResult, value) {
1483
- decodeResult.raw.groundspeed = value;
1484
- decodeResult.formatted.items.push({
1485
- type: "aircraft_groundspeed",
1486
- code: "GSPD",
1487
- label: "Aircraft Groundspeed",
1488
- value: `${decodeResult.raw.groundspeed}`
1489
- });
1490
- }
1491
- static temperature(decodeResult, value) {
1492
- decodeResult.raw.outside_air_temperature = Number(value.substring(1)) * (value.charAt(0) === "M" ? -1 : 1);
1493
- decodeResult.formatted.items.push({
1494
- type: "outside_air_temperature",
1495
- code: "OATEMP",
1496
- label: "Outside Air Temperature (C)",
1497
- value: `${decodeResult.raw.outside_air_temperature}`
1498
- });
1499
- }
1500
- static unknown(decodeResult, value) {
1501
- decodeResult.remaining.text += "," + value;
1502
- }
1503
- };
1504
-
1505
- // lib/utils/route_utils.ts
1506
- var RouteUtils = class _RouteUtils {
1507
- static routeToString(route) {
1508
- let str = "";
1509
- if (route.name) {
1510
- str += route.name;
1511
- }
1512
- if (route.runway) {
1513
- str += `(${route.runway})`;
1514
- }
1515
- if (str.length !== 0 && route.waypoints && route.waypoints.length === 1) {
1516
- str += " starting at ";
1517
- } else if (str.length !== 0 && route.waypoints) {
1518
- str += ": ";
1519
- }
1520
- if (route.waypoints) {
1521
- str += _RouteUtils.waypointsToString(route.waypoints);
1522
- }
1523
- return str;
1524
- }
1525
- static waypointToString(waypoint) {
1526
- let s = waypoint.name;
1527
- if (waypoint.latitude && waypoint.longitude) {
1528
- s += `(${CoordinateUtils.coordinateString({ latitude: waypoint.latitude, longitude: waypoint.longitude })})`;
1529
- }
1530
- if (waypoint.offset) {
1531
- s += `[${waypoint.offset.bearing}\xB0 ${waypoint.offset.distance}nm]`;
1532
- }
1533
- if (waypoint.time && waypoint.timeFormat) {
1534
- s += `@${_RouteUtils.timestampToString(waypoint.time, waypoint.timeFormat)}`;
1535
- }
1536
- return s;
1537
- }
1538
- static getWaypoint(leg) {
1539
- const regex = leg.match(/^([A-Z]+)(\d{3})-(\d{4})$/);
1540
- if (regex?.length == 4) {
1541
- return { name: regex[1], offset: { bearing: parseInt(regex[2]), distance: parseInt(regex[3]) / 10 } };
1542
- }
1543
- const waypoint = leg.split(",");
1544
- if (waypoint.length == 2) {
1545
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(waypoint[1]);
1546
- if (position) {
1547
- return { name: waypoint[0], latitude: position.latitude, longitude: position.longitude };
1548
- }
1549
- }
1550
- if (leg.length == 13 || leg.length == 14) {
1551
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(leg);
1552
- const name = waypoint.length == 2 ? waypoint[0] : "";
1553
- if (position) {
1554
- return { name, latitude: position.latitude, longitude: position.longitude };
1555
- }
1556
- }
1557
- return { name: leg };
1558
- }
1559
- // move out if we want public
1560
- static timestampToString(time, format) {
1561
- const date = new Date(time * 1e3);
1562
- if (format == "tod") {
1563
- return date.toISOString().slice(11, 19);
1564
- }
1565
- return date.toISOString().slice(0, -5) + "Z";
1566
- }
1567
- static waypointsToString(waypoints) {
1568
- let str = waypoints.map((x) => _RouteUtils.waypointToString(x)).join(" > ").replaceAll("> >", ">>");
1569
- if (str.startsWith(" > ")) {
1570
- str = ">>" + str.slice(2);
1571
- }
1572
- return str;
1573
- }
1574
- };
1575
-
1576
1686
  // lib/utils/flight_plan_utils.ts
1577
1687
  var FlightPlanUtils = class _FlightPlanUtils {
1578
1688
  /**
@@ -2249,6 +2359,60 @@ function processUnknown2(decodeResult, value) {
2249
2359
  decodeResult.remaining.text += value;
2250
2360
  }
2251
2361
 
2362
+ // lib/plugins/Label_HX.ts
2363
+ var Label_HX = class extends DecoderPlugin {
2364
+ name = "label-hx";
2365
+ qualifiers() {
2366
+ return {
2367
+ labels: ["HX"],
2368
+ preambles: ["RA FMT LOCATION", "RA FMT 43"]
2369
+ };
2370
+ }
2371
+ decode(message, options = {}) {
2372
+ const decodeResult = this.defaultResult();
2373
+ decodeResult.decoder.name = this.name;
2374
+ decodeResult.message = message;
2375
+ decodeResult.formatted.description = "Undelivered Uplink Report";
2376
+ const parts = message.text.split(" ");
2377
+ decodeResult.decoded = true;
2378
+ if (parts[2] === "LOCATION") {
2379
+ let latdir = parts[3].substring(0, 1);
2380
+ let latdeg = Number(parts[3].substring(1, 3));
2381
+ let latmin = Number(parts[3].substring(3, 7));
2382
+ let londir = parts[4].substring(0, 1);
2383
+ let londeg = Number(parts[4].substring(1, 4));
2384
+ let lonmin = Number(parts[4].substring(4, 8));
2385
+ decodeResult.raw.position = {
2386
+ latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
2387
+ longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
2388
+ };
2389
+ decodeResult.remaining.text = parts.slice(5).join(" ");
2390
+ } else if (parts[2] === "43") {
2391
+ ResultFormatter.departureAirport(decodeResult, parts[3]);
2392
+ decodeResult.remaining.text = parts.slice(4).join(" ");
2393
+ } else {
2394
+ decodeResult.decoded = false;
2395
+ }
2396
+ if (decodeResult.raw.position) {
2397
+ decodeResult.formatted.items.push({
2398
+ type: "aircraft_position",
2399
+ code: "POS",
2400
+ label: "Aircraft Position",
2401
+ value: CoordinateUtils.coordinateString(decodeResult.raw.position)
2402
+ });
2403
+ }
2404
+ if (decodeResult.decoded) {
2405
+ if (decodeResult.remaining.text === "")
2406
+ decodeResult.decoder.decodeLevel = "full";
2407
+ else
2408
+ decodeResult.decoder.decodeLevel = "partial";
2409
+ } else {
2410
+ decodeResult.decoder.decodeLevel = "none";
2411
+ }
2412
+ return decodeResult;
2413
+ }
2414
+ };
2415
+
2252
2416
  // lib/plugins/Label_SQ.ts
2253
2417
  var Label_SQ = class extends DecoderPlugin {
2254
2418
  name = "label-sq";
@@ -2289,11 +2453,13 @@ var Label_SQ = class extends DecoderPlugin {
2289
2453
  decodeResult.formatted.items = [
2290
2454
  {
2291
2455
  type: "network",
2456
+ code: "NETT",
2292
2457
  label: "Network",
2293
2458
  value: formattedNetwork
2294
2459
  },
2295
2460
  {
2296
2461
  type: "version",
2462
+ code: "VER",
2297
2463
  label: "Version",
2298
2464
  value: decodeResult.raw.version
2299
2465
  }
@@ -2302,6 +2468,7 @@ var Label_SQ = class extends DecoderPlugin {
2302
2468
  if (decodeResult.raw.groundStation.icaoCode && decodeResult.raw.groundStation.number) {
2303
2469
  decodeResult.formatted.items.push({
2304
2470
  type: "ground_station",
2471
+ code: "GNDSTN",
2305
2472
  label: "Ground Station",
2306
2473
  value: `${decodeResult.raw.groundStation.icaoCode}${decodeResult.raw.groundStation.number}`
2307
2474
  });
@@ -2309,6 +2476,7 @@ var Label_SQ = class extends DecoderPlugin {
2309
2476
  if (decodeResult.raw.groundStation.iataCode) {
2310
2477
  decodeResult.formatted.items.push({
2311
2478
  type: "iataCode",
2479
+ code: "IATA",
2312
2480
  label: "IATA",
2313
2481
  value: decodeResult.raw.groundStation.iataCode
2314
2482
  });
@@ -2316,6 +2484,7 @@ var Label_SQ = class extends DecoderPlugin {
2316
2484
  if (decodeResult.raw.groundStation.icaoCode) {
2317
2485
  decodeResult.formatted.items.push({
2318
2486
  type: "icaoCode",
2487
+ code: "ICAO",
2319
2488
  label: "ICAO",
2320
2489
  value: decodeResult.raw.groundStation.icaoCode
2321
2490
  });
@@ -2323,6 +2492,7 @@ var Label_SQ = class extends DecoderPlugin {
2323
2492
  if (decodeResult.raw.groundStation.coordinates.latitude) {
2324
2493
  decodeResult.formatted.items.push({
2325
2494
  type: "coordinates",
2495
+ code: "COORD",
2326
2496
  label: "Ground Station Location",
2327
2497
  value: `${decodeResult.raw.groundStation.coordinates.latitude}, ${decodeResult.raw.groundStation.coordinates.longitude}`
2328
2498
  });
@@ -2330,6 +2500,7 @@ var Label_SQ = class extends DecoderPlugin {
2330
2500
  if (decodeResult.raw.groundStation.airport) {
2331
2501
  decodeResult.formatted.items.push({
2332
2502
  type: "airport",
2503
+ code: "APT",
2333
2504
  label: "Airport",
2334
2505
  value: `${decodeResult.raw.groundStation.airport.name} (${decodeResult.raw.groundStation.airport.icao}) in ${decodeResult.raw.groundStation.airport.location}`
2335
2506
  });
@@ -2338,6 +2509,7 @@ var Label_SQ = class extends DecoderPlugin {
2338
2509
  if (decodeResult.raw.vdlFrequency) {
2339
2510
  decodeResult.formatted.items.push({
2340
2511
  type: "vdlFrequency",
2512
+ code: "VDLFRQ",
2341
2513
  label: "VDL Frequency",
2342
2514
  value: `${decodeResult.raw.vdlFrequency} MHz`
2343
2515
  });
@@ -2494,31 +2666,48 @@ var Label_QQ = class extends DecoderPlugin {
2494
2666
  decode(message, options = {}) {
2495
2667
  const decodeResult = this.defaultResult();
2496
2668
  decodeResult.decoder.name = this.name;
2497
- decodeResult.raw.origin = message.text.substring(0, 4);
2498
- decodeResult.raw.destination = message.text.substring(4, 8);
2499
- decodeResult.raw.wheels_off = message.text.substring(8, 12);
2500
- decodeResult.remaining.text = message.text.substring(12);
2669
+ decodeResult.message = message;
2501
2670
  decodeResult.formatted.description = "OFF Report";
2502
- decodeResult.formatted.items = [
2503
- {
2504
- type: "origin",
2505
- code: "ORG",
2506
- label: "Origin",
2507
- value: decodeResult.raw.origin
2508
- },
2509
- {
2510
- type: "destination",
2511
- code: "DST",
2512
- label: "Destination",
2513
- value: decodeResult.raw.destination
2514
- },
2515
- {
2516
- type: "wheels_off",
2517
- code: "WOFF",
2518
- label: "Wheels OFF",
2519
- value: decodeResult.raw.wheels_off
2671
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
2672
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
2673
+ decodeResult.raw.wheels_off = message.text.substring(8, 12);
2674
+ if (message.text.substring(12, 19) === "\r\n001FE") {
2675
+ decodeResult.raw.day_of_month = message.text.substring(19, 21);
2676
+ decodeResult.raw.wheels_off = message.text.substring(21, 27);
2677
+ let latdir = message.text.substring(27, 28);
2678
+ let latdeg = Number(message.text.substring(28, 30));
2679
+ let latmin = Number(message.text.substring(30, 34));
2680
+ let londir = message.text.substring(34, 35);
2681
+ let londeg = Number(message.text.substring(35, 38));
2682
+ let lonmin = Number(message.text.substring(38, 42));
2683
+ decodeResult.raw.position = {
2684
+ latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
2685
+ longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
2686
+ };
2687
+ decodeResult.remaining.text = message.text.substring(42, 45);
2688
+ if (decodeResult.remaining.text !== "---") {
2689
+ ResultFormatter.groundspeed(decodeResult, message.text.substring(45, 48));
2690
+ } else {
2691
+ ResultFormatter.unknown(decodeResult, message.text.substring(45, 48));
2520
2692
  }
2521
- ];
2693
+ ResultFormatter.unknown(decodeResult, message.text.substring(48));
2694
+ } else {
2695
+ decodeResult.remaining.text = message.text.substring(12);
2696
+ }
2697
+ decodeResult.formatted.items.push({
2698
+ type: "wheels_off",
2699
+ code: "WOFF",
2700
+ label: "Wheels OFF",
2701
+ value: decodeResult.raw.wheels_off
2702
+ });
2703
+ if (decodeResult.raw.position) {
2704
+ decodeResult.formatted.items.push({
2705
+ type: "aircraft_position",
2706
+ code: "POS",
2707
+ label: "Aircraft Position",
2708
+ value: CoordinateUtils.coordinateString(decodeResult.raw.position)
2709
+ });
2710
+ }
2522
2711
  decodeResult.decoded = true;
2523
2712
  if (decodeResult.remaining.text === "")
2524
2713
  decodeResult.decoder.decodeLevel = "full";
@@ -3341,6 +3530,9 @@ var MessageDecoder = class {
3341
3530
  this.debug = false;
3342
3531
  this.registerPlugin(new Label_ColonComma(this));
3343
3532
  this.registerPlugin(new Label_5Z(this));
3533
+ this.registerPlugin(new Label_10_LDR(this));
3534
+ this.registerPlugin(new Label_10_POS(this));
3535
+ this.registerPlugin(new Label_10_Slash(this));
3344
3536
  this.registerPlugin(new Label_12_N_Space(this));
3345
3537
  this.registerPlugin(new Label_15(this));
3346
3538
  this.registerPlugin(new Label_15_FST(this));
@@ -3361,6 +3553,7 @@ var MessageDecoder = class {
3361
3553
  this.registerPlugin(new Label_H1_OHMA(this));
3362
3554
  this.registerPlugin(new Label_H1_POS(this));
3363
3555
  this.registerPlugin(new Label_H1_WRN(this));
3556
+ this.registerPlugin(new Label_HX(this));
3364
3557
  this.registerPlugin(new Label_80(this));
3365
3558
  this.registerPlugin(new Label_8E(this));
3366
3559
  this.registerPlugin(new Label_1M_Slash(this));