@airframes/acars-decoder 1.6.12 → 1.6.14

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
@@ -129,7 +129,7 @@ var DecoderPlugin = class {
129
129
  };
130
130
 
131
131
  // lib/utils/coordinate_utils.ts
132
- var CoordinateUtils = class {
132
+ var CoordinateUtils = class _CoordinateUtils {
133
133
  /**
134
134
  * Decode a string of coordinates into an object with latitude and longitude in millidegrees
135
135
  * @param stringCoords - The string of coordinates to decode
@@ -146,8 +146,8 @@ var CoordinateUtils = class {
146
146
  longitudeChars = stringCoords.substring(8, 14);
147
147
  }
148
148
  if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
149
- results.latitude = Number(stringCoords.substring(1, 6)) / 1e3 * (firstChar === "S" ? -1 : 1);
150
- results.longitude = Number(longitudeChars) / 1e3 * (middleChar === "W" ? -1 : 1);
149
+ results.latitude = Number(stringCoords.substring(1, 6)) / 1e3 * _CoordinateUtils.getDirection(firstChar);
150
+ results.longitude = Number(longitudeChars) / 1e3 * _CoordinateUtils.getDirection(middleChar);
151
151
  } else {
152
152
  return;
153
153
  }
@@ -173,8 +173,8 @@ var CoordinateUtils = class {
173
173
  const lonDeg = Math.trunc(Number(longitudeChars) / 1e3);
174
174
  const lonMin = Number(longitudeChars) % 1e3 / 10;
175
175
  if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
176
- results.latitude = (latDeg + latMin / 60) * (firstChar === "S" ? -1 : 1);
177
- results.longitude = (lonDeg + lonMin / 60) * (middleChar === "W" ? -1 : 1);
176
+ results.latitude = (latDeg + latMin / 60) * _CoordinateUtils.getDirection(firstChar);
177
+ results.longitude = (lonDeg + lonMin / 60) * _CoordinateUtils.getDirection(middleChar);
178
178
  } else {
179
179
  return;
180
180
  }
@@ -281,6 +281,15 @@ var RouteUtils = class _RouteUtils {
281
281
 
282
282
  // lib/utils/result_formatter.ts
283
283
  var ResultFormatter = class {
284
+ static route(decodeResult, route) {
285
+ decodeResult.raw.route = route;
286
+ decodeResult.formatted.items.push({
287
+ type: "aircraft_route",
288
+ code: "ROUTE",
289
+ label: "Aircraft Route",
290
+ value: RouteUtils.routeToString(route)
291
+ });
292
+ }
284
293
  static state_change(decodeResult, from, to) {
285
294
  decodeResult.raw.state_change = {
286
295
  from,
@@ -317,6 +326,9 @@ var ResultFormatter = class {
317
326
  });
318
327
  }
319
328
  static position(decodeResult, value) {
329
+ if (!value || isNaN(value.latitude) || isNaN(value.longitude)) {
330
+ return;
331
+ }
320
332
  decodeResult.raw.position = value;
321
333
  decodeResult.formatted.items.push({
322
334
  type: "aircraft_position",
@@ -553,17 +565,50 @@ var ResultFormatter = class {
553
565
  value: DateTimeUtils.timestampToString(time, "tod")
554
566
  });
555
567
  }
556
- static text(decodeResult, text2) {
557
- decodeResult.raw.text = text2;
568
+ static day(decodeResult, day) {
569
+ decodeResult.raw.day_of_month = day;
570
+ decodeResult.formatted.items.push({
571
+ type: "day_of_month",
572
+ code: "MSG_DAY",
573
+ label: "Day of Month",
574
+ value: `${day}`
575
+ });
576
+ }
577
+ static departureDay(decodeResult, day) {
578
+ decodeResult.raw.departure_day_of_month = day;
579
+ decodeResult.formatted.items.push({
580
+ type: "day_of_month",
581
+ code: "DEP_DAY",
582
+ label: "Departure Day",
583
+ value: `${day}`
584
+ });
585
+ }
586
+ static arrivalDay(decodeResult, day) {
587
+ decodeResult.raw.arrival_day_of_month = day;
588
+ decodeResult.formatted.items.push({
589
+ type: "day_of_month",
590
+ code: "ARR_DAY",
591
+ label: "Arrival Day",
592
+ value: `${day}`
593
+ });
594
+ }
595
+ static text(decodeResult, text) {
596
+ decodeResult.raw.text = text;
558
597
  decodeResult.formatted.items.push({
559
598
  type: "text",
560
599
  code: "TEXT",
561
600
  label: "Text Message",
562
- value: text2
601
+ value: text
563
602
  });
564
603
  }
565
- static unknown(decodeResult, value) {
566
- decodeResult.remaining.text += "," + value;
604
+ static unknown(decodeResult, value, sep = ",") {
605
+ if (!decodeResult.remaining.text)
606
+ decodeResult.remaining.text = value;
607
+ else
608
+ decodeResult.remaining.text += sep + value;
609
+ }
610
+ static unknownArr(decodeResult, value, sep = ",") {
611
+ this.unknown(decodeResult, value.join(sep), sep);
567
612
  }
568
613
  };
569
614
 
@@ -639,14 +684,14 @@ var Label_5Z_Slash = class extends DecoderPlugin {
639
684
  decodeResult.raw.day_of_month = Number(info[3]);
640
685
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
641
686
  ResultFormatter.arrivalRunway(decodeResult, info[5].slice(1));
642
- decodeResult.remaining.text = data.slice(3).join("/");
687
+ ResultFormatter.unknownArr(decodeResult, data.slice(3), "/");
643
688
  } else if (type === "B3") {
644
689
  ResultFormatter.departureAirport(decodeResult, header[1].substring(0, 3), "IATA");
645
690
  ResultFormatter.arrivalAirport(decodeResult, header[1].substring(3), "IATA");
646
691
  decodeResult.raw.day_of_month = Number(header[2]);
647
692
  ResultFormatter.arrivalRunway(decodeResult, header[3].slice(1));
648
693
  if (header.length > 4) {
649
- decodeResult.remaining.text = header.slice(4).join(" ");
694
+ ResultFormatter.unknownArr(decodeResult, header.slice(4), "/");
650
695
  }
651
696
  } else if (type === "C3" && data[1] === "C3 GATE REQ ") {
652
697
  const info = data[2].split(" ");
@@ -654,7 +699,7 @@ var Label_5Z_Slash = class extends DecoderPlugin {
654
699
  ResultFormatter.arrivalAirport(decodeResult, info[2]);
655
700
  decodeResult.raw.day_of_month = Number(info[3]);
656
701
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(info[4]));
657
- decodeResult.remaining.text = info.slice(5).join(" ");
702
+ ResultFormatter.unknownArr(decodeResult, info.slice(5), " ");
658
703
  } else if (type === "C3") {
659
704
  ResultFormatter.departureAirport(decodeResult, header[1].substring(0, 3), "IATA");
660
705
  ResultFormatter.arrivalAirport(decodeResult, header[1].substring(3), "IATA");
@@ -666,7 +711,7 @@ var Label_5Z_Slash = class extends DecoderPlugin {
666
711
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(airports[4]));
667
712
  const estimates = data[3].split(" ");
668
713
  ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(estimates[1] + "00"));
669
- decodeResult.remaining.text = estimates[2];
714
+ ResultFormatter.unknown(decodeResult, estimates[2]);
670
715
  } else {
671
716
  if (options.debug) {
672
717
  console.log(`Decoder: Unkown 5Z RDC format: ${message.text}`);
@@ -678,7 +723,7 @@ var Label_5Z_Slash = class extends DecoderPlugin {
678
723
  if (options.debug) {
679
724
  console.log(`Decoder: Unknown 5Z message: ${message.text}`);
680
725
  }
681
- decodeResult.remaining.text = message.text;
726
+ ResultFormatter.unknown(decodeResult, message.text);
682
727
  decodeResult.decoded = false;
683
728
  decodeResult.decoder.decodeLevel = "none";
684
729
  }
@@ -706,7 +751,7 @@ var Label_10_LDR = class extends DecoderPlugin {
706
751
  if (options.debug) {
707
752
  console.log(`Decoder: Unknown 10 message: ${message.text}`);
708
753
  }
709
- decodeResult.remaining.text = message.text;
754
+ ResultFormatter.unknown(decodeResult, message.text);
710
755
  decodeResult.decoded = false;
711
756
  decodeResult.decoder.decodeLevel = "none";
712
757
  return decodeResult;
@@ -727,7 +772,7 @@ var Label_10_LDR = class extends DecoderPlugin {
727
772
  if (altRwy != "") {
728
773
  ResultFormatter.alternateRunway(decodeResult, altRwy);
729
774
  }
730
- decodeResult.remaining.text = [...parts.slice(0, 5), ...parts.slice(15)].join(",");
775
+ ResultFormatter.unknownArr(decodeResult, [...parts.slice(0, 5), ...parts.slice(15)]);
731
776
  decodeResult.decoded = true;
732
777
  decodeResult.decoder.decodeLevel = "partial";
733
778
  return decodeResult;
@@ -754,7 +799,7 @@ var Label_10_POS = class extends DecoderPlugin {
754
799
  if (options.debug) {
755
800
  console.log(`Decoder: Unknown 10 message: ${message.text}`);
756
801
  }
757
- decodeResult.remaining.text = message.text;
802
+ ResultFormatter.unknown(decodeResult, message.text);
758
803
  decodeResult.decoded = false;
759
804
  decodeResult.decoder.decodeLevel = "none";
760
805
  return decodeResult;
@@ -767,7 +812,7 @@ var Label_10_POS = class extends DecoderPlugin {
767
812
  };
768
813
  ResultFormatter.position(decodeResult, position);
769
814
  ResultFormatter.altitude(decodeResult, Number(parts[7]));
770
- decodeResult.remaining.text = [parts[0], ...parts.slice(3, 7), ...parts.slice(8)].join(",");
815
+ ResultFormatter.unknownArr(decodeResult, [parts[0], ...parts.slice(3, 7), ...parts.slice(8)]);
771
816
  decodeResult.decoded = true;
772
817
  decodeResult.decoder.decodeLevel = "partial";
773
818
  return decodeResult;
@@ -794,7 +839,7 @@ var Label_10_Slash = class extends DecoderPlugin {
794
839
  if (options.debug) {
795
840
  console.log(`Decoder: Unknown 10 message: ${message.text}`);
796
841
  }
797
- decodeResult.remaining.text = message.text;
842
+ ResultFormatter.unknown(decodeResult, message.text);
798
843
  decodeResult.decoded = false;
799
844
  decodeResult.decoder.decodeLevel = "none";
800
845
  return decodeResult;
@@ -821,17 +866,11 @@ var Label_10_Slash = class extends DecoderPlugin {
821
866
  time: DateTimeUtils.convertHHMMSSToTod(parts[15] + "00"),
822
867
  timeFormat: "tod"
823
868
  }];
824
- decodeResult.raw.route = { waypoints };
825
- decodeResult.formatted.items.push({
826
- type: "aircraft_route",
827
- code: "ROUTE",
828
- label: "Aircraft Route",
829
- value: RouteUtils.routeToString(decodeResult.raw.route)
830
- });
869
+ ResultFormatter.route(decodeResult, { waypoints });
831
870
  if (parts[16]) {
832
871
  ResultFormatter.departureAirport(decodeResult, parts[16]);
833
872
  }
834
- decodeResult.remaining.text = [parts[3], parts[4], ...parts.slice(9, 11), ...parts.slice(17)].join("/");
873
+ ResultFormatter.unknownArr(decodeResult, [parts[3], parts[4], ...parts.slice(9, 11), ...parts.slice(17)], "/");
835
874
  decodeResult.decoded = true;
836
875
  decodeResult.decoder.decodeLevel = "partial";
837
876
  return decodeResult;
@@ -853,35 +892,29 @@ var Label_12_N_Space = class extends DecoderPlugin {
853
892
  decodeResult.formatted.description = "Position Report";
854
893
  decodeResult.message = message;
855
894
  const variant1Regex = /^(?<lat>[NS])\s(?<lat_coord>.*),(?<long>[EW])\s*(?<long_coord>.*),(?<alt>.*),(?<unkwn1>.*),\s*(?<unkwn2>.*),.(?<airframe>.*),(?<unkwn3>.*)$/;
856
- let results;
857
- if (results = message.text.match(variant1Regex)) {
895
+ let results = message.text.match(variant1Regex);
896
+ if (results?.groups) {
858
897
  if (options.debug) {
859
898
  console.log(`Label 12 N : results`);
860
899
  console.log(results);
861
900
  }
862
- decodeResult.raw.position = {
901
+ ResultFormatter.position(decodeResult, {
863
902
  latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
864
903
  longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
865
- };
866
- const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
867
- decodeResult.formatted.items.push({
868
- type: "aircraft_position",
869
- code: "POS",
870
- label: "Aircraft Position",
871
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
872
904
  });
905
+ const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
873
906
  ResultFormatter.altitude(decodeResult, altitude);
874
- decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}, ${results.groups.unkwn3}`;
907
+ ResultFormatter.unknownArr(decodeResult, [results.groups.unkwn1, results.groups.unkwn2, results.groups.unkwn3]);
875
908
  decodeResult.decoded = true;
876
909
  decodeResult.decoder.decodeLevel = "partial";
877
- } else {
878
- if (options.debug) {
879
- console.log(`Decoder: Unknown 12 message: ${message.text}`);
880
- }
881
- decodeResult.remaining.text = message.text;
882
- decodeResult.decoded = false;
883
- decodeResult.decoder.decodeLevel = "none";
910
+ return decodeResult;
884
911
  }
912
+ if (options.debug) {
913
+ console.log(`Decoder: Unknown 12 message: ${message.text}`);
914
+ }
915
+ ResultFormatter.unknown(decodeResult, message.text);
916
+ decodeResult.decoded = false;
917
+ decodeResult.decoder.decodeLevel = "none";
885
918
  return decodeResult;
886
919
  }
887
920
  };
@@ -908,12 +941,11 @@ var Label_13Through18_Slash = class extends DecoderPlugin {
908
941
  if (options?.debug) {
909
942
  console.log(`Decoder: Unknown OOOI message: ${message.text}`);
910
943
  }
911
- decodeResult.remaining.text = message.text;
944
+ ResultFormatter.unknown(decodeResult, message.text);
912
945
  decodeResult.decoded = false;
913
946
  decodeResult.decoder.decodeLevel = "none";
914
947
  return decodeResult;
915
948
  }
916
- decodeResult.remaining.text = "";
917
949
  const data = parts[2].split(" ");
918
950
  ResultFormatter.departureAirport(decodeResult, data[1]);
919
951
  ResultFormatter.arrivalAirport(decodeResult, data[2]);
@@ -929,7 +961,7 @@ var Label_13Through18_Slash = class extends DecoderPlugin {
929
961
  ResultFormatter.in(decodeResult, time);
930
962
  }
931
963
  if (parts.length === 7) {
932
- decodeResult.remaining.text += parts.slice(4).join("/");
964
+ ResultFormatter.unknownArr(decodeResult, parts.slice(4), "/");
933
965
  }
934
966
  for (let i = 1; i < lines.length; i++) {
935
967
  if (lines[i].startsWith("/LOC")) {
@@ -943,11 +975,9 @@ var Label_13Through18_Slash = class extends DecoderPlugin {
943
975
  longitude: CoordinateUtils.getDirection(location[1][0]) * CoordinateUtils.dmsToDecimalDegrees(Number(location[1].substring(1, 4)), Number(location[1].substring(4, 6)), Number(location[1].substring(6, 8)))
944
976
  };
945
977
  }
946
- if (!isNaN(position.latitude) && !isNaN(position.longitude)) {
947
- ResultFormatter.position(decodeResult, position);
948
- }
978
+ ResultFormatter.position(decodeResult, position);
949
979
  } else {
950
- decodeResult.remaining.text += "\r\n" + lines[i];
980
+ ResultFormatter.unknown(decodeResult, lines[i], "\r\n");
951
981
  }
952
982
  }
953
983
  decodeResult.decoded = true;
@@ -992,16 +1022,8 @@ var Label_15 = class extends DecoderPlugin {
992
1022
  decodeResult.formatted.description = "Position Report";
993
1023
  const twoZeeRegex = /^\(2(?<between>.+)\(Z$/;
994
1024
  const results = message.text.match(twoZeeRegex);
995
- if (results) {
996
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.between.substr(0, 13));
997
- if (decodeResult.raw.position) {
998
- decodeResult.formatted.items.push({
999
- type: "position",
1000
- code: "POS",
1001
- label: "Position",
1002
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1003
- });
1004
- }
1025
+ if (results?.groups) {
1026
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.between.substr(0, 13)));
1005
1027
  }
1006
1028
  decodeResult.decoded = true;
1007
1029
  decodeResult.decoder.decodeLevel = "partial";
@@ -1025,31 +1047,23 @@ var Label_15_FST = class extends DecoderPlugin {
1025
1047
  decodeResult.message = message;
1026
1048
  const parts = message.text.split(" ");
1027
1049
  const header = parts[0];
1028
- decodeResult.raw.departure_icao = header.substring(5, 9);
1029
- decodeResult.raw.arrival_icao = header.substring(9, 13);
1030
1050
  const stringCoords = header.substring(13);
1031
1051
  const firstChar = stringCoords.substring(0, 1);
1032
1052
  const middleChar = stringCoords.substring(7, 8);
1033
1053
  decodeResult.raw.position = {};
1034
1054
  if ((firstChar === "N" || firstChar === "S") && (middleChar === "W" || middleChar === "E")) {
1035
- decodeResult.raw.position.latitude = Number(stringCoords.substring(1, 7)) / 1e4 * (firstChar === "S" ? -1 : 1);
1036
- decodeResult.raw.position.longitude = Number(stringCoords.substring(8, 15)) / 1e4 * (middleChar === "W" ? -1 : 1);
1037
- decodeResult.raw.altitude = Number(stringCoords.substring(15)) * 100;
1055
+ const lat = Number(stringCoords.substring(1, 7)) / 1e4 * (firstChar === "S" ? -1 : 1);
1056
+ const lon = Number(stringCoords.substring(8, 15)) / 1e4 * (middleChar === "W" ? -1 : 1);
1057
+ ResultFormatter.position(decodeResult, { latitude: lat, longitude: lon });
1058
+ ResultFormatter.altitude(decodeResult, Number(stringCoords.substring(15)) * 100);
1038
1059
  } else {
1039
1060
  decodeResult.decoded = false;
1040
1061
  decodeResult.decoder.decodeLevel = "none";
1041
1062
  return decodeResult;
1042
1063
  }
1043
- decodeResult.formatted.items.push({
1044
- type: "aircraft_position",
1045
- code: "POS",
1046
- label: "Aircraft Position",
1047
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1048
- });
1049
- ResultFormatter.altitude(decodeResult, decodeResult.raw.altitude);
1050
- ResultFormatter.departureAirport(decodeResult, decodeResult.raw.departure_icao);
1051
- ResultFormatter.arrivalAirport(decodeResult, decodeResult.raw.arrival_icao);
1052
- decodeResult.remaining.text = parts.slice(1).join(" ");
1064
+ ResultFormatter.departureAirport(decodeResult, header.substring(5, 9));
1065
+ ResultFormatter.arrivalAirport(decodeResult, header.substring(9, 13));
1066
+ ResultFormatter.unknownArr(decodeResult, parts.slice(1), " ");
1053
1067
  decodeResult.decoded = true;
1054
1068
  decodeResult.decoder.decodeLevel = "partial";
1055
1069
  return decodeResult;
@@ -1072,52 +1086,45 @@ var Label_16_N_Space = class extends DecoderPlugin {
1072
1086
  decodeResult.message = message;
1073
1087
  let variant1Regex = /^(?<lat>[NS])\s(?<lat_coord>.*),(?<long>[EW])\s*(?<long_coord>.*),(?<alt>.*),(?<unkwn1>.*),\s*(?<unkwn2>.*)$/;
1074
1088
  let variant2Regex = /^(?<lat>[NS])\s(?<lat_coord>.*)\/(?<long>[EW])\s*(?<long_coord>.*)$/;
1075
- let results;
1076
- if (results = message.text.match(variant1Regex)) {
1089
+ let results = message.text.match(variant1Regex);
1090
+ if (results?.groups) {
1077
1091
  if (options.debug) {
1078
1092
  console.log(`Label 16 N : results`);
1079
1093
  console.log(results);
1080
1094
  }
1081
- decodeResult.raw.position = {
1095
+ let pos = {
1082
1096
  latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
1083
1097
  longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
1084
1098
  };
1085
1099
  const altitude = results.groups.alt == "GRD" || results.groups.alt == "***" ? 0 : Number(results.groups.alt);
1086
- decodeResult.formatted.items.push({
1087
- type: "aircraft_position",
1088
- code: "POS",
1089
- label: "Aircraft Position",
1090
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1091
- });
1100
+ ResultFormatter.position(decodeResult, pos);
1092
1101
  ResultFormatter.altitude(decodeResult, altitude);
1093
- decodeResult.remaining.text = `,${results.groups.unkwn1} ,${results.groups.unkwn2}`;
1102
+ ResultFormatter.unknownArr(decodeResult, [results.groups.unkwn1, results.groups.unkwn2]);
1094
1103
  decodeResult.decoded = true;
1095
1104
  decodeResult.decoder.decodeLevel = "partial";
1096
- } else if (results = message.text.match(variant2Regex)) {
1105
+ return decodeResult;
1106
+ }
1107
+ results = message.text.match(variant2Regex);
1108
+ if (results?.groups) {
1097
1109
  if (options.debug) {
1098
1110
  console.log(`Label 16 N : results`);
1099
1111
  console.log(results);
1100
1112
  }
1101
- decodeResult.raw.position = {
1113
+ let pos = {
1102
1114
  latitude: Number(results.groups.lat_coord) * (results.groups.lat == "N" ? 1 : -1),
1103
1115
  longitude: Number(results.groups.long_coord) * (results.groups.long == "E" ? 1 : -1)
1104
1116
  };
1105
- decodeResult.formatted.items.push({
1106
- type: "aircraft_position",
1107
- code: "POS",
1108
- label: "Aircraft Position",
1109
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1110
- });
1117
+ ResultFormatter.position(decodeResult, pos);
1111
1118
  decodeResult.decoded = true;
1112
1119
  decodeResult.decoder.decodeLevel = "full";
1113
- } else {
1114
- if (options.debug) {
1115
- console.log(`Decoder: Unknown 16 message: ${message.text}`);
1116
- }
1117
- decodeResult.remaining.text = message.text;
1118
- decodeResult.decoded = false;
1119
- decodeResult.decoder.decodeLevel = "none";
1120
+ return decodeResult;
1121
+ }
1122
+ if (options.debug) {
1123
+ console.log(`Decoder: Unknown 16 message: ${message.text}`);
1120
1124
  }
1125
+ ResultFormatter.unknown(decodeResult, message.text);
1126
+ decodeResult.decoded = false;
1127
+ decodeResult.decoder.decodeLevel = "none";
1121
1128
  return decodeResult;
1122
1129
  }
1123
1130
  };
@@ -1156,6 +1163,265 @@ var Label_1M_Slash = class extends DecoderPlugin {
1156
1163
  }
1157
1164
  };
1158
1165
 
1166
+ // lib/plugins/Label_1L_3-line.ts
1167
+ var Label_1L_3Line = class extends DecoderPlugin {
1168
+ // eslint-disable-line camelcase
1169
+ name = "label-1l-3-line";
1170
+ qualifiers() {
1171
+ return {
1172
+ labels: ["1L"]
1173
+ };
1174
+ }
1175
+ decode(message, options = {}) {
1176
+ const decodeResult = this.defaultResult();
1177
+ decodeResult.decoder.name = this.name;
1178
+ decodeResult.formatted.description = "Position Report";
1179
+ decodeResult.message = message;
1180
+ const lines = message.text.split("\r\n");
1181
+ if (lines.length !== 3) {
1182
+ if (options.debug) {
1183
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1184
+ }
1185
+ decodeResult.remaining.text = message.text;
1186
+ decodeResult.decoded = false;
1187
+ decodeResult.decoder.decodeLevel = "none";
1188
+ return decodeResult;
1189
+ }
1190
+ const parts = message.text.replaceAll("\r\n", "/").split("/");
1191
+ const data = /* @__PURE__ */ new Map();
1192
+ data.set("", parts[0]);
1193
+ for (let i = 1; i < parts.length; i++) {
1194
+ const part = parts[i].split(" ");
1195
+ data.set(part[0], part.slice(1).join(" "));
1196
+ }
1197
+ const dep = data.get("DEP");
1198
+ if (dep) {
1199
+ ResultFormatter.departureAirport(decodeResult, dep);
1200
+ data.delete("DEP");
1201
+ }
1202
+ const des = data.get("DES");
1203
+ if (des) {
1204
+ ResultFormatter.arrivalAirport(decodeResult, des);
1205
+ data.delete("DES");
1206
+ }
1207
+ const eta = data.get("ETA");
1208
+ if (eta) {
1209
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta + "00"));
1210
+ data.delete("ETA");
1211
+ }
1212
+ const alt = data.get("ALT");
1213
+ if (alt) {
1214
+ ResultFormatter.altitude(decodeResult, Number(alt));
1215
+ data.delete("ALT");
1216
+ }
1217
+ const fn = data.get("FN");
1218
+ if (fn) {
1219
+ ResultFormatter.flightNumber(decodeResult, fn);
1220
+ data.delete("FN");
1221
+ }
1222
+ const day = data.get("DAY");
1223
+ const utc = data.get("UTC");
1224
+ if (day && utc) {
1225
+ decodeResult.raw.message_timestamp = Date.parse(day + " GMT+0000") / 1e3 + DateTimeUtils.convertHHMMSSToTod(utc);
1226
+ data.delete("DAY");
1227
+ data.delete("UTC");
1228
+ }
1229
+ const lat = data.get("LAT");
1230
+ const lon = data.get("LON");
1231
+ if (lat && lon) {
1232
+ ResultFormatter.position(decodeResult, {
1233
+ latitude: CoordinateUtils.getDirection(lat[0]) * Number(lat.substring(1)),
1234
+ longitude: CoordinateUtils.getDirection(lon[0]) * Number(lon.substring(1))
1235
+ });
1236
+ data.delete("LAT");
1237
+ data.delete("LON");
1238
+ }
1239
+ let remaining = "";
1240
+ for (const [key, value] of data.entries()) {
1241
+ if (key === "") {
1242
+ remaining += value;
1243
+ } else {
1244
+ remaining += `/${key} ${value}`;
1245
+ }
1246
+ }
1247
+ decodeResult.remaining.text = remaining;
1248
+ decodeResult.decoded = true;
1249
+ decodeResult.decoder.decodeLevel = "partial";
1250
+ return decodeResult;
1251
+ }
1252
+ };
1253
+
1254
+ // lib/plugins/Label_1L_070.ts
1255
+ var Label_1L_070 = class extends DecoderPlugin {
1256
+ // eslint-disable-line camelcase
1257
+ name = "label-1l-070";
1258
+ qualifiers() {
1259
+ return {
1260
+ labels: ["1L"],
1261
+ preambles: ["000000070"]
1262
+ };
1263
+ }
1264
+ decode(message, options = {}) {
1265
+ const decodeResult = this.defaultResult();
1266
+ decodeResult.decoder.name = this.name;
1267
+ decodeResult.formatted.description = "Position Report";
1268
+ decodeResult.message = message;
1269
+ if (!message.text.startsWith("000000070")) {
1270
+ if (options.debug) {
1271
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1272
+ }
1273
+ decodeResult.remaining.text = message.text;
1274
+ decodeResult.decoded = false;
1275
+ decodeResult.decoder.decodeLevel = "none";
1276
+ return decodeResult;
1277
+ }
1278
+ const parts = message.text.substring(9).split(",");
1279
+ if (parts.length !== 7) {
1280
+ if (options.debug) {
1281
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1282
+ }
1283
+ decodeResult.remaining.text = message.text;
1284
+ decodeResult.decoded = false;
1285
+ decodeResult.decoder.decodeLevel = "none";
1286
+ return decodeResult;
1287
+ }
1288
+ ResultFormatter.departureAirport(decodeResult, parts[0]);
1289
+ ResultFormatter.arrivalAirport(decodeResult, parts[1]);
1290
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[2] + "00"));
1291
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(parts[3] + "00"));
1292
+ ResultFormatter.position(decodeResult, {
1293
+ latitude: CoordinateUtils.getDirection(parts[4][0]) * Number(parts[4].substring(1)),
1294
+ longitude: CoordinateUtils.getDirection(parts[5][0]) * Number(parts[5].substring(1))
1295
+ });
1296
+ decodeResult.remaining.text = parts[6];
1297
+ decodeResult.decoded = true;
1298
+ decodeResult.decoder.decodeLevel = "partial";
1299
+ return decodeResult;
1300
+ }
1301
+ };
1302
+
1303
+ // lib/plugins/Label_1L_660.ts
1304
+ var Label_1L_660 = class extends DecoderPlugin {
1305
+ // eslint-disable-line camelcase
1306
+ name = "label-1l-660";
1307
+ qualifiers() {
1308
+ return {
1309
+ labels: ["1L"],
1310
+ preambles: ["000000660"]
1311
+ };
1312
+ }
1313
+ decode(message, options = {}) {
1314
+ const decodeResult = this.defaultResult();
1315
+ decodeResult.decoder.name = this.name;
1316
+ decodeResult.formatted.description = "Position Report";
1317
+ decodeResult.message = message;
1318
+ if (!message.text.startsWith("000000660")) {
1319
+ if (options.debug) {
1320
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1321
+ }
1322
+ decodeResult.remaining.text = message.text;
1323
+ decodeResult.decoded = false;
1324
+ decodeResult.decoder.decodeLevel = "none";
1325
+ return decodeResult;
1326
+ }
1327
+ const parts = message.text.substring(9).split(",");
1328
+ if (parts.length !== 5) {
1329
+ if (options.debug) {
1330
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1331
+ }
1332
+ decodeResult.remaining.text = message.text;
1333
+ decodeResult.decoded = false;
1334
+ decodeResult.decoder.decodeLevel = "none";
1335
+ return decodeResult;
1336
+ }
1337
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(parts[0]);
1338
+ if (position) {
1339
+ ResultFormatter.position(decodeResult, position);
1340
+ }
1341
+ const hhmmss = parts[1].substring(0, 6);
1342
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(hhmmss));
1343
+ const fl = parts[1].substring(6, 9);
1344
+ ResultFormatter.altitude(decodeResult, Number(fl) * 100);
1345
+ const next = parts[1].substring(9);
1346
+ ResultFormatter.route(decodeResult, { waypoints: [{ name: next.trim() }] });
1347
+ decodeResult.remaining.text = parts.slice(2).join(",");
1348
+ decodeResult.decoded = true;
1349
+ decodeResult.decoder.decodeLevel = "partial";
1350
+ return decodeResult;
1351
+ }
1352
+ };
1353
+
1354
+ // lib/plugins/Label_1L_Slash.ts
1355
+ var Label_1L_Slash = class extends DecoderPlugin {
1356
+ // eslint-disable-line camelcase
1357
+ name = "label-1l-1-line";
1358
+ qualifiers() {
1359
+ return {
1360
+ labels: ["1L"],
1361
+ preambles: ["+", "-"]
1362
+ };
1363
+ }
1364
+ decode(message, options = {}) {
1365
+ const decodeResult = this.defaultResult();
1366
+ decodeResult.decoder.name = this.name;
1367
+ decodeResult.formatted.description = "Position Report";
1368
+ decodeResult.message = message;
1369
+ const parts = message.text.split("/");
1370
+ if (parts.length !== 7) {
1371
+ if (options.debug) {
1372
+ console.log(`Decoder: Unknown 1L message: ${message.text}`);
1373
+ }
1374
+ decodeResult.remaining.text = message.text;
1375
+ decodeResult.decoded = false;
1376
+ decodeResult.decoder.decodeLevel = "none";
1377
+ return decodeResult;
1378
+ }
1379
+ const data = /* @__PURE__ */ new Map();
1380
+ data.set("LAT", parts[0].replaceAll(" ", ""));
1381
+ data.set("LON", parts[1].replaceAll(" ", ""));
1382
+ for (let i = 2; i < parts.length; i++) {
1383
+ const part = parts[i].split(" ");
1384
+ data.set(part[0], part.slice(1).join(" "));
1385
+ }
1386
+ console.log(data);
1387
+ const position = {
1388
+ latitude: Number(data.get("LAT")),
1389
+ longitude: Number(data.get("LON"))
1390
+ };
1391
+ data.delete("LAT");
1392
+ data.delete("LON");
1393
+ ResultFormatter.position(decodeResult, position);
1394
+ const utc = data.get("UTC");
1395
+ if (utc) {
1396
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(utc));
1397
+ data.delete("UTC");
1398
+ }
1399
+ const alt = data.get("ALT");
1400
+ if (alt) {
1401
+ ResultFormatter.altitude(decodeResult, Number(alt));
1402
+ data.delete("ALT");
1403
+ }
1404
+ const fob = data.get("FOB");
1405
+ if (fob) {
1406
+ ResultFormatter.currentFuel(decodeResult, Number(fob));
1407
+ data.delete("FOB");
1408
+ }
1409
+ const eta = data.get("ETA");
1410
+ if (eta) {
1411
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(eta + "00"));
1412
+ data.delete("ETA");
1413
+ }
1414
+ let remaining = "";
1415
+ for (const [key, value] of data.entries()) {
1416
+ remaining += `/${key} ${value}`;
1417
+ }
1418
+ decodeResult.remaining.text = remaining;
1419
+ decodeResult.decoded = true;
1420
+ decodeResult.decoder.decodeLevel = "partial";
1421
+ return decodeResult;
1422
+ }
1423
+ };
1424
+
1159
1425
  // lib/plugins/Label_20_POS.ts
1160
1426
  var Label_20_POS = class extends DecoderPlugin {
1161
1427
  name = "label-20-pos";
@@ -1178,30 +1444,16 @@ var Label_20_POS = class extends DecoderPlugin {
1178
1444
  console.log(`DEBUG: ${this.name}: Variation 1 detected`);
1179
1445
  }
1180
1446
  const rawCoords = fields[0];
1181
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
1182
- if (decodeResult.raw.position) {
1183
- decodeResult.formatted.items.push({
1184
- type: "position",
1185
- code: "POS",
1186
- label: "Position",
1187
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1188
- });
1189
- }
1447
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(rawCoords));
1190
1448
  decodeResult.decoded = true;
1191
1449
  decodeResult.decoder.decodeLevel = "full";
1192
1450
  } else if (fields.length == 5) {
1193
1451
  if (options.debug) {
1194
1452
  console.log(`DEBUG: ${this.name}: Variation 2 detected`);
1195
1453
  }
1196
- const rawCoords = fields[0];
1197
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(rawCoords);
1198
- if (decodeResult.raw.position) {
1199
- decodeResult.formatted.items.push({
1200
- type: "position",
1201
- code: "POS",
1202
- label: "Position",
1203
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1204
- });
1454
+ const position = CoordinateUtils.decodeStringCoordinates(fields[0]);
1455
+ if (position) {
1456
+ ResultFormatter.position(decodeResult, position);
1205
1457
  }
1206
1458
  decodeResult.decoded = true;
1207
1459
  decodeResult.decoder.decodeLevel = "full";
@@ -1240,11 +1492,7 @@ var Label_21_POS = class extends DecoderPlugin {
1240
1492
  ResultFormatter.temperature(decodeResult, fields[6].replace(/ /g, ""));
1241
1493
  ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[7]));
1242
1494
  ResultFormatter.arrivalAirport(decodeResult, fields[8]);
1243
- decodeResult.remaining.text = [
1244
- fields[1],
1245
- fields[4],
1246
- fields[5]
1247
- ].join(",");
1495
+ ResultFormatter.unknownArr(decodeResult, [fields[1], fields[4], fields[5]]);
1248
1496
  decodeResult.decoded = true;
1249
1497
  decodeResult.decoder.decodeLevel = "partial";
1250
1498
  } else {
@@ -1270,41 +1518,74 @@ function processPosition(decodeResult, value) {
1270
1518
  ResultFormatter.position(decodeResult, position);
1271
1519
  }
1272
1520
 
1273
- // lib/plugins/Label_24_Slash.ts
1274
- var Label_24_Slash = class extends DecoderPlugin {
1275
- name = "label-24-slash";
1521
+ // lib/plugins/Label_22_OFF.ts
1522
+ var Label_22_OFF = class extends DecoderPlugin {
1523
+ name = "label-22-off";
1276
1524
  qualifiers() {
1277
1525
  return {
1278
- labels: ["24"],
1279
- preambles: ["/"]
1526
+ labels: ["22"],
1527
+ preambles: ["OFF"]
1280
1528
  };
1281
1529
  }
1282
1530
  decode(message, options = {}) {
1283
1531
  const decodeResult = this.defaultResult();
1284
1532
  decodeResult.decoder.name = this.name;
1285
- decodeResult.formatted.description = "Position Report";
1533
+ decodeResult.formatted.description = "Takeoff Report";
1286
1534
  decodeResult.message = message;
1287
- const fields = message.text.split("/");
1288
- if (fields.length == 10 && fields[0] == "" && fields[9] == "") {
1289
- const mmddyy = fields[1].substring(4, 6) + fields[1].substring(2, 4) + fields[1].substring(0, 2);
1290
- const hhmmss = fields[2] + "00";
1291
- decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(hhmmss, mmddyy);
1292
- ResultFormatter.flightNumber(decodeResult, fields[3]);
1293
- ResultFormatter.altitude(decodeResult, Number(fields[4]));
1294
- const lat = fields[5];
1295
- const lon = fields[6];
1296
- const position = {
1297
- latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1)),
1298
- longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1))
1299
- };
1300
- ResultFormatter.position(decodeResult, position);
1301
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[8] + "00"));
1302
- decodeResult.remaining.text = fields[7];
1535
+ if (message.text.startsWith("OFF01")) {
1536
+ const fields = message.text.substring(5).split("/");
1537
+ if (fields.length != 2) {
1538
+ decodeResult.decoded = false;
1539
+ decodeResult.decoder.decodeLevel = "none";
1540
+ return decodeResult;
1541
+ }
1542
+ ResultFormatter.flightNumber(decodeResult, fields[0]);
1543
+ ResultFormatter.departureDay(decodeResult, Number(fields[1].substring(0, 2)));
1544
+ ResultFormatter.arrivalDay(decodeResult, Number(fields[1].substring(2, 4)));
1545
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(4, 8) + "00"));
1546
+ ResultFormatter.departureAirport(decodeResult, fields[1].substring(8, 12));
1547
+ ResultFormatter.arrivalAirport(decodeResult, fields[1].substring(12, 16));
1548
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 22)));
1549
+ ResultFormatter.unknown(decodeResult, fields[1].substring(22));
1550
+ decodeResult.decoded = true;
1551
+ decodeResult.decoder.decodeLevel = "partial";
1552
+ } else if (message.text.startsWith("OFF02\r\n")) {
1553
+ const fields = message.text.substring(7).split(",");
1554
+ if (fields.length != 4) {
1555
+ decodeResult.decoded = false;
1556
+ decodeResult.decoder.decodeLevel = "none";
1557
+ return decodeResult;
1558
+ }
1559
+ ResultFormatter.departureAirport(decodeResult, fields[0]);
1560
+ ResultFormatter.arrivalAirport(decodeResult, fields[1]);
1561
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2] + "00"));
1562
+ ResultFormatter.unknown(decodeResult, fields[3]);
1563
+ decodeResult.decoded = true;
1564
+ decodeResult.decoder.decodeLevel = "partial";
1565
+ } else if (message.text.startsWith("OFF02")) {
1566
+ const fields = message.text.substring(5).split("/");
1567
+ if (fields.length != 2) {
1568
+ decodeResult.decoded = false;
1569
+ decodeResult.decoder.decodeLevel = "none";
1570
+ return decodeResult;
1571
+ }
1572
+ ResultFormatter.flightNumber(decodeResult, fields[0]);
1573
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(fields[1].substring(0, 14));
1574
+ if (position) {
1575
+ ResultFormatter.position(decodeResult, position);
1576
+ }
1577
+ ResultFormatter.day(decodeResult, Number(fields[1].substring(14, 16)));
1578
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(16, 20) + "00"));
1579
+ ResultFormatter.departureAirport(decodeResult, fields[1].substring(20, 24));
1580
+ ResultFormatter.arrivalAirport(decodeResult, fields[1].substring(24, 28));
1581
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(28, 32) + "00"));
1582
+ ResultFormatter.unknown(decodeResult, fields[1].substring(32, 36));
1583
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1].substring(36, 40) + "00"));
1303
1584
  decodeResult.decoded = true;
1304
1585
  decodeResult.decoder.decodeLevel = "partial";
1305
1586
  } else {
1306
1587
  if (options.debug) {
1307
- console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}. Message: ${message.text}`);
1588
+ console.log(`DEBUG: ${this.name}: Unknown variation.`);
1308
1589
  }
1309
1590
  decodeResult.decoded = false;
1310
1591
  decodeResult.decoder.decodeLevel = "none";
@@ -1313,33 +1594,116 @@ var Label_24_Slash = class extends DecoderPlugin {
1313
1594
  }
1314
1595
  };
1315
1596
 
1316
- // lib/plugins/Label_30_Slash_EA.ts
1317
- var Label_30_Slash_EA = class extends DecoderPlugin {
1318
- name = "label-30-slash-ea";
1597
+ // lib/plugins/Label_22_POS.ts
1598
+ var Label_22_POS = class extends DecoderPlugin {
1599
+ name = "label-22-pos";
1319
1600
  qualifiers() {
1320
1601
  return {
1321
- labels: ["30"],
1322
- preambles: ["/EA"]
1602
+ labels: ["22"],
1603
+ preambles: ["N", "S"]
1323
1604
  };
1324
1605
  }
1325
1606
  decode(message, options = {}) {
1326
1607
  const decodeResult = this.defaultResult();
1327
1608
  decodeResult.decoder.name = this.name;
1328
- decodeResult.formatted.description = "ETA Report";
1609
+ decodeResult.formatted.description = "Position Report";
1329
1610
  decodeResult.message = message;
1330
- const results = message.text.split(/\n|\//).slice(1);
1331
- if (results) {
1611
+ const fields = message.text.split(",");
1612
+ if (fields.length !== 11) {
1332
1613
  if (options.debug) {
1333
- console.log(`Label 30 EA: results`);
1334
- console.log(results);
1614
+ console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}, content: ${fields.join(",")}`);
1615
+ }
1616
+ decodeResult.decoded = false;
1617
+ decodeResult.decoder.decodeLevel = "none";
1618
+ return decodeResult;
1619
+ }
1620
+ const latStr = fields[0].substring(1, 8);
1621
+ const lonStr = fields[0].substring(9);
1622
+ const lat = Number(latStr) / 1e4;
1623
+ const lon = Number(lonStr) / 1e4;
1624
+ ResultFormatter.position(decodeResult, {
1625
+ latitude: CoordinateUtils.getDirection(fields[0][0]) * lat,
1626
+ longitude: CoordinateUtils.getDirection(fields[0][8]) * lon
1627
+ });
1628
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2]));
1629
+ ResultFormatter.altitude(decodeResult, Number(fields[3]));
1630
+ ResultFormatter.unknownArr(decodeResult, [fields[1], ...fields.slice(4)]);
1631
+ decodeResult.decoded = true;
1632
+ decodeResult.decoder.decodeLevel = "partial";
1633
+ return decodeResult;
1634
+ }
1635
+ };
1636
+
1637
+ // lib/plugins/Label_24_Slash.ts
1638
+ var Label_24_Slash = class extends DecoderPlugin {
1639
+ name = "label-24-slash";
1640
+ qualifiers() {
1641
+ return {
1642
+ labels: ["24"],
1643
+ preambles: ["/"]
1644
+ };
1645
+ }
1646
+ decode(message, options = {}) {
1647
+ const decodeResult = this.defaultResult();
1648
+ decodeResult.decoder.name = this.name;
1649
+ decodeResult.formatted.description = "Position Report";
1650
+ decodeResult.message = message;
1651
+ const fields = message.text.split("/");
1652
+ if (fields.length == 10 && fields[0] == "" && fields[9] == "") {
1653
+ const mmddyy = fields[1].substring(4, 6) + fields[1].substring(2, 4) + fields[1].substring(0, 2);
1654
+ const hhmmss = fields[2] + "00";
1655
+ decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(hhmmss, mmddyy);
1656
+ ResultFormatter.flightNumber(decodeResult, fields[3]);
1657
+ ResultFormatter.altitude(decodeResult, Number(fields[4]));
1658
+ const lat = fields[5];
1659
+ const lon = fields[6];
1660
+ const position = {
1661
+ latitude: (lat[0] === "N" ? 1 : -1) * Number(lat.substring(1)),
1662
+ longitude: (lon[0] === "E" ? 1 : -1) * Number(lon.substring(1))
1663
+ };
1664
+ ResultFormatter.position(decodeResult, position);
1665
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[8] + "00"));
1666
+ ResultFormatter.unknown(decodeResult, fields[7]);
1667
+ decodeResult.decoded = true;
1668
+ decodeResult.decoder.decodeLevel = "partial";
1669
+ } else {
1670
+ if (options.debug) {
1671
+ console.log(`DEBUG: ${this.name}: Unknown variation. Field count: ${fields.length}. Message: ${message.text}`);
1672
+ }
1673
+ decodeResult.decoded = false;
1674
+ decodeResult.decoder.decodeLevel = "none";
1675
+ }
1676
+ return decodeResult;
1677
+ }
1678
+ };
1679
+
1680
+ // lib/plugins/Label_30_Slash_EA.ts
1681
+ var Label_30_Slash_EA = class extends DecoderPlugin {
1682
+ name = "label-30-slash-ea";
1683
+ qualifiers() {
1684
+ return {
1685
+ labels: ["30"],
1686
+ preambles: ["/EA"]
1687
+ };
1688
+ }
1689
+ decode(message, options = {}) {
1690
+ const decodeResult = this.defaultResult();
1691
+ decodeResult.decoder.name = this.name;
1692
+ decodeResult.formatted.description = "ETA Report";
1693
+ decodeResult.message = message;
1694
+ const results = message.text.split(/\n|\//).slice(1);
1695
+ if (results) {
1696
+ if (options.debug) {
1697
+ console.log(`Label 30 EA: results`);
1698
+ console.log(results);
1335
1699
  }
1336
1700
  }
1337
1701
  ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results[0].substr(2, 4) + "00"));
1338
1702
  if (results[1].substring(0, 2) === "DS") {
1339
1703
  ResultFormatter.arrivalAirport(decodeResult, results[1].substring(2, 6));
1340
- decodeResult.remaining.text = "/".concat(results[2]);
1704
+ ResultFormatter.unknown(decodeResult, "/".concat(results[2]));
1341
1705
  } else {
1342
- decodeResult.remaining.text = "/".concat(results[1], "/", results[2]);
1706
+ ResultFormatter.unknown(decodeResult, "/".concat(results[1], "/", results[2]));
1343
1707
  }
1344
1708
  decodeResult.decoded = true;
1345
1709
  decodeResult.decoder.decodeLevel = "partial";
@@ -1363,40 +1727,20 @@ var Label_44_ETA = class extends DecoderPlugin {
1363
1727
  decodeResult.message = message;
1364
1728
  const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
1365
1729
  const results = message.text.match(regex);
1366
- if (results) {
1730
+ if (results?.groups) {
1367
1731
  if (options.debug) {
1368
1732
  console.log(`Label 44 ETA Report: groups`);
1369
1733
  console.log(results.groups);
1370
1734
  }
1371
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
1372
- decodeResult.raw.departure_icao = results.groups.departure_icao;
1373
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1735
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords));
1736
+ ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1737
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1374
1738
  decodeResult.raw.current_time = Date.parse(
1375
1739
  (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.current_time.substr(0, 2) + ":" + results.groups.current_time.substr(2, 2) + ":00Z"
1376
1740
  );
1377
1741
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1378
- decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1379
- }
1380
- if (decodeResult.raw.position) {
1381
- decodeResult.formatted.items.push({
1382
- type: "position",
1383
- code: "POS",
1384
- label: "Position",
1385
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1386
- });
1742
+ ResultFormatter.remainingFuel(decodeResult, Number(results.groups.fuel_in_tons));
1387
1743
  }
1388
- decodeResult.formatted.items.push({
1389
- type: "origin",
1390
- code: "ORG",
1391
- label: "Origin",
1392
- value: decodeResult.raw.departure_icao
1393
- });
1394
- decodeResult.formatted.items.push({
1395
- type: "destination",
1396
- code: "DST",
1397
- label: "Destination",
1398
- value: decodeResult.raw.arrival_icao
1399
- });
1400
1744
  }
1401
1745
  decodeResult.decoded = true;
1402
1746
  decodeResult.decoder.decodeLevel = "full";
@@ -1420,40 +1764,20 @@ var Label_44_IN = class extends DecoderPlugin {
1420
1764
  decodeResult.message = message;
1421
1765
  const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
1422
1766
  const results = message.text.match(regex);
1423
- if (results) {
1767
+ if (results?.groups) {
1424
1768
  if (options.debug) {
1425
1769
  console.log(`Label 44 In Air Report: groups`);
1426
1770
  console.log(results.groups);
1427
1771
  }
1428
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
1429
- decodeResult.raw.departure_icao = results.groups.departure_icao;
1430
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1772
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords));
1773
+ ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1774
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1431
1775
  decodeResult.raw.current_time = Date.parse(
1432
1776
  (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.current_time.substr(0, 2) + ":" + results.groups.current_time.substr(2, 2) + ":00Z"
1433
1777
  );
1434
1778
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1435
1779
  decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1436
1780
  }
1437
- if (decodeResult.raw.position) {
1438
- decodeResult.formatted.items.push({
1439
- type: "position",
1440
- code: "POS",
1441
- label: "Position",
1442
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1443
- });
1444
- }
1445
- decodeResult.formatted.items.push({
1446
- type: "origin",
1447
- code: "ORG",
1448
- label: "Origin",
1449
- value: decodeResult.raw.departure_icao
1450
- });
1451
- decodeResult.formatted.items.push({
1452
- type: "destination",
1453
- code: "DST",
1454
- label: "Destination",
1455
- value: decodeResult.raw.arrival_icao
1456
- });
1457
1781
  }
1458
1782
  decodeResult.decoded = true;
1459
1783
  decodeResult.decoder.decodeLevel = "full";
@@ -1477,13 +1801,14 @@ var Label_44_OFF = class extends DecoderPlugin {
1477
1801
  decodeResult.message = message;
1478
1802
  const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<eta_time>.*),(?<fuel_in_tons>.*)$/;
1479
1803
  const results = message.text.match(regex);
1480
- if (results) {
1804
+ if (results?.groups) {
1481
1805
  if (options.debug) {
1482
1806
  console.log(`Label 44 Off Runway Report: groups`);
1483
1807
  console.log(results.groups);
1484
1808
  }
1485
- decodeResult.raw.departure_icao = results.groups.departure_icao;
1486
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1809
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords));
1810
+ ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1811
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1487
1812
  decodeResult.raw.current_time = Date.parse(
1488
1813
  (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.current_time.substr(0, 2) + ":" + results.groups.current_time.substr(2, 2) + ":00Z"
1489
1814
  );
@@ -1493,27 +1818,6 @@ var Label_44_OFF = class extends DecoderPlugin {
1493
1818
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1494
1819
  decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1495
1820
  }
1496
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
1497
- if (decodeResult.raw.position) {
1498
- decodeResult.formatted.items.push({
1499
- type: "position",
1500
- code: "POS",
1501
- label: "Position",
1502
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1503
- });
1504
- }
1505
- decodeResult.formatted.items.push({
1506
- type: "origin",
1507
- code: "ORG",
1508
- label: "Origin",
1509
- value: decodeResult.raw.departure_icao
1510
- });
1511
- decodeResult.formatted.items.push({
1512
- type: "destination",
1513
- code: "DST",
1514
- label: "Destination",
1515
- value: decodeResult.raw.arrival_icao
1516
- });
1517
1821
  }
1518
1822
  decodeResult.decoded = true;
1519
1823
  decodeResult.decoder.decodeLevel = "full";
@@ -1537,40 +1841,20 @@ var Label_44_ON = class extends DecoderPlugin {
1537
1841
  decodeResult.message = message;
1538
1842
  const regex = /^.*,(?<unsplit_coords>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<fuel_in_tons>.*)$/;
1539
1843
  const results = message.text.match(regex);
1540
- if (results) {
1844
+ if (results?.groups) {
1541
1845
  if (options.debug) {
1542
1846
  console.log(`Label 44 On Runway Report: groups`);
1543
1847
  console.log(results.groups);
1544
1848
  }
1545
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords);
1546
- decodeResult.raw.departure_icao = results.groups.departure_icao;
1547
- decodeResult.raw.arrival_icao = results.groups.arrival_icao;
1849
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(results.groups.unsplit_coords));
1850
+ ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1851
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1548
1852
  decodeResult.raw.current_time = Date.parse(
1549
1853
  (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.current_time.substr(0, 2) + ":" + results.groups.current_time.substr(2, 2) + ":00Z"
1550
1854
  );
1551
1855
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1552
- decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1856
+ ResultFormatter.remainingFuel(decodeResult, Number(results.groups.fuel_in_tons));
1553
1857
  }
1554
- if (decodeResult.raw.position) {
1555
- decodeResult.formatted.items.push({
1556
- type: "position",
1557
- code: "POS",
1558
- label: "Position",
1559
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1560
- });
1561
- }
1562
- decodeResult.formatted.items.push({
1563
- type: "origin",
1564
- code: "ORG",
1565
- label: "Origin",
1566
- value: decodeResult.raw.departure_icao
1567
- });
1568
- decodeResult.formatted.items.push({
1569
- type: "destination",
1570
- code: "DST",
1571
- label: "Destination",
1572
- value: decodeResult.raw.arrival_icao
1573
- });
1574
1858
  }
1575
1859
  decodeResult.decoded = true;
1576
1860
  decodeResult.decoder.decodeLevel = "full";
@@ -1594,12 +1878,12 @@ var Label_44_POS = class extends DecoderPlugin {
1594
1878
  decodeResult.message = message;
1595
1879
  const regex = /^.*,(?<unsplit_coords>.*),(?<flight_level_or_ground>.*),(?<departure_icao>.*),(?<arrival_icao>.*),(?<current_date>.*),(?<current_time>.*),(?<eta_time>.*),(?<fuel_in_tons>.*)$/;
1596
1880
  const results = message.text.match(regex);
1597
- if (results) {
1881
+ if (results?.groups) {
1598
1882
  if (options.debug) {
1599
1883
  console.log(`Label 44 Position Report: groups`);
1600
1884
  console.log(results.groups);
1601
1885
  }
1602
- decodeResult.raw.position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(results.groups.unsplit_coords);
1886
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(results.groups.unsplit_coords));
1603
1887
  const flight_level = results.groups.flight_level_or_ground == "GRD" || results.groups.flight_level_or_ground == "***" ? 0 : Number(results.groups.flight_level_or_ground);
1604
1888
  decodeResult.raw.current_time = Date.parse(
1605
1889
  (/* @__PURE__ */ new Date()).getFullYear() + "-" + results.groups.current_date.substr(0, 2) + "-" + results.groups.current_date.substr(2, 2) + "T" + results.groups.current_time.substr(0, 2) + ":" + results.groups.current_time.substr(2, 2) + ":00Z"
@@ -1610,14 +1894,6 @@ var Label_44_POS = class extends DecoderPlugin {
1610
1894
  if (results.groups.fuel_in_tons != "***" && results.groups.fuel_in_tons != "****") {
1611
1895
  decodeResult.raw.fuel_in_tons = Number(results.groups.fuel_in_tons);
1612
1896
  }
1613
- if (decodeResult.raw.position) {
1614
- decodeResult.formatted.items.push({
1615
- type: "aircraft_position",
1616
- code: "POS",
1617
- label: "Aircraft Position",
1618
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
1619
- });
1620
- }
1621
1897
  ResultFormatter.departureAirport(decodeResult, results.groups.departure_icao);
1622
1898
  ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
1623
1899
  ResultFormatter.altitude(decodeResult, flight_level * 100);
@@ -1641,13 +1917,13 @@ var Label_4A = class extends DecoderPlugin {
1641
1917
  decodeResult.decoder.name = this.name;
1642
1918
  decodeResult.message = message;
1643
1919
  decodeResult.formatted.description = "Latest New Format";
1644
- let text2 = message.text;
1645
- if (text2.match(/^M\d{2}A\w{6}/)) {
1920
+ let text = message.text;
1921
+ if (text.match(/^M\d{2}A\w{6}/)) {
1646
1922
  ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
1647
- text2 = text2.substring(10);
1923
+ text = text.substring(10);
1648
1924
  }
1649
1925
  decodeResult.decoded = true;
1650
- const fields = text2.split(",");
1926
+ const fields = text.split(",");
1651
1927
  if (fields.length === 11) {
1652
1928
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[0]));
1653
1929
  ResultFormatter.tail(decodeResult, fields[2].replace(".", ""));
@@ -1655,8 +1931,8 @@ var Label_4A = class extends DecoderPlugin {
1655
1931
  ResultFormatter.callsign(decodeResult, fields[3]);
1656
1932
  ResultFormatter.departureAirport(decodeResult, fields[4]);
1657
1933
  ResultFormatter.arrivalAirport(decodeResult, fields[5]);
1658
- ResultFormatter.altitude(decodeResult, text2.substring(48, 51) * 100);
1659
- decodeResult.remaining.text = fields.slice(8).join(",");
1934
+ ResultFormatter.altitude(decodeResult, Number(text.substring(48, 51)) * 100);
1935
+ ResultFormatter.unknownArr(decodeResult, fields.slice(8));
1660
1936
  } else if (fields.length === 6) {
1661
1937
  if (fields[0].match(/^[NS]/)) {
1662
1938
  ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates(fields[0].substring(0, 13)));
@@ -1665,31 +1941,25 @@ var Label_4A = class extends DecoderPlugin {
1665
1941
  time: DateTimeUtils.convertHHMMSSToTod(fields[1].substring(0, 6)),
1666
1942
  timeFormat: "tod"
1667
1943
  };
1668
- ResultFormatter.altitude(decodeResult, fields[1].substring(6, 9) * 100);
1944
+ ResultFormatter.altitude(decodeResult, Number(fields[1].substring(6, 9)) * 100);
1669
1945
  let wp2 = {
1670
1946
  name: fields[1].substring(9).trim(),
1671
1947
  time: DateTimeUtils.convertHHMMSSToTod(fields[2]),
1672
1948
  timeFormat: "tod"
1673
1949
  };
1674
- decodeResult.raw.route = { waypoints: [wp1, wp2] };
1675
- decodeResult.formatted.items.push({
1676
- type: "aircraft_route",
1677
- code: "ROUTE",
1678
- label: "Aircraft Route",
1679
- value: RouteUtils.routeToString(decodeResult.raw.route)
1680
- });
1950
+ ResultFormatter.route(decodeResult, { waypoints: [wp1, wp2] });
1681
1951
  ResultFormatter.temperature(decodeResult, fields[3]);
1682
- decodeResult.remaining.text = fields.slice(4).join(",");
1952
+ ResultFormatter.unknownArr(decodeResult, fields.slice(4));
1683
1953
  } else {
1684
1954
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[0]));
1685
1955
  ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[1]));
1686
- decodeResult.remaining.text = fields[2];
1687
- ResultFormatter.altitude(decodeResult, fields[3]);
1956
+ ResultFormatter.unknown(decodeResult, fields[2]);
1957
+ ResultFormatter.altitude(decodeResult, Number(fields[3]));
1688
1958
  ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinates((fields[4] + fields[5]).replace(/[ \.]/g, "")));
1689
1959
  }
1690
1960
  } else {
1691
1961
  decodeResult.decoded = false;
1692
- decodeResult.remaining.text = text2;
1962
+ ResultFormatter.unknown(decodeResult, text);
1693
1963
  }
1694
1964
  if (decodeResult.decoded) {
1695
1965
  if (!decodeResult.remaining.text)
@@ -1726,11 +1996,11 @@ var Label_4A_01 = class extends DecoderPlugin {
1726
1996
  ResultFormatter.departureAirport(decodeResult, rgx[5]);
1727
1997
  ResultFormatter.arrivalAirport(decodeResult, rgx[6]);
1728
1998
  ResultFormatter.altitude(decodeResult, Number(rgx[7].replace(/ /g, "")));
1729
- decodeResult.remaining.text = rgx[8];
1999
+ ResultFormatter.unknown(decodeResult, rgx[8]);
1730
2000
  ResultFormatter.temperature(decodeResult, rgx[9].replace(/ /g, ""));
1731
2001
  } else {
1732
2002
  decodeResult.decoded = false;
1733
- decodeResult.remaining.text = message.text;
2003
+ ResultFormatter.unknown(decodeResult, message.text);
1734
2004
  }
1735
2005
  if (decodeResult.decoded) {
1736
2006
  if (!decodeResult.remaining.text)
@@ -1796,7 +2066,7 @@ var Label_4A_DOOR = class extends DecoderPlugin {
1796
2066
  ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[2] + "00"));
1797
2067
  } else {
1798
2068
  decodeResult.decoded = false;
1799
- decodeResult.remaining.text = text;
2069
+ ResultFormatter.unknown(decodeResult, message.text);
1800
2070
  }
1801
2071
  if (decodeResult.decoded) {
1802
2072
  if (!decodeResult.remaining.text)
@@ -1826,10 +2096,10 @@ var Label_4A_Slash_01 = class extends DecoderPlugin {
1826
2096
  decodeResult.formatted.description = "Latest New Format";
1827
2097
  decodeResult.decoded = true;
1828
2098
  if (message.text.length === 5 && message.text.substring(0, 4) === "/01-") {
1829
- decodeResult.remaining.text = message.text.substring(4);
2099
+ ResultFormatter.unknown(decodeResult, message.text.substring(4));
1830
2100
  } else {
1831
2101
  decodeResult.decoded = false;
1832
- decodeResult.remaining.text = message.text;
2102
+ ResultFormatter.unknown(decodeResult, message.text);
1833
2103
  }
1834
2104
  if (decodeResult.decoded) {
1835
2105
  if (!decodeResult.remaining.text)
@@ -1843,630 +2113,93 @@ var Label_4A_Slash_01 = class extends DecoderPlugin {
1843
2113
  }
1844
2114
  };
1845
2115
 
1846
- // lib/plugins/Label_4N.ts
1847
- var Label_4N = class extends DecoderPlugin {
1848
- name = "label-4n";
1849
- qualifiers() {
1850
- return {
1851
- labels: ["4N"]
1852
- };
1853
- }
1854
- decode(message, options = {}) {
1855
- const decodeResult = this.defaultResult();
1856
- decodeResult.decoder.name = this.name;
1857
- decodeResult.message = message;
1858
- decodeResult.formatted.description = "Airline Defined";
1859
- let text2 = message.text;
1860
- if (text2.match(/^M\d{2}A\w{6}/)) {
1861
- ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
1862
- text2 = text2.substring(10);
1863
- }
1864
- decodeResult.decoded = true;
1865
- const fields = text2.split(",");
1866
- if (text2.length === 51) {
1867
- decodeResult.raw.day_of_month = text2.substring(0, 2);
1868
- ResultFormatter.departureAirport(decodeResult, text2.substring(8, 11));
1869
- ResultFormatter.arrivalAirport(decodeResult, text2.substring(13, 16));
1870
- ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text2.substring(30, 45).replace(/^(.)0/, "$1")));
1871
- ResultFormatter.altitude(decodeResult, text2.substring(48, 51) * 100);
1872
- decodeResult.remaining.text = [text2.substring(2, 4), text2.substring(19, 29)].join(" ");
1873
- } else if (fields.length === 33) {
1874
- decodeResult.raw.date = fields[3];
1875
- if (fields[1] === "B") {
1876
- ResultFormatter.position(decodeResult, { latitude: Number(fields[4]), longitude: Number(fields[5]) });
1877
- ResultFormatter.altitude(decodeResult, fields[6]);
2116
+ // lib/utils/flight_plan_utils.ts
2117
+ var FlightPlanUtils = class _FlightPlanUtils {
2118
+ /**
2119
+ * Processes flight plan data
2120
+ *
2121
+ * Expected format is [header, key1, val1, ... keyN, valN]
2122
+ *
2123
+ * @param decodeResult - results
2124
+ * @param data - original message split by ':'
2125
+ * @returns whether all fields were processed or not
2126
+ */
2127
+ static processFlightPlan(decodeResult, data) {
2128
+ let allKnownFields = _FlightPlanUtils.parseHeader(decodeResult, data[0]);
2129
+ for (let i = 1; i < data.length; i += 2) {
2130
+ const key = data[i];
2131
+ const value = data[i + 1];
2132
+ switch (key) {
2133
+ case "A":
2134
+ addProcedure(decodeResult, value, "arrival");
2135
+ break;
2136
+ case "AA":
2137
+ addArrivalAirport(decodeResult, value);
2138
+ break;
2139
+ case "AP":
2140
+ addProcedure(decodeResult, value, "approach");
2141
+ break;
2142
+ case "CR":
2143
+ addCompanyRoute(decodeResult, value);
2144
+ break;
2145
+ case "D":
2146
+ addProcedure(decodeResult, value, "departure");
2147
+ break;
2148
+ case "DA":
2149
+ addDepartureAirport(decodeResult, value);
2150
+ break;
2151
+ case "F":
2152
+ addRoute(decodeResult, value);
2153
+ break;
2154
+ case "R":
2155
+ addRunway(decodeResult, value);
2156
+ break;
2157
+ // case 'WS': // something about routes, has altitude, so current parsing won't work
2158
+ // break;
2159
+ default:
2160
+ if (allKnownFields) {
2161
+ decodeResult.remaining.text = "";
2162
+ allKnownFields = false;
2163
+ }
2164
+ decodeResult.remaining.text += `:${key}:${value}`;
2165
+ decodeResult.decoder.decodeLevel = "partial";
1878
2166
  }
1879
- ResultFormatter.departureAirport(decodeResult, fields[8]);
1880
- ResultFormatter.arrivalAirport(decodeResult, fields[9]);
1881
- ResultFormatter.alternateAirport(decodeResult, fields[10]);
1882
- ResultFormatter.arrivalRunway(decodeResult, fields[11].split("/")[0]);
1883
- if (fields[12].length > 1) {
1884
- ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
2167
+ }
2168
+ return allKnownFields;
2169
+ }
2170
+ static parseHeader(decodeResult, header) {
2171
+ let allKnownFields = true;
2172
+ if (header.startsWith("RF")) {
2173
+ decodeResult.formatted.items.push({
2174
+ type: "status",
2175
+ code: "ROUTE_STATUS",
2176
+ label: "Route Status",
2177
+ value: "Route Filed"
2178
+ });
2179
+ decodeResult.raw.route_status = "RF";
2180
+ if (header.length > 2) {
2181
+ addRoute(decodeResult, header.substring(2));
1885
2182
  }
1886
- ResultFormatter.checksum(decodeResult, fields[32]);
1887
- decodeResult.remaining.text = [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != "").join(",");
2183
+ } else if (header.startsWith("RP")) {
2184
+ decodeResult.raw.route_status = "RP";
2185
+ decodeResult.formatted.items.push({
2186
+ type: "status",
2187
+ code: "ROUTE_STATUS",
2188
+ label: "Route Status",
2189
+ value: "Route Planned"
2190
+ });
2191
+ decodeResult.raw.route_status = header;
2192
+ } else if (header.startsWith("RI")) {
2193
+ decodeResult.raw.route_status = "RI";
2194
+ decodeResult.formatted.items.push({
2195
+ type: "status",
2196
+ code: "ROUTE_STATUS",
2197
+ label: "Route Status",
2198
+ value: "Route Inactive"
2199
+ });
1888
2200
  } else {
1889
- decodeResult.decoded = false;
1890
- decodeResult.remaining.text = text2;
1891
- }
1892
- if (decodeResult.decoded) {
1893
- if (!decodeResult.remaining.text)
1894
- decodeResult.decoder.decodeLevel = "full";
1895
- else
1896
- decodeResult.decoder.decodeLevel = "partial";
1897
- } else {
1898
- decodeResult.decoder.decodeLevel = "none";
1899
- }
1900
- return decodeResult;
1901
- }
1902
- };
1903
-
1904
- // lib/plugins/Label_80.ts
1905
- var Label_80 = class extends DecoderPlugin {
1906
- name = "label-80";
1907
- descriptions = {
1908
- ALT: "Altitude",
1909
- DWND: "Wind Direction",
1910
- ETA: "Estimated Time of Arrival",
1911
- FOB: "Fuel on Board",
1912
- FL: "Flight Level",
1913
- HDG: "Heading",
1914
- MCH: "Aircraft Speed",
1915
- NWYP: "Next Waypoint",
1916
- POS: "Aircraft Position",
1917
- SAT: "Static Air Temperature",
1918
- SWND: "Wind Speed",
1919
- TAS: "True Airspeed",
1920
- WYP: "Waypoint"
1921
- };
1922
- qualifiers() {
1923
- return {
1924
- labels: ["80"],
1925
- preambles: ["3N01 POSRPT"]
1926
- };
1927
- }
1928
- decode(message, options = {}) {
1929
- const decodeResult = this.defaultResult();
1930
- decodeResult.decoder.name = this.name;
1931
- decodeResult.formatted.description = "Airline Defined Position Report";
1932
- const parts = message.text.split("\n");
1933
- let posRptRegex = /^3N01 POSRPT \d\d\d\d\/\d\d (?<orig>\w+)\/(?<dest>\w+) \.(?<tail>[\w-]+)(\/(?<agate>.+) (?<sta>\w+:\w+))*/;
1934
- let results = parts[0].match(posRptRegex);
1935
- if (!results?.groups) {
1936
- decodeResult.decoded = false;
1937
- decodeResult.decoder.decodeLevel = "none";
1938
- return decodeResult;
1939
- }
1940
- if (results && results.length > 0) {
1941
- ResultFormatter.departureAirport(decodeResult, results.groups.orig);
1942
- ResultFormatter.arrivalAirport(decodeResult, results.groups.dest);
1943
- ResultFormatter.tail(decodeResult, results.groups.tail);
1944
- if (results.groups.agate) {
1945
- decodeResult.raw.arrival_gate = results.groups.agate;
1946
- decodeResult.formatted.items.push({
1947
- type: "arrival_gate",
1948
- code: "ARG",
1949
- label: "Arrival Gate",
1950
- value: `${results.groups.agate}`
1951
- });
1952
- decodeResult.raw.scheduled_time_of_arrival = results.groups.sta;
1953
- decodeResult.formatted.items.push({
1954
- type: "scheduled_time_of_arrival",
1955
- code: "STA",
1956
- label: "Scheduled Time of Arrival",
1957
- value: `${results.groups.sta}`
1958
- });
1959
- }
1960
- posRptRegex = /\/(?<field>\w+)\s(?<value>[\w\+\-:\.]+)\s*/gi;
1961
- const remainingParts = parts.slice(1);
1962
- for (const part of remainingParts) {
1963
- const matches = part.matchAll(posRptRegex);
1964
- for (const match of matches) {
1965
- switch (match.groups?.field) {
1966
- case "ALT": {
1967
- ResultFormatter.altitude(decodeResult, Number(match.groups.value));
1968
- break;
1969
- }
1970
- case "DWND": {
1971
- decodeResult.raw.wind_direction = Number(match.groups.value);
1972
- decodeResult.formatted.items.push({
1973
- type: "wind_direction",
1974
- code: "DWND",
1975
- label: this.descriptions[match.groups.field],
1976
- value: decodeResult.raw.wind_direction
1977
- });
1978
- break;
1979
- }
1980
- case "FL": {
1981
- const flight_level = Number(match.groups.value);
1982
- ResultFormatter.altitude(decodeResult, flight_level * 100);
1983
- break;
1984
- }
1985
- case "FOB": {
1986
- decodeResult.raw.fuel_on_board = match.groups.value;
1987
- decodeResult.formatted.items.push({
1988
- type: "fuel_on_board",
1989
- code: "FOB",
1990
- label: this.descriptions[match.groups.field],
1991
- value: decodeResult.raw.fuel_on_board
1992
- });
1993
- break;
1994
- }
1995
- case "HDG": {
1996
- decodeResult.raw.heading = Number(match.groups.value);
1997
- decodeResult.formatted.items.push({
1998
- type: "heading",
1999
- code: "HDG",
2000
- label: this.descriptions[match.groups.field],
2001
- value: decodeResult.raw.heading
2002
- });
2003
- break;
2004
- }
2005
- case "MCH": {
2006
- decodeResult.raw.mach = Number(match.groups.value) / 1e3;
2007
- decodeResult.formatted.items.push({
2008
- type: "mach",
2009
- code: "MCH",
2010
- label: this.descriptions[match.groups.field],
2011
- value: `${decodeResult.raw.mach} Mach`
2012
- });
2013
- break;
2014
- }
2015
- case "NWYP": {
2016
- decodeResult.raw.next_waypoint = match.groups.value;
2017
- decodeResult.formatted.items.push({
2018
- type: "next_waypoint",
2019
- code: "NWYP",
2020
- label: this.descriptions[match.groups.field],
2021
- value: decodeResult.raw.next_waypoint
2022
- });
2023
- break;
2024
- }
2025
- case "POS": {
2026
- const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
2027
- const posResult = match.groups.value.match(posRegex);
2028
- const lat = Number(posResult?.groups?.lat) * (posResult?.groups?.lngd === "S" ? -1 : 1);
2029
- const lon = Number(posResult?.groups?.lng) * (posResult?.groups?.lngd === "W" ? -1 : 1);
2030
- const position = {
2031
- latitude: Number.isInteger(lat) ? lat / 1e3 : lat / 100,
2032
- longitude: Number.isInteger(lon) ? lon / 1e3 : lon / 100
2033
- };
2034
- ResultFormatter.position(decodeResult, position);
2035
- break;
2036
- }
2037
- case "SWND": {
2038
- decodeResult.raw.wind_speed = Number(match.groups.value);
2039
- decodeResult.formatted.items.push({
2040
- type: "wind_speed",
2041
- code: "SWND",
2042
- label: this.descriptions[match.groups.field],
2043
- value: decodeResult.raw.wind_speed
2044
- });
2045
- break;
2046
- }
2047
- default: {
2048
- if (match.groups?.field != void 0) {
2049
- const description = this.descriptions[match.groups.field] ? this.descriptions[match.groups.field] : "Unknown";
2050
- decodeResult.formatted.items.push({
2051
- type: match.groups.field,
2052
- code: match.groups.field,
2053
- label: description || `Unknown (${match.groups.field})`,
2054
- value: `${match.groups.value}`
2055
- });
2056
- }
2057
- }
2058
- }
2059
- }
2060
- }
2061
- decodeResult.decoded = true;
2062
- decodeResult.decoder.decodeLevel = "partial";
2063
- }
2064
- return decodeResult;
2065
- }
2066
- };
2067
-
2068
- // lib/plugins/Label_83.ts
2069
- var Label_83 = class extends DecoderPlugin {
2070
- name = "label-83";
2071
- qualifiers() {
2072
- return {
2073
- labels: ["83"]
2074
- };
2075
- }
2076
- decode(message, options = {}) {
2077
- const decodeResult = this.defaultResult();
2078
- decodeResult.decoder.name = this.name;
2079
- decodeResult.message = message;
2080
- decodeResult.formatted.description = "Airline Defined";
2081
- let text2 = message.text;
2082
- if (text2.match(/^M\d{2}A\w{6}/)) {
2083
- ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
2084
- text2 = text2.substring(10);
2085
- }
2086
- decodeResult.decoded = true;
2087
- if (text2.substring(0, 10) === "4DH3 ETAT2") {
2088
- const fields = text2.split(/\s+/);
2089
- if (fields[2].length > 5) {
2090
- decodeResult.raw.day_of_month = fields[2].substring(5);
2091
- }
2092
- decodeResult.remaining.text = fields[2].substring(0, 4);
2093
- const subfields = fields[3].split("/");
2094
- ResultFormatter.departureAirport(decodeResult, subfields[0]);
2095
- ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
2096
- ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
2097
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[6] + "00"));
2098
- } else if (text2.substring(0, 5) === "001PR") {
2099
- decodeResult.raw.day_of_month = text2.substring(5, 7);
2100
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text2.substring(13, 28).replace(/\./g, ""));
2101
- if (position) {
2102
- ResultFormatter.position(decodeResult, position);
2103
- }
2104
- ResultFormatter.altitude(decodeResult, Number(text2.substring(28, 33)));
2105
- decodeResult.remaining.text = text2.substring(33);
2106
- } else {
2107
- const fields = text2.replace(/\s/g, "").split(",");
2108
- if (fields.length === 9) {
2109
- ResultFormatter.departureAirport(decodeResult, fields[0]);
2110
- ResultFormatter.arrivalAirport(decodeResult, fields[1]);
2111
- decodeResult.raw.day_of_month = fields[2].substring(0, 2);
2112
- decodeResult.raw.time = fields[2].substring(2);
2113
- ResultFormatter.position(
2114
- decodeResult,
2115
- {
2116
- latitude: Number(fields[3].replace(/\s/g, "")),
2117
- longitude: Number(fields[4].replace(/\s/g, ""))
2118
- }
2119
- );
2120
- ResultFormatter.altitude(decodeResult, Number(fields[5]));
2121
- ResultFormatter.groundspeed(decodeResult, fields[6]);
2122
- ResultFormatter.heading(decodeResult, fields[7]);
2123
- decodeResult.remaining.text = fields[8];
2124
- } else {
2125
- decodeResult.decoded = false;
2126
- decodeResult.remaining.text = message.text;
2127
- }
2128
- }
2129
- if (decodeResult.decoded) {
2130
- if (!decodeResult.remaining.text)
2131
- decodeResult.decoder.decodeLevel = "full";
2132
- else
2133
- decodeResult.decoder.decodeLevel = "partial";
2134
- } else {
2135
- decodeResult.decoder.decodeLevel = "none";
2136
- }
2137
- return decodeResult;
2138
- }
2139
- };
2140
-
2141
- // lib/plugins/Label_8E.ts
2142
- var Label_8E = class extends DecoderPlugin {
2143
- name = "label-8e";
2144
- qualifiers() {
2145
- return {
2146
- labels: ["8E"]
2147
- };
2148
- }
2149
- decode(message, options = {}) {
2150
- const decodeResult = this.defaultResult();
2151
- decodeResult.decoder.name = this.name;
2152
- decodeResult.formatted.description = "ETA Report";
2153
- decodeResult.message = message;
2154
- const regex = /^(?<arrival_icao>\w{4}),(?<arrival_eta>\d{4})$/;
2155
- const results = message.text.match(regex);
2156
- if (results) {
2157
- if (options.debug) {
2158
- console.log(`Label 8E ETA: groups`);
2159
- console.log(results.groups);
2160
- }
2161
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta + "00"));
2162
- ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
2163
- }
2164
- decodeResult.decoded = true;
2165
- decodeResult.decoder.decodeLevel = "full";
2166
- return decodeResult;
2167
- }
2168
- };
2169
-
2170
- // lib/plugins/Label_B6.ts
2171
- var Label_B6_Forwardslash = class extends DecoderPlugin {
2172
- name = "label-b6-forwardslash";
2173
- qualifiers() {
2174
- return {
2175
- labels: ["B6"],
2176
- preambles: ["/"]
2177
- };
2178
- }
2179
- decode(message, options = {}) {
2180
- const decodeResult = this.defaultResult();
2181
- decodeResult.decoder.name = this.name;
2182
- decodeResult.formatted.description = "CPDLC Message";
2183
- decodeResult.message = message;
2184
- if (options.debug) {
2185
- console.log("CPDLC: " + message);
2186
- }
2187
- return decodeResult;
2188
- }
2189
- };
2190
-
2191
- // lib/plugins/Label_ColonComma.ts
2192
- var Label_ColonComma = class extends DecoderPlugin {
2193
- name = "label-colon-comma";
2194
- qualifiers() {
2195
- return {
2196
- labels: [":;"]
2197
- };
2198
- }
2199
- decode(message, options = {}) {
2200
- const decodeResult = this.defaultResult();
2201
- decodeResult.decoder.name = this.name;
2202
- decodeResult.raw.frequency = Number(message.text) / 1e3;
2203
- decodeResult.formatted.description = "Aircraft Transceiver Frequency Change";
2204
- decodeResult.formatted.items.push({
2205
- type: "frequency",
2206
- label: "Frequency",
2207
- value: `${decodeResult.raw.frequency} MHz`
2208
- });
2209
- decodeResult.decoded = true;
2210
- decodeResult.decoder.decodeLevel = "full";
2211
- return decodeResult;
2212
- }
2213
- };
2214
-
2215
- // lib/plugins/Label_H1_FLR.ts
2216
- var Label_H1_FLR = class extends DecoderPlugin {
2217
- name = "label-h1-flr";
2218
- qualifiers() {
2219
- return {
2220
- labels: ["H1"],
2221
- preambles: ["FLR", "#CFBFLR"]
2222
- };
2223
- }
2224
- decode(message, options = {}) {
2225
- let decodeResult = this.defaultResult();
2226
- decodeResult.decoder.name = this.name;
2227
- decodeResult.formatted.description = "Fault Log Report";
2228
- decodeResult.message = message;
2229
- const parts = message.text.split("/FR");
2230
- if (parts.length > 1) {
2231
- decodeResult.remaining.text = "";
2232
- const fields = parts[0].split("/");
2233
- for (let i = 1; i < fields.length; i++) {
2234
- const field = fields[i];
2235
- if (field.startsWith("PN")) {
2236
- processUnknown(decodeResult, "/" + field);
2237
- } else {
2238
- processUnknown(decodeResult, "/" + field);
2239
- }
2240
- }
2241
- const data = parts[1].substring(0, 20);
2242
- const msg = parts[1].substring(20);
2243
- const datetime = data.substring(0, 12);
2244
- const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
2245
- processUnknown(decodeResult, data.substring(12));
2246
- decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
2247
- decodeResult.raw.fault_message = msg;
2248
- decodeResult.formatted.items.push({
2249
- type: "fault",
2250
- code: "FR",
2251
- label: "Fault Report",
2252
- value: decodeResult.raw.fault_message
2253
- });
2254
- decodeResult.decoded = true;
2255
- decodeResult.decoder.decodeLevel = "partial";
2256
- } else {
2257
- if (options.debug) {
2258
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
2259
- }
2260
- decodeResult.remaining.text = message.text;
2261
- decodeResult.decoded = false;
2262
- decodeResult.decoder.decodeLevel = "none";
2263
- }
2264
- return decodeResult;
2265
- }
2266
- };
2267
- function processUnknown(decodeResult, value) {
2268
- decodeResult.remaining.text += value;
2269
- }
2270
-
2271
- // lib/plugins/Label_H1_OHMA.ts
2272
- import * as zlib from "minizlib";
2273
- var Label_H1_OHMA = class extends DecoderPlugin {
2274
- name = "label-h1-ohma";
2275
- qualifiers() {
2276
- return {
2277
- labels: ["H1"],
2278
- preambles: ["OHMA", "/RTNBOCR.OHMA", "#T1B/RTNBOCR.OHMA"]
2279
- };
2280
- }
2281
- decode(message, options = {}) {
2282
- let decodeResult = this.defaultResult();
2283
- decodeResult.decoder.name = this.name;
2284
- decodeResult.formatted.description = "OHMA Message";
2285
- decodeResult.message = message;
2286
- decodeResult.remaining.text = "";
2287
- const data = message.text.split("OHMA")[1];
2288
- try {
2289
- const compressedBuffer = Buffer.from(data, "base64");
2290
- const decompress = new zlib.Inflate({ windowBits: 15 });
2291
- decompress.write(compressedBuffer);
2292
- decompress.flush(zlib.constants.Z_SYNC_FLUSH);
2293
- const result = decompress.read();
2294
- const jsonText = result.toString();
2295
- let formattedMsg;
2296
- let jsonMessage;
2297
- try {
2298
- jsonMessage = JSON.parse(jsonText).message;
2299
- } catch {
2300
- jsonMessage = jsonText;
2301
- }
2302
- try {
2303
- const ohmaMsg = JSON.parse(jsonMessage);
2304
- formattedMsg = JSON.stringify(ohmaMsg, null, 2);
2305
- } catch {
2306
- formattedMsg = jsonMessage;
2307
- }
2308
- decodeResult.decoded = true;
2309
- decodeResult.decoder.decodeLevel = "full";
2310
- decodeResult.raw.ohma = jsonText;
2311
- decodeResult.formatted.items.push({
2312
- type: "ohma",
2313
- code: "OHMA",
2314
- label: "OHMA Downlink",
2315
- value: formattedMsg
2316
- });
2317
- } catch (e) {
2318
- if (options.debug) {
2319
- console.log(`Decoder: Unknown H1 OHMA message: ${message.text}`, e);
2320
- }
2321
- decodeResult.remaining.text += message.text;
2322
- decodeResult.decoded = false;
2323
- decodeResult.decoder.decodeLevel = "none";
2324
- }
2325
- return decodeResult;
2326
- }
2327
- };
2328
-
2329
- // lib/plugins/Label_H1_WRN.ts
2330
- var Label_H1_WRN = class extends DecoderPlugin {
2331
- name = "label-h1-wrn";
2332
- qualifiers() {
2333
- return {
2334
- labels: ["H1"],
2335
- preambles: ["WRN", "#CFBWRN"]
2336
- };
2337
- }
2338
- decode(message, options = {}) {
2339
- let decodeResult = this.defaultResult();
2340
- decodeResult.decoder.name = this.name;
2341
- decodeResult.formatted.description = "Warning Message";
2342
- decodeResult.message = message;
2343
- const parts = message.text.split("/WN");
2344
- if (parts.length > 1) {
2345
- decodeResult.remaining.text = "";
2346
- const fields = parts[0].split("/");
2347
- for (let i = 1; i < fields.length; i++) {
2348
- const field = fields[i];
2349
- if (field.startsWith("PN")) {
2350
- processUnknown2(decodeResult, "/" + field);
2351
- } else {
2352
- processUnknown2(decodeResult, "/" + field);
2353
- }
2354
- }
2355
- const data = parts[1].substring(0, 20);
2356
- const msg = parts[1].substring(20);
2357
- const datetime = data.substring(0, 12);
2358
- const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
2359
- processUnknown2(decodeResult, data.substring(12));
2360
- decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
2361
- decodeResult.raw.warning_message = msg;
2362
- decodeResult.formatted.items.push({
2363
- type: "warning",
2364
- code: "WRN",
2365
- label: "Warning Message",
2366
- value: decodeResult.raw.warning_message
2367
- });
2368
- decodeResult.decoded = true;
2369
- decodeResult.decoder.decodeLevel = "partial";
2370
- } else {
2371
- if (options.debug) {
2372
- console.log(`Decoder: Unknown H1 message: ${message.text}`);
2373
- }
2374
- decodeResult.remaining.text = message.text;
2375
- decodeResult.decoded = false;
2376
- decodeResult.decoder.decodeLevel = "none";
2377
- }
2378
- return decodeResult;
2379
- }
2380
- };
2381
- function processUnknown2(decodeResult, value) {
2382
- decodeResult.remaining.text += value;
2383
- }
2384
-
2385
- // lib/utils/flight_plan_utils.ts
2386
- var FlightPlanUtils = class _FlightPlanUtils {
2387
- /**
2388
- * Processes flight plan data
2389
- *
2390
- * Expected format is [header, key1, val1, ... keyN, valN]
2391
- *
2392
- * @param decodeResult - results
2393
- * @param data - original message split by ':'
2394
- * @returns whether all fields were processed or not
2395
- */
2396
- static processFlightPlan(decodeResult, data) {
2397
- let allKnownFields = _FlightPlanUtils.parseHeader(decodeResult, data[0]);
2398
- for (let i = 1; i < data.length; i += 2) {
2399
- const key = data[i];
2400
- const value = data[i + 1];
2401
- switch (key) {
2402
- case "A":
2403
- addProcedure(decodeResult, value, "arrival");
2404
- break;
2405
- case "AA":
2406
- addArrivalAirport(decodeResult, value);
2407
- break;
2408
- case "AP":
2409
- addProcedure(decodeResult, value, "approach");
2410
- break;
2411
- case "CR":
2412
- addCompanyRoute(decodeResult, value);
2413
- break;
2414
- case "D":
2415
- addProcedure(decodeResult, value, "departure");
2416
- break;
2417
- case "DA":
2418
- addDepartureAirport(decodeResult, value);
2419
- break;
2420
- case "F":
2421
- addRoute(decodeResult, value);
2422
- break;
2423
- case "R":
2424
- addRunway(decodeResult, value);
2425
- break;
2426
- default:
2427
- if (allKnownFields) {
2428
- decodeResult.remaining.text = "";
2429
- allKnownFields = false;
2430
- }
2431
- decodeResult.remaining.text += `:${key}:${value}`;
2432
- decodeResult.decoder.decodeLevel = "partial";
2433
- }
2434
- }
2435
- return allKnownFields;
2436
- }
2437
- static parseHeader(decodeResult, header) {
2438
- let allKnownFields = true;
2439
- if (header.startsWith("RF")) {
2440
- decodeResult.formatted.items.push({
2441
- type: "status",
2442
- code: "ROUTE_STATUS",
2443
- label: "Route Status",
2444
- value: "Route Filed"
2445
- });
2446
- decodeResult.raw.route_status = "RF";
2447
- if (header.length > 2) {
2448
- addRoute(decodeResult, header.substring(2));
2449
- }
2450
- } else if (header.startsWith("RP")) {
2451
- decodeResult.raw.route_status = "RP";
2452
- decodeResult.formatted.items.push({
2453
- type: "status",
2454
- code: "ROUTE_STATUS",
2455
- label: "Route Status",
2456
- value: "Route Planned"
2457
- });
2458
- decodeResult.raw.route_status = header;
2459
- } else if (header.startsWith("RI")) {
2460
- decodeResult.raw.route_status = "RI";
2461
- decodeResult.formatted.items.push({
2462
- type: "status",
2463
- code: "ROUTE_STATUS",
2464
- label: "Route Status",
2465
- value: "Route Inactive"
2466
- });
2467
- } else {
2468
- decodeResult.remaining.text += header;
2469
- allKnownFields = false;
2201
+ decodeResult.remaining.text += header;
2202
+ allKnownFields = false;
2470
2203
  }
2471
2204
  return allKnownFields;
2472
2205
  }
@@ -2485,13 +2218,7 @@ function addRunway(decodeResult, value) {
2485
2218
  }
2486
2219
  function addRoute(decodeResult, value) {
2487
2220
  const route = value.split(".");
2488
- decodeResult.raw.route = { waypoints: route.map((leg) => RouteUtils.getWaypoint(leg)) };
2489
- decodeResult.formatted.items.push({
2490
- type: "aircraft_route",
2491
- code: "ROUTE",
2492
- label: "Aircraft Route",
2493
- value: RouteUtils.routeToString(decodeResult.raw.route)
2494
- });
2221
+ ResultFormatter.route(decodeResult, { waypoints: route.map((leg) => RouteUtils.getWaypoint(leg)) });
2495
2222
  }
2496
2223
  function addProcedure(decodeResult, value, type) {
2497
2224
  if (decodeResult.raw.procedures === void 0) {
@@ -2541,257 +2268,652 @@ function addCompanyRoute(decodeResult, value) {
2541
2268
  });
2542
2269
  }
2543
2270
 
2544
- // lib/utils/h1_helper.ts
2545
- var H1Helper = class {
2546
- static decodeH1Message(decodeResult, message) {
2547
- const checksum = message.slice(-4);
2548
- const data = message.slice(0, message.length - 4);
2549
- const fields = data.split("/");
2550
- parseMessageType(decodeResult, fields[0]);
2551
- for (let i = 1; i < fields.length; ++i) {
2552
- if (fields[i].startsWith("FN")) {
2553
- decodeResult.raw.flight_number = fields[i].substring(2);
2554
- } else if (fields[i].startsWith("SN")) {
2555
- decodeResult.raw.serial_number = fields[i].substring(2);
2556
- } else if (fields[i].startsWith("DC")) {
2557
- processDC(decodeResult, fields[i].substring(2).split(","));
2558
- } else if (fields[i].startsWith("TS")) {
2559
- const ts = fields[i].substring(2).split(",");
2560
- let time = DateTimeUtils.convertDateTimeToEpoch(ts[0], ts[1]);
2561
- if (Number.isNaN(time)) {
2562
- const date = ts[1].substring(2, 4) + ts[1].substring(0, 2) + ts[1].substring(4, 6);
2563
- time = DateTimeUtils.convertDateTimeToEpoch(ts[0], date);
2564
- }
2565
- decodeResult.raw.message_date = ts[1];
2566
- decodeResult.raw.message_timestamp = time;
2567
- } else if (fields[i].startsWith("PS")) {
2568
- const pos = processPS(decodeResult, fields[i].substring(2).split(","));
2569
- } else if (fields[i].startsWith("DT")) {
2570
- const data2 = fields[i].substring(2).split(",");
2571
- processDT(decodeResult, data2);
2572
- } else if (fields[i].startsWith("ID")) {
2573
- processIdentification(decodeResult, fields[i].substring(2).split(","));
2574
- } else if (fields[i].startsWith("LR")) {
2575
- const data2 = fields[i].substring(2).split(",");
2576
- processLR(decodeResult, data2);
2577
- } else if (fields[i].startsWith("RI") || fields[i].startsWith("RF") || fields[i].startsWith("RP")) {
2578
- FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
2579
- } else if (fields[i].startsWith("PR")) {
2580
- decodeResult.remaining.text += "/" + fields[i];
2581
- } else if (fields[i].startsWith("AF")) {
2582
- processAirField(decodeResult, fields[i].substring(2).split(","));
2583
- } else if (fields[i].startsWith("TD")) {
2584
- processTimeOfDeparture(decodeResult, fields[i].substring(2).split(","));
2585
- } else if (fields[i].startsWith("FX")) {
2586
- decodeResult.raw.free_text = fields[i].substring(2);
2271
+ // lib/utils/h1_helper.ts
2272
+ var H1Helper = class {
2273
+ static decodeH1Message(decodeResult, message) {
2274
+ const checksum = message.slice(-4);
2275
+ const data = message.slice(0, message.length - 4);
2276
+ const fields = data.split("/");
2277
+ parseMessageType(decodeResult, fields[0]);
2278
+ for (let i = 1; i < fields.length; ++i) {
2279
+ if (fields[i].startsWith("FN")) {
2280
+ decodeResult.raw.flight_number = fields[i].substring(2);
2281
+ } else if (fields[i].startsWith("SN")) {
2282
+ decodeResult.raw.serial_number = fields[i].substring(2);
2283
+ } else if (fields[i].startsWith("DC")) {
2284
+ processDC(decodeResult, fields[i].substring(2).split(","));
2285
+ } else if (fields[i].startsWith("TS")) {
2286
+ const ts = fields[i].substring(2).split(",");
2287
+ let time = DateTimeUtils.convertDateTimeToEpoch(ts[0], ts[1]);
2288
+ if (Number.isNaN(time)) {
2289
+ const date = ts[1].substring(2, 4) + ts[1].substring(0, 2) + ts[1].substring(4, 6);
2290
+ time = DateTimeUtils.convertDateTimeToEpoch(ts[0], date);
2291
+ }
2292
+ decodeResult.raw.message_date = ts[1];
2293
+ decodeResult.raw.message_timestamp = time;
2294
+ } else if (fields[i].startsWith("PS")) {
2295
+ const pos = processPS(decodeResult, fields[i].substring(2).split(","));
2296
+ } else if (fields[i].startsWith("DT")) {
2297
+ const data2 = fields[i].substring(2).split(",");
2298
+ processDT(decodeResult, data2);
2299
+ } else if (fields[i].startsWith("ID")) {
2300
+ processIdentification(decodeResult, fields[i].substring(2).split(","));
2301
+ } else if (fields[i].startsWith("LR")) {
2302
+ const data2 = fields[i].substring(2).split(",");
2303
+ processLR(decodeResult, data2);
2304
+ } else if (fields[i].startsWith("RI") || fields[i].startsWith("RF") || fields[i].startsWith("RP")) {
2305
+ FlightPlanUtils.processFlightPlan(decodeResult, fields[i].split(":"));
2306
+ } else if (fields[i].startsWith("PR")) {
2307
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
2308
+ } else if (fields[i].startsWith("AF")) {
2309
+ processAirField(decodeResult, fields[i].substring(2).split(","));
2310
+ } else if (fields[i].startsWith("TD")) {
2311
+ processTimeOfDeparture(decodeResult, fields[i].substring(2).split(","));
2312
+ } else if (fields[i].startsWith("FX")) {
2313
+ ResultFormatter.freetext(decodeResult, fields[i].substring(2));
2314
+ } else if (fields[i].startsWith("ET")) {
2315
+ if (fields[i].length === 7) {
2316
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(3) + "00"));
2317
+ } else if (fields[i].length === 8) {
2318
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[i].substring(4) + "00"));
2319
+ } else {
2320
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
2321
+ }
2322
+ } else {
2323
+ ResultFormatter.unknown(decodeResult, fields[i], "/");
2324
+ }
2325
+ }
2326
+ if (decodeResult.formatted.items.length > 0) {
2327
+ ResultFormatter.checksum(decodeResult, checksum);
2328
+ }
2329
+ return true;
2330
+ }
2331
+ };
2332
+ function processAirField(decodeResult, data) {
2333
+ if (data.length === 2) {
2334
+ ResultFormatter.departureAirport(decodeResult, data[0]);
2335
+ ResultFormatter.arrivalAirport(decodeResult, data[1]);
2336
+ } else {
2337
+ ResultFormatter.unknown(decodeResult, data.join(","), "AF/");
2338
+ }
2339
+ }
2340
+ function processTimeOfDeparture(decodeResult, data) {
2341
+ if (data.length === 2) {
2342
+ decodeResult.raw.plannedDepartureTime = data[0];
2343
+ decodeResult.formatted.items.push({
2344
+ type: "ptd",
2345
+ code: "ptd",
2346
+ label: "Planned Departure Time",
2347
+ value: `YYYY-MM-${data[0].substring(0, 2)}T${data[0].substring(2, 4)}:${data[0].substring(4)}:00Z`
2348
+ });
2349
+ decodeResult.raw.plannedDepartureTime = data[1];
2350
+ decodeResult.formatted.items.push({
2351
+ type: "etd",
2352
+ code: "etd",
2353
+ label: "Estimated Departure Time",
2354
+ value: `${data[1].substring(0, 2)}:${data[1].substring(2)}`
2355
+ });
2356
+ } else {
2357
+ ResultFormatter.unknown(decodeResult, data.join(","), "/TD");
2358
+ }
2359
+ }
2360
+ function processIdentification(decodeResult, data) {
2361
+ ResultFormatter.tail(decodeResult, data[0]);
2362
+ if (data.length > 1) {
2363
+ decodeResult.raw.flight_number = data[1];
2364
+ }
2365
+ if (data.length > 2) {
2366
+ decodeResult.raw.mission_number = data[2];
2367
+ }
2368
+ }
2369
+ function processDT(decodeResult, data) {
2370
+ if (!decodeResult.raw.arrival_icao) {
2371
+ ResultFormatter.arrivalAirport(decodeResult, data[0]);
2372
+ } else if (decodeResult.raw.arrival_icao != data[0]) {
2373
+ ResultFormatter.unknownArr(decodeResult, data);
2374
+ }
2375
+ if (data.length > 1) {
2376
+ ResultFormatter.arrivalRunway(decodeResult, data[1]);
2377
+ }
2378
+ if (data.length > 2) {
2379
+ ResultFormatter.currentFuel(decodeResult, Number(data[2]));
2380
+ }
2381
+ if (data.length > 3) {
2382
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[3]));
2383
+ }
2384
+ if (data.length > 4) {
2385
+ ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
2386
+ }
2387
+ if (data.length > 5) {
2388
+ ResultFormatter.unknownArr(decodeResult, data);
2389
+ }
2390
+ }
2391
+ function processLR(decodeResult, data) {
2392
+ if (data.length === 19) {
2393
+ ResultFormatter.unknown(decodeResult, data[1]);
2394
+ ResultFormatter.flightNumber(decodeResult, data[2]);
2395
+ ResultFormatter.departureAirport(decodeResult, data[3]);
2396
+ ResultFormatter.arrivalAirport(decodeResult, data[4]);
2397
+ ResultFormatter.arrivalRunway(decodeResult, data[5]);
2398
+ ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
2399
+ } else {
2400
+ ResultFormatter.unknown(decodeResult, data.join(","));
2401
+ }
2402
+ }
2403
+ function parseMessageType(decodeResult, messageType) {
2404
+ const parts = messageType.split("#");
2405
+ if (parts.length == 1) {
2406
+ const type = parts[0].substring(0, 3);
2407
+ if (type === "POS" && parts[0].length !== 3) {
2408
+ processPosition2(decodeResult, parts[0].substring(3).split(","));
2409
+ }
2410
+ return processMessageType(decodeResult, type);
2411
+ } else if (parts.length == 2) {
2412
+ if (parts[0].length > 0) {
2413
+ ResultFormatter.unknown(decodeResult, parts[0].substring(0, 3));
2414
+ decodeResult.raw.flight_number = parts[0].substring(3);
2415
+ ResultFormatter.unknown(decodeResult, parts[1].length == 5 ? parts[1].substring(0, 2) : parts[1].substring(0, 3), "#");
2416
+ }
2417
+ const type = parts[1].length == 5 ? parts[1].substring(2, 5) : parts[1].substring(3, 6);
2418
+ if (parts[1].substring(3, 6) === "POS" && parts[1].length > 6) {
2419
+ processPosition2(decodeResult, parts[1].substring(6).split(","));
2420
+ }
2421
+ processMessageType(decodeResult, type);
2422
+ } else {
2423
+ ResultFormatter.unknown(decodeResult, messageType);
2424
+ }
2425
+ }
2426
+ function processMessageType(decodeResult, type) {
2427
+ if (type === "FPN") {
2428
+ decodeResult.formatted.description = "Flight Plan";
2429
+ } else if (type === "FTX") {
2430
+ decodeResult.formatted.description = "Free Text";
2431
+ } else if (type === "INI") {
2432
+ decodeResult.formatted.description = "Flight Plan Initial Report";
2433
+ } else if (type === "POS") {
2434
+ decodeResult.formatted.description = "Position Report";
2435
+ } else if (type === "PRG") {
2436
+ decodeResult.formatted.description = "Progress Report";
2437
+ } else {
2438
+ decodeResult.formatted.description = "Unknown H1 Message";
2439
+ }
2440
+ }
2441
+ function processDC(decodeResult, data) {
2442
+ decodeResult.raw.message_date = data[0];
2443
+ if (data.length === 1) {
2444
+ } else if (data.length === 2) {
2445
+ const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
2446
+ const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
2447
+ decodeResult.raw.message_timestamp = time;
2448
+ }
2449
+ }
2450
+ function processPS(decodeResult, data) {
2451
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2452
+ if (position) {
2453
+ decodeResult.raw.position = position;
2454
+ decodeResult.formatted.items.push({
2455
+ type: "aircraft_position",
2456
+ code: "POS",
2457
+ label: "Aircraft Position",
2458
+ value: CoordinateUtils.coordinateString(position)
2459
+ });
2460
+ }
2461
+ if (data.length === 9) {
2462
+ processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
2463
+ ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
2464
+ ResultFormatter.temperature(decodeResult, data[6]);
2465
+ ResultFormatter.unknown(decodeResult, data[7]);
2466
+ ResultFormatter.unknown(decodeResult, data[8]);
2467
+ }
2468
+ if (data.length === 14) {
2469
+ ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2470
+ processRoute(decodeResult, data[4], data[2], data[6], data[5], void 0);
2471
+ ResultFormatter.temperature(decodeResult, data[7]);
2472
+ ResultFormatter.groundspeed(decodeResult, Number(data[10]));
2473
+ ResultFormatter.unknown(decodeResult, data[1]);
2474
+ ResultFormatter.unknown(decodeResult, data[8]);
2475
+ ResultFormatter.unknown(decodeResult, data[9]);
2476
+ ResultFormatter.unknown(decodeResult, data.slice(11).join(","));
2477
+ }
2478
+ }
2479
+ function processPosition2(decodeResult, data) {
2480
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2481
+ if (position) {
2482
+ decodeResult.raw.position = position;
2483
+ decodeResult.formatted.items.push({
2484
+ type: "aircraft_position",
2485
+ code: "POS",
2486
+ label: "Aircraft Position",
2487
+ value: CoordinateUtils.coordinateString(position)
2488
+ });
2489
+ }
2490
+ if (data.length >= 10) {
2491
+ ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2492
+ processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
2493
+ ResultFormatter.temperature(decodeResult, data[7]);
2494
+ ResultFormatter.unknown(decodeResult, data[8]);
2495
+ ResultFormatter.unknown(decodeResult, data[9]);
2496
+ }
2497
+ if (data.length >= 14) {
2498
+ ResultFormatter.groundspeed(decodeResult, Number(data[10]));
2499
+ ResultFormatter.unknown(decodeResult, data[11]);
2500
+ ResultFormatter.unknown(decodeResult, data[12]);
2501
+ ResultFormatter.unknown(decodeResult, data[13]);
2502
+ }
2503
+ }
2504
+ function processRoute(decodeResult, last, time, next, eta, then, date) {
2505
+ const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
2506
+ const nextTime = date ? DateTimeUtils.convertDateTimeToEpoch(eta, date) : DateTimeUtils.convertHHMMSSToTod(eta);
2507
+ const timeFormat = date ? "epoch" : "tod";
2508
+ const lastWaypoint = RouteUtils.getWaypoint(last);
2509
+ lastWaypoint.time = lastTime;
2510
+ lastWaypoint.timeFormat = timeFormat;
2511
+ const nextWaypoint = RouteUtils.getWaypoint(next);
2512
+ nextWaypoint.time = nextTime;
2513
+ nextWaypoint.timeFormat = timeFormat;
2514
+ const thenWaypoint = RouteUtils.getWaypoint(then || "?");
2515
+ const waypoints = [lastWaypoint, nextWaypoint, thenWaypoint];
2516
+ decodeResult.raw.route = { waypoints };
2517
+ decodeResult.formatted.items.push({
2518
+ type: "aircraft_route",
2519
+ code: "ROUTE",
2520
+ label: "Aircraft Route",
2521
+ value: RouteUtils.routeToString(decodeResult.raw.route)
2522
+ });
2523
+ }
2524
+
2525
+ // lib/plugins/Label_4J_POS.ts
2526
+ var Label_4J_POS = class extends DecoderPlugin {
2527
+ name = "label-4j-pos";
2528
+ qualifiers() {
2529
+ return {
2530
+ labels: ["4J"],
2531
+ preambles: ["POS/"]
2532
+ };
2533
+ }
2534
+ // copied from Label_H1.ts since i don't really want to have to have
2535
+ // something named like that decode more than 1 type
2536
+ // if we figure out a good name, i'll combine them
2537
+ decode(message, options = {}) {
2538
+ let decodeResult = this.defaultResult();
2539
+ decodeResult.decoder.name = this.name;
2540
+ decodeResult.message = message;
2541
+ const msg = message.text.replace(/\n|\r/g, "");
2542
+ const decoded = H1Helper.decodeH1Message(decodeResult, msg);
2543
+ decodeResult.decoded = decoded;
2544
+ decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
2545
+ if (decodeResult.formatted.items.length === 0) {
2546
+ if (options.debug) {
2547
+ console.log(`Decoder: Unknown H1 message: ${message.text}`);
2548
+ }
2549
+ ResultFormatter.unknown(decodeResult, message.text);
2550
+ decodeResult.decoded = false;
2551
+ decodeResult.decoder.decodeLevel = "none";
2552
+ }
2553
+ return decodeResult;
2554
+ }
2555
+ };
2556
+
2557
+ // lib/plugins/Label_4N.ts
2558
+ var Label_4N = class extends DecoderPlugin {
2559
+ name = "label-4n";
2560
+ qualifiers() {
2561
+ return {
2562
+ labels: ["4N"]
2563
+ };
2564
+ }
2565
+ decode(message, options = {}) {
2566
+ const decodeResult = this.defaultResult();
2567
+ decodeResult.decoder.name = this.name;
2568
+ decodeResult.message = message;
2569
+ decodeResult.formatted.description = "Airline Defined";
2570
+ let text = message.text;
2571
+ if (text.match(/^M\d{2}A\w{6}/)) {
2572
+ ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
2573
+ text = text.substring(10);
2574
+ }
2575
+ decodeResult.decoded = true;
2576
+ const fields = text.split(",");
2577
+ if (text.length === 51) {
2578
+ decodeResult.raw.day_of_month = text.substring(0, 2);
2579
+ ResultFormatter.departureAirport(decodeResult, text.substring(8, 11));
2580
+ ResultFormatter.arrivalAirport(decodeResult, text.substring(13, 16));
2581
+ ResultFormatter.position(decodeResult, CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(30, 45).replace(/^(.)0/, "$1")));
2582
+ ResultFormatter.altitude(decodeResult, Number(text.substring(48, 51)) * 100);
2583
+ ResultFormatter.unknownArr(decodeResult, [text.substring(2, 4), text.substring(19, 29)], " ");
2584
+ } else if (fields.length === 33) {
2585
+ decodeResult.raw.date = fields[3];
2586
+ if (fields[1] === "B") {
2587
+ ResultFormatter.position(decodeResult, { latitude: Number(fields[4]), longitude: Number(fields[5]) });
2588
+ ResultFormatter.altitude(decodeResult, Number(fields[6]));
2589
+ }
2590
+ ResultFormatter.departureAirport(decodeResult, fields[8]);
2591
+ ResultFormatter.arrivalAirport(decodeResult, fields[9]);
2592
+ ResultFormatter.alternateAirport(decodeResult, fields[10]);
2593
+ ResultFormatter.arrivalRunway(decodeResult, fields[11].split("/")[0]);
2594
+ if (fields[12].length > 1) {
2595
+ ResultFormatter.alternateRunway(decodeResult, fields[12].split("/")[0]);
2596
+ }
2597
+ ResultFormatter.checksum(decodeResult, fields[32]);
2598
+ ResultFormatter.unknownArr(decodeResult, [...fields.slice(1, 3), fields[7], ...fields.slice(13, 32)].filter((f) => f != ""));
2599
+ } else {
2600
+ decodeResult.decoded = false;
2601
+ ResultFormatter.unknown(decodeResult, text);
2602
+ }
2603
+ if (decodeResult.decoded) {
2604
+ if (!decodeResult.remaining.text)
2605
+ decodeResult.decoder.decodeLevel = "full";
2606
+ else
2607
+ decodeResult.decoder.decodeLevel = "partial";
2608
+ } else {
2609
+ decodeResult.decoder.decodeLevel = "none";
2610
+ }
2611
+ return decodeResult;
2612
+ }
2613
+ };
2614
+
2615
+ // lib/plugins/Label_80.ts
2616
+ var Label_80 = class extends DecoderPlugin {
2617
+ name = "label-80";
2618
+ descriptions = {
2619
+ ALT: "Altitude",
2620
+ DWND: "Wind Direction",
2621
+ ETA: "Estimated Time of Arrival",
2622
+ FOB: "Fuel on Board",
2623
+ FL: "Flight Level",
2624
+ HDG: "Heading",
2625
+ MCH: "Aircraft Speed",
2626
+ NWYP: "Next Waypoint",
2627
+ POS: "Aircraft Position",
2628
+ SAT: "Static Air Temperature",
2629
+ SWND: "Wind Speed",
2630
+ TAS: "True Airspeed",
2631
+ WYP: "Waypoint"
2632
+ };
2633
+ qualifiers() {
2634
+ return {
2635
+ labels: ["80"],
2636
+ preambles: ["3N01 POSRPT"]
2637
+ };
2638
+ }
2639
+ decode(message, options = {}) {
2640
+ const decodeResult = this.defaultResult();
2641
+ decodeResult.decoder.name = this.name;
2642
+ decodeResult.formatted.description = "Airline Defined Position Report";
2643
+ const parts = message.text.split("\n");
2644
+ let posRptRegex = /^3N01 POSRPT \d\d\d\d\/\d\d (?<orig>\w+)\/(?<dest>\w+) \.(?<tail>[\w-]+)(\/(?<agate>.+) (?<sta>\w+:\w+))*/;
2645
+ let results = parts[0].match(posRptRegex);
2646
+ if (!results?.groups) {
2647
+ decodeResult.decoded = false;
2648
+ decodeResult.decoder.decodeLevel = "none";
2649
+ return decodeResult;
2650
+ }
2651
+ if (results && results.length > 0) {
2652
+ ResultFormatter.departureAirport(decodeResult, results.groups.orig);
2653
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.dest);
2654
+ ResultFormatter.tail(decodeResult, results.groups.tail);
2655
+ if (results.groups.agate) {
2656
+ decodeResult.raw.arrival_gate = results.groups.agate;
2587
2657
  decodeResult.formatted.items.push({
2588
- type: "text",
2589
- code: "TEXT",
2590
- label: "Free Text",
2591
- value: decodeResult.raw.free_text
2658
+ type: "arrival_gate",
2659
+ code: "ARG",
2660
+ label: "Arrival Gate",
2661
+ value: `${results.groups.agate}`
2662
+ });
2663
+ decodeResult.raw.scheduled_time_of_arrival = results.groups.sta;
2664
+ decodeResult.formatted.items.push({
2665
+ type: "scheduled_time_of_arrival",
2666
+ code: "STA",
2667
+ label: "Scheduled Time of Arrival",
2668
+ value: `${results.groups.sta}`
2592
2669
  });
2593
- } else {
2594
- decodeResult.remaining.text += "/" + fields[i];
2595
2670
  }
2671
+ posRptRegex = /\/(?<field>\w+)\s(?<value>[\w\+\-:\.]+)\s*/gi;
2672
+ const remainingParts = parts.slice(1);
2673
+ for (const part of remainingParts) {
2674
+ const matches = part.matchAll(posRptRegex);
2675
+ for (const match of matches) {
2676
+ switch (match.groups?.field) {
2677
+ case "ALT": {
2678
+ ResultFormatter.altitude(decodeResult, Number(match.groups.value));
2679
+ break;
2680
+ }
2681
+ case "DWND": {
2682
+ decodeResult.raw.wind_direction = Number(match.groups.value);
2683
+ decodeResult.formatted.items.push({
2684
+ type: "wind_direction",
2685
+ code: "DWND",
2686
+ label: this.descriptions[match.groups.field],
2687
+ value: decodeResult.raw.wind_direction
2688
+ });
2689
+ break;
2690
+ }
2691
+ case "FL": {
2692
+ const flight_level = Number(match.groups.value);
2693
+ ResultFormatter.altitude(decodeResult, flight_level * 100);
2694
+ break;
2695
+ }
2696
+ case "FOB": {
2697
+ const fob = Number(match.groups.value);
2698
+ if (!isNaN(fob)) {
2699
+ ResultFormatter.currentFuel(decodeResult, fob);
2700
+ }
2701
+ break;
2702
+ }
2703
+ case "HDG": {
2704
+ ResultFormatter.heading(decodeResult, Number(match.groups.value));
2705
+ break;
2706
+ }
2707
+ case "MCH": {
2708
+ decodeResult.raw.mach = Number(match.groups.value) / 1e3;
2709
+ decodeResult.formatted.items.push({
2710
+ type: "mach",
2711
+ code: "MCH",
2712
+ label: this.descriptions[match.groups.field],
2713
+ value: `${decodeResult.raw.mach} Mach`
2714
+ });
2715
+ break;
2716
+ }
2717
+ case "NWYP": {
2718
+ decodeResult.raw.next_waypoint = match.groups.value;
2719
+ decodeResult.formatted.items.push({
2720
+ type: "next_waypoint",
2721
+ code: "NWYP",
2722
+ label: this.descriptions[match.groups.field],
2723
+ value: decodeResult.raw.next_waypoint
2724
+ });
2725
+ break;
2726
+ }
2727
+ case "POS": {
2728
+ const posRegex = /^(?<latd>[NS])(?<lat>.+)(?<lngd>[EW])(?<lng>.+)/;
2729
+ const posResult = match.groups.value.match(posRegex);
2730
+ const lat = Number(posResult?.groups?.lat) * (posResult?.groups?.lngd === "S" ? -1 : 1);
2731
+ const lon = Number(posResult?.groups?.lng) * (posResult?.groups?.lngd === "W" ? -1 : 1);
2732
+ const position = {
2733
+ latitude: Number.isInteger(lat) ? lat / 1e3 : lat / 100,
2734
+ longitude: Number.isInteger(lon) ? lon / 1e3 : lon / 100
2735
+ };
2736
+ ResultFormatter.position(decodeResult, position);
2737
+ break;
2738
+ }
2739
+ case "SWND": {
2740
+ decodeResult.raw.wind_speed = Number(match.groups.value);
2741
+ decodeResult.formatted.items.push({
2742
+ type: "wind_speed",
2743
+ code: "SWND",
2744
+ label: this.descriptions[match.groups.field],
2745
+ value: decodeResult.raw.wind_speed
2746
+ });
2747
+ break;
2748
+ }
2749
+ default: {
2750
+ if (match.groups?.field != void 0) {
2751
+ const description = this.descriptions[match.groups.field] ? this.descriptions[match.groups.field] : "Unknown";
2752
+ decodeResult.formatted.items.push({
2753
+ type: match.groups.field,
2754
+ code: match.groups.field,
2755
+ label: description || `Unknown (${match.groups.field})`,
2756
+ value: `${match.groups.value}`
2757
+ });
2758
+ }
2759
+ }
2760
+ }
2761
+ }
2762
+ }
2763
+ decodeResult.decoded = true;
2764
+ decodeResult.decoder.decodeLevel = "partial";
2596
2765
  }
2597
- if (decodeResult.formatted.items.length > 0) {
2598
- ResultFormatter.checksum(decodeResult, checksum);
2599
- }
2600
- return true;
2766
+ return decodeResult;
2601
2767
  }
2602
2768
  };
2603
- function processAirField(decodeResult, data) {
2604
- if (data.length === 2) {
2605
- ResultFormatter.departureAirport(decodeResult, data[0]);
2606
- ResultFormatter.arrivalAirport(decodeResult, data[1]);
2607
- } else {
2608
- decodeResult.remaining.text += "AF/" + data.join(",");
2609
- }
2610
- }
2611
- function processTimeOfDeparture(decodeResult, data) {
2612
- if (data.length === 2) {
2613
- decodeResult.raw.plannedDepartureTime = data[0];
2614
- decodeResult.formatted.items.push({
2615
- type: "ptd",
2616
- code: "ptd",
2617
- label: "Planned Departure Time",
2618
- value: `YYYY-MM-${data[0].substring(0, 2)}T${data[0].substring(2, 4)}:${data[0].substring(4)}:00Z`
2619
- });
2620
- decodeResult.raw.plannedDepartureTime = data[1];
2621
- decodeResult.formatted.items.push({
2622
- type: "etd",
2623
- code: "etd",
2624
- label: "Estimated Departure Time",
2625
- value: `${data[1].substring(0, 2)}:${data[1].substring(2)}`
2626
- });
2627
- } else {
2628
- decodeResult.remaining.text += "/TD" + data.join(",");
2629
- }
2630
- }
2631
- function processIdentification(decodeResult, data) {
2632
- ResultFormatter.tail(decodeResult, data[0]);
2633
- if (data.length > 1) {
2634
- decodeResult.raw.flight_number = data[1];
2635
- }
2636
- if (data.length > 2) {
2637
- decodeResult.raw.mission_number = data[2];
2638
- }
2639
- }
2640
- function processDT(decodeResult, data) {
2641
- if (!decodeResult.raw.arrival_icao) {
2642
- ResultFormatter.arrivalAirport(decodeResult, data[0]);
2643
- } else if (decodeResult.raw.arrival_icao != data[0]) {
2644
- decodeResult.remaining.text += "/" + data;
2645
- }
2646
- if (data.length > 1) {
2647
- ResultFormatter.arrivalRunway(decodeResult, data[1]);
2648
- }
2649
- if (data.length > 2) {
2650
- ResultFormatter.currentFuel(decodeResult, Number(data[2]));
2651
- }
2652
- if (data.length > 3) {
2653
- ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(data[3]));
2654
- }
2655
- if (data.length > 4) {
2656
- ResultFormatter.remainingFuel(decodeResult, Number(data[4]));
2657
- }
2658
- if (data.length > 5) {
2659
- decodeResult.remaining.text += "," + data.slice(5).join(",");
2660
- }
2661
- }
2662
- function processLR(decodeResult, data) {
2663
- if (data.length === 19) {
2664
- ResultFormatter.unknown(decodeResult, data[1]);
2665
- ResultFormatter.flightNumber(decodeResult, data[2]);
2666
- ResultFormatter.departureAirport(decodeResult, data[3]);
2667
- ResultFormatter.arrivalAirport(decodeResult, data[4]);
2668
- ResultFormatter.arrivalRunway(decodeResult, data[5]);
2669
- ResultFormatter.unknown(decodeResult, data.slice(6, 19).join(","));
2670
- } else {
2671
- ResultFormatter.unknown(decodeResult, data.join(","));
2769
+
2770
+ // lib/plugins/Label_83.ts
2771
+ var Label_83 = class extends DecoderPlugin {
2772
+ name = "label-83";
2773
+ qualifiers() {
2774
+ return {
2775
+ labels: ["83"]
2776
+ };
2672
2777
  }
2673
- }
2674
- function parseMessageType(decodeResult, messageType) {
2675
- const parts = messageType.split("#");
2676
- if (parts.length == 1) {
2677
- const type = parts[0].substring(0, 3);
2678
- if (type === "POS" && parts[0].length !== 3) {
2679
- processPosition2(decodeResult, parts[0].substring(3).split(","));
2778
+ decode(message, options = {}) {
2779
+ const decodeResult = this.defaultResult();
2780
+ decodeResult.decoder.name = this.name;
2781
+ decodeResult.message = message;
2782
+ decodeResult.formatted.description = "Airline Defined";
2783
+ let text = message.text;
2784
+ if (text.match(/^M\d{2}A\w{6}/)) {
2785
+ ResultFormatter.flightNumber(decodeResult, message.text.substring(4, 10).replace(/^([A-Z]+)0*/g, "$1"));
2786
+ text = text.substring(10);
2680
2787
  }
2681
- return processMessageType(decodeResult, type);
2682
- } else if (parts.length == 2) {
2683
- if (parts[0].length > 0) {
2684
- decodeResult.remaining.text += parts[0].substring(0, 3);
2685
- decodeResult.raw.flight_number = parts[0].substring(3);
2686
- decodeResult.remaining.text += "#" + (parts[1].length == 5 ? parts[1].substring(0, 2) : parts[1].substring(0, 3));
2788
+ decodeResult.decoded = true;
2789
+ if (text.substring(0, 10) === "4DH3 ETAT2") {
2790
+ const fields = text.split(/\s+/);
2791
+ if (fields[2].length > 5) {
2792
+ decodeResult.raw.day_of_month = fields[2].substring(5);
2793
+ }
2794
+ ResultFormatter.unknown(decodeResult, fields[2].substring(0, 4));
2795
+ const subfields = fields[3].split("/");
2796
+ ResultFormatter.departureAirport(decodeResult, subfields[0]);
2797
+ ResultFormatter.arrivalAirport(decodeResult, subfields[1]);
2798
+ ResultFormatter.tail(decodeResult, fields[4].replace(/\./g, ""));
2799
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(fields[6] + "00"));
2800
+ } else if (text.substring(0, 5) === "001PR") {
2801
+ decodeResult.raw.day_of_month = text.substring(5, 7);
2802
+ const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(text.substring(13, 28).replace(/\./g, ""));
2803
+ if (position) {
2804
+ ResultFormatter.position(decodeResult, position);
2805
+ }
2806
+ ResultFormatter.altitude(decodeResult, Number(text.substring(28, 33)));
2807
+ ResultFormatter.unknown(decodeResult, text.substring(33));
2808
+ } else {
2809
+ const fields = text.replace(/\s/g, "").split(",");
2810
+ if (fields.length === 9) {
2811
+ ResultFormatter.departureAirport(decodeResult, fields[0]);
2812
+ ResultFormatter.arrivalAirport(decodeResult, fields[1]);
2813
+ decodeResult.raw.day_of_month = fields[2].substring(0, 2);
2814
+ decodeResult.raw.time = fields[2].substring(2);
2815
+ ResultFormatter.position(
2816
+ decodeResult,
2817
+ {
2818
+ latitude: Number(fields[3].replace(/\s/g, "")),
2819
+ longitude: Number(fields[4].replace(/\s/g, ""))
2820
+ }
2821
+ );
2822
+ ResultFormatter.altitude(decodeResult, Number(fields[5]));
2823
+ ResultFormatter.groundspeed(decodeResult, Number(fields[6]));
2824
+ ResultFormatter.heading(decodeResult, Number(fields[7]));
2825
+ ResultFormatter.unknown(decodeResult, fields[8]);
2826
+ } else {
2827
+ decodeResult.decoded = false;
2828
+ ResultFormatter.unknown(decodeResult, message.text);
2829
+ }
2687
2830
  }
2688
- const type = parts[1].length == 5 ? parts[1].substring(2, 5) : parts[1].substring(3, 6);
2689
- if (parts[1].substring(3, 6) === "POS" && parts[1].length > 6) {
2690
- processPosition2(decodeResult, parts[1].substring(6).split(","));
2831
+ if (decodeResult.decoded) {
2832
+ if (!decodeResult.remaining.text)
2833
+ decodeResult.decoder.decodeLevel = "full";
2834
+ else
2835
+ decodeResult.decoder.decodeLevel = "partial";
2836
+ } else {
2837
+ decodeResult.decoder.decodeLevel = "none";
2691
2838
  }
2692
- processMessageType(decodeResult, type);
2693
- } else {
2694
- decodeResult.remaining.text += messageType;
2695
- }
2696
- }
2697
- function processMessageType(decodeResult, type) {
2698
- if (type === "FPN") {
2699
- decodeResult.formatted.description = "Flight Plan";
2700
- } else if (type === "FTX") {
2701
- decodeResult.formatted.description = "Free Text";
2702
- } else if (type === "INI") {
2703
- decodeResult.formatted.description = "Flight Plan Initial Report";
2704
- } else if (type === "POS") {
2705
- decodeResult.formatted.description = "Position Report";
2706
- } else if (type === "PRG") {
2707
- decodeResult.formatted.description = "Progress Report";
2708
- } else {
2709
- decodeResult.formatted.description = "Unknown H1 Message";
2710
- }
2711
- }
2712
- function processDC(decodeResult, data) {
2713
- decodeResult.raw.message_date = data[0];
2714
- if (data.length === 1) {
2715
- } else if (data.length === 2) {
2716
- const date = data[0].substring(2, 4) + data[0].substring(0, 2) + data[0].substring(4, 6);
2717
- const time = DateTimeUtils.convertDateTimeToEpoch(data[1], data[0]);
2718
- decodeResult.raw.message_timestamp = time;
2839
+ return decodeResult;
2719
2840
  }
2720
- }
2721
- function processPS(decodeResult, data) {
2722
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2723
- if (position) {
2724
- decodeResult.raw.position = position;
2725
- decodeResult.formatted.items.push({
2726
- type: "aircraft_position",
2727
- code: "POS",
2728
- label: "Aircraft Position",
2729
- value: CoordinateUtils.coordinateString(position)
2730
- });
2841
+ };
2842
+
2843
+ // lib/plugins/Label_8E.ts
2844
+ var Label_8E = class extends DecoderPlugin {
2845
+ name = "label-8e";
2846
+ qualifiers() {
2847
+ return {
2848
+ labels: ["8E"]
2849
+ };
2731
2850
  }
2732
- if (data.length === 9) {
2733
- processRoute(decodeResult, data[3], data[1], data[5], data[4], void 0);
2734
- ResultFormatter.altitude(decodeResult, Number(data[2]) * 100);
2735
- ResultFormatter.temperature(decodeResult, data[6]);
2736
- ResultFormatter.unknown(decodeResult, data[7]);
2737
- ResultFormatter.unknown(decodeResult, data[8]);
2851
+ decode(message, options = {}) {
2852
+ const decodeResult = this.defaultResult();
2853
+ decodeResult.decoder.name = this.name;
2854
+ decodeResult.formatted.description = "ETA Report";
2855
+ decodeResult.message = message;
2856
+ const regex = /^(?<arrival_icao>\w{4}),(?<arrival_eta>\d{4})$/;
2857
+ const results = message.text.match(regex);
2858
+ if (results?.groups) {
2859
+ if (options.debug) {
2860
+ console.log(`Label 8E ETA: groups`);
2861
+ console.log(results.groups);
2862
+ }
2863
+ ResultFormatter.eta(decodeResult, DateTimeUtils.convertHHMMSSToTod(results.groups.arrival_eta + "00"));
2864
+ ResultFormatter.arrivalAirport(decodeResult, results.groups.arrival_icao);
2865
+ }
2866
+ decodeResult.decoded = true;
2867
+ decodeResult.decoder.decodeLevel = "full";
2868
+ return decodeResult;
2738
2869
  }
2739
- if (data.length === 14) {
2740
- ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2741
- processRoute(decodeResult, data[4], data[2], data[6], data[5], void 0);
2742
- ResultFormatter.temperature(decodeResult, data[7]);
2743
- ResultFormatter.groundspeed(decodeResult, Number(data[10]));
2744
- ResultFormatter.unknown(decodeResult, data[1]);
2745
- ResultFormatter.unknown(decodeResult, data[8]);
2746
- ResultFormatter.unknown(decodeResult, data[9]);
2747
- ResultFormatter.unknown(decodeResult, data.slice(11).join(","));
2870
+ };
2871
+
2872
+ // lib/plugins/Label_B6.ts
2873
+ var Label_B6_Forwardslash = class extends DecoderPlugin {
2874
+ name = "label-b6-forwardslash";
2875
+ qualifiers() {
2876
+ return {
2877
+ labels: ["B6"],
2878
+ preambles: ["/"]
2879
+ };
2748
2880
  }
2749
- }
2750
- function processPosition2(decodeResult, data) {
2751
- const position = CoordinateUtils.decodeStringCoordinatesDecimalMinutes(data[0]);
2752
- if (position) {
2753
- decodeResult.raw.position = position;
2754
- decodeResult.formatted.items.push({
2755
- type: "aircraft_position",
2756
- code: "POS",
2757
- label: "Aircraft Position",
2758
- value: CoordinateUtils.coordinateString(position)
2759
- });
2881
+ decode(message, options = {}) {
2882
+ const decodeResult = this.defaultResult();
2883
+ decodeResult.decoder.name = this.name;
2884
+ decodeResult.formatted.description = "CPDLC Message";
2885
+ decodeResult.message = message;
2886
+ if (options.debug) {
2887
+ console.log("CPDLC: " + message);
2888
+ }
2889
+ return decodeResult;
2760
2890
  }
2761
- if (data.length >= 10) {
2762
- ResultFormatter.altitude(decodeResult, Number(data[3]) * 100);
2763
- processRoute(decodeResult, data[1], data[2], data[4], data[5], data[6]);
2764
- ResultFormatter.temperature(decodeResult, data[7]);
2765
- ResultFormatter.unknown(decodeResult, data[8]);
2766
- ResultFormatter.unknown(decodeResult, data[9]);
2891
+ };
2892
+
2893
+ // lib/plugins/Label_ColonComma.ts
2894
+ var Label_ColonComma = class extends DecoderPlugin {
2895
+ name = "label-colon-comma";
2896
+ qualifiers() {
2897
+ return {
2898
+ labels: [":;"]
2899
+ };
2767
2900
  }
2768
- if (data.length >= 14) {
2769
- ResultFormatter.groundspeed(decodeResult, Number(data[10]));
2770
- ResultFormatter.unknown(decodeResult, data[11]);
2771
- ResultFormatter.unknown(decodeResult, data[12]);
2772
- ResultFormatter.unknown(decodeResult, data[13]);
2901
+ decode(message, options = {}) {
2902
+ const decodeResult = this.defaultResult();
2903
+ decodeResult.decoder.name = this.name;
2904
+ decodeResult.raw.frequency = Number(message.text) / 1e3;
2905
+ decodeResult.formatted.description = "Aircraft Transceiver Frequency Change";
2906
+ decodeResult.formatted.items.push({
2907
+ type: "frequency",
2908
+ label: "Frequency",
2909
+ value: `${decodeResult.raw.frequency} MHz`,
2910
+ code: "FREQ"
2911
+ });
2912
+ decodeResult.decoded = true;
2913
+ decodeResult.decoder.decodeLevel = "full";
2914
+ return decodeResult;
2773
2915
  }
2774
- }
2775
- function processRoute(decodeResult, last, time, next, eta, then, date) {
2776
- const lastTime = date ? DateTimeUtils.convertDateTimeToEpoch(time, date) : DateTimeUtils.convertHHMMSSToTod(time);
2777
- const nextTime = date ? DateTimeUtils.convertDateTimeToEpoch(eta, date) : DateTimeUtils.convertHHMMSSToTod(eta);
2778
- const timeFormat = date ? "epoch" : "tod";
2779
- const lastWaypoint = RouteUtils.getWaypoint(last);
2780
- lastWaypoint.time = lastTime;
2781
- lastWaypoint.timeFormat = timeFormat;
2782
- const nextWaypoint = RouteUtils.getWaypoint(next);
2783
- nextWaypoint.time = nextTime;
2784
- nextWaypoint.timeFormat = timeFormat;
2785
- const thenWaypoint = RouteUtils.getWaypoint(then || "?");
2786
- const waypoints = [lastWaypoint, nextWaypoint, thenWaypoint];
2787
- decodeResult.raw.route = { waypoints };
2788
- decodeResult.formatted.items.push({
2789
- type: "aircraft_route",
2790
- code: "ROUTE",
2791
- label: "Aircraft Route",
2792
- value: RouteUtils.routeToString(decodeResult.raw.route)
2793
- });
2794
- }
2916
+ };
2795
2917
 
2796
2918
  // lib/plugins/Label_H1.ts
2797
2919
  var Label_H1 = class extends DecoderPlugin {
@@ -2805,16 +2927,205 @@ var Label_H1 = class extends DecoderPlugin {
2805
2927
  let decodeResult = this.defaultResult();
2806
2928
  decodeResult.decoder.name = this.name;
2807
2929
  decodeResult.message = message;
2808
- decodeResult.remaining.text = "";
2809
2930
  const msg = message.text.replace(/\n|\r/g, "");
2810
2931
  const decoded = H1Helper.decodeH1Message(decodeResult, msg);
2811
2932
  decodeResult.decoded = decoded;
2812
- decodeResult.decoder.decodeLevel = decodeResult.remaining.text.length === 0 ? "full" : "partial";
2933
+ decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? "full" : "partial";
2813
2934
  if (decodeResult.formatted.items.length === 0) {
2814
2935
  if (options.debug) {
2815
2936
  console.log(`Decoder: Unknown H1 message: ${message.text}`);
2816
2937
  }
2817
- decodeResult.remaining.text = message.text;
2938
+ ResultFormatter.unknown(decodeResult, message.text);
2939
+ decodeResult.decoded = false;
2940
+ decodeResult.decoder.decodeLevel = "none";
2941
+ }
2942
+ return decodeResult;
2943
+ }
2944
+ };
2945
+
2946
+ // lib/plugins/Label_H1_FLR.ts
2947
+ var Label_H1_FLR = class extends DecoderPlugin {
2948
+ name = "label-h1-flr";
2949
+ qualifiers() {
2950
+ return {
2951
+ labels: ["H1"],
2952
+ preambles: ["FLR", "#CFBFLR"]
2953
+ };
2954
+ }
2955
+ decode(message, options = {}) {
2956
+ let decodeResult = this.defaultResult();
2957
+ decodeResult.decoder.name = this.name;
2958
+ decodeResult.formatted.description = "Fault Log Report";
2959
+ decodeResult.message = message;
2960
+ const parts = message.text.split("/FR");
2961
+ if (parts.length > 1) {
2962
+ const fields = parts[0].split("/");
2963
+ for (let i = 1; i < fields.length; i++) {
2964
+ const field = fields[i];
2965
+ ResultFormatter.unknown(decodeResult, field, "/");
2966
+ }
2967
+ const data = parts[1].substring(0, 20);
2968
+ const msg = parts[1].substring(20);
2969
+ const datetime = data.substring(0, 12);
2970
+ const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
2971
+ ResultFormatter.unknown(decodeResult, data.substring(12), "/");
2972
+ decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
2973
+ decodeResult.raw.fault_message = msg;
2974
+ decodeResult.formatted.items.push({
2975
+ type: "fault",
2976
+ code: "FR",
2977
+ label: "Fault Report",
2978
+ value: decodeResult.raw.fault_message
2979
+ });
2980
+ decodeResult.decoded = true;
2981
+ decodeResult.decoder.decodeLevel = "partial";
2982
+ } else {
2983
+ if (options.debug) {
2984
+ console.log(`Decoder: Unknown H1 message: ${message.text}`);
2985
+ }
2986
+ ResultFormatter.unknown(decodeResult, message.text);
2987
+ decodeResult.decoded = false;
2988
+ decodeResult.decoder.decodeLevel = "none";
2989
+ }
2990
+ return decodeResult;
2991
+ }
2992
+ };
2993
+
2994
+ // lib/plugins/Label_H1_OHMA.ts
2995
+ import * as zlib from "minizlib";
2996
+ var Label_H1_OHMA = class extends DecoderPlugin {
2997
+ name = "label-h1-ohma";
2998
+ qualifiers() {
2999
+ return {
3000
+ labels: ["H1"],
3001
+ preambles: ["OHMA", "/RTNBOCR.OHMA", "#T1B/RTNBOCR.OHMA"]
3002
+ };
3003
+ }
3004
+ decode(message, options = {}) {
3005
+ let decodeResult = this.defaultResult();
3006
+ decodeResult.decoder.name = this.name;
3007
+ decodeResult.formatted.description = "OHMA Message";
3008
+ decodeResult.message = message;
3009
+ const data = message.text.split("OHMA")[1];
3010
+ try {
3011
+ const compressedBuffer = Buffer.from(data, "base64");
3012
+ const decompress = new zlib.Inflate({ windowBits: 15 });
3013
+ decompress.write(compressedBuffer);
3014
+ decompress.flush(zlib.constants.Z_SYNC_FLUSH);
3015
+ const result = decompress.read();
3016
+ const jsonText = result.toString();
3017
+ let formattedMsg;
3018
+ let jsonMessage;
3019
+ try {
3020
+ jsonMessage = JSON.parse(jsonText).message;
3021
+ } catch {
3022
+ jsonMessage = jsonText;
3023
+ }
3024
+ try {
3025
+ const ohmaMsg = JSON.parse(jsonMessage);
3026
+ formattedMsg = JSON.stringify(ohmaMsg, null, 2);
3027
+ } catch {
3028
+ formattedMsg = jsonMessage;
3029
+ }
3030
+ decodeResult.decoded = true;
3031
+ decodeResult.decoder.decodeLevel = "full";
3032
+ decodeResult.raw.ohma = jsonText;
3033
+ decodeResult.formatted.items.push({
3034
+ type: "ohma",
3035
+ code: "OHMA",
3036
+ label: "OHMA Downlink",
3037
+ value: formattedMsg
3038
+ });
3039
+ } catch (e) {
3040
+ if (options.debug) {
3041
+ console.log(`Decoder: Unknown H1 OHMA message: ${message.text}`, e);
3042
+ }
3043
+ ResultFormatter.unknown(decodeResult, message.text);
3044
+ decodeResult.decoded = false;
3045
+ decodeResult.decoder.decodeLevel = "none";
3046
+ }
3047
+ return decodeResult;
3048
+ }
3049
+ };
3050
+
3051
+ // lib/plugins/Label_H1_StarPOS.ts
3052
+ var Label_H1_StarPOS = class extends DecoderPlugin {
3053
+ name = "label-h1-star-pos";
3054
+ qualifiers() {
3055
+ return {
3056
+ labels: ["H1"],
3057
+ preambles: ["*POS"]
3058
+ };
3059
+ }
3060
+ decode(message, options = {}) {
3061
+ let decodeResult = this.defaultResult();
3062
+ decodeResult.decoder.name = this.name;
3063
+ decodeResult.formatted.description = "Position Report";
3064
+ decodeResult.message = message;
3065
+ const msg = message.text;
3066
+ if (msg.length !== 43 || !msg.startsWith("*POS")) {
3067
+ if (options.debug) {
3068
+ console.log(`Decoder: Unknown H1 message: ${msg}`);
3069
+ }
3070
+ ResultFormatter.unknown(decodeResult, msg);
3071
+ decodeResult.decoded = false;
3072
+ decodeResult.decoder.decodeLevel = "none";
3073
+ return decodeResult;
3074
+ }
3075
+ decodeResult.raw.month = Number(msg.substring(4, 6));
3076
+ decodeResult.raw.day_of_month = Number(msg.substring(6, 8));
3077
+ ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(msg.substring(8, 12) + "00"));
3078
+ ResultFormatter.position(decodeResult, {
3079
+ // Deg Min, no sec
3080
+ latitude: CoordinateUtils.getDirection(msg.substring(12, 13)) * (Number(msg.substring(13, 15)) + Number(msg.substring(15, 17)) / 60),
3081
+ longitude: CoordinateUtils.getDirection(msg.substring(17, 18)) * (Number(msg.substring(18, 21)) + Number(msg.substring(21, 23)) / 60)
3082
+ });
3083
+ ResultFormatter.altitude(decodeResult, Number(msg.substring(23, 28)));
3084
+ ResultFormatter.unknown(decodeResult, msg.substring(28));
3085
+ decodeResult.decoded = true;
3086
+ decodeResult.decoder.decodeLevel = "partial";
3087
+ return decodeResult;
3088
+ }
3089
+ };
3090
+
3091
+ // lib/plugins/Label_H1_WRN.ts
3092
+ var Label_H1_WRN = class extends DecoderPlugin {
3093
+ name = "label-h1-wrn";
3094
+ qualifiers() {
3095
+ return {
3096
+ labels: ["H1"],
3097
+ preambles: ["WRN", "#CFBWRN"]
3098
+ };
3099
+ }
3100
+ decode(message, options = {}) {
3101
+ let decodeResult = this.defaultResult();
3102
+ decodeResult.decoder.name = this.name;
3103
+ decodeResult.formatted.description = "Warning Message";
3104
+ decodeResult.message = message;
3105
+ const parts = message.text.split("/WN");
3106
+ if (parts.length > 1) {
3107
+ const fields = parts[0].split("/");
3108
+ ResultFormatter.unknownArr(decodeResult, fields.slice(1), "/");
3109
+ const data = parts[1].substring(0, 20);
3110
+ const msg = parts[1].substring(20);
3111
+ const datetime = data.substring(0, 12);
3112
+ const date = datetime.substring(4, 6) + datetime.substring(2, 4) + datetime.substring(0, 2);
3113
+ ResultFormatter.unknown(decodeResult, data.substring(12), "/");
3114
+ decodeResult.raw.message_timestamp = DateTimeUtils.convertDateTimeToEpoch(datetime.substring(6), date);
3115
+ decodeResult.raw.warning_message = msg;
3116
+ decodeResult.formatted.items.push({
3117
+ type: "warning",
3118
+ code: "WRN",
3119
+ label: "Warning Message",
3120
+ value: decodeResult.raw.warning_message
3121
+ });
3122
+ decodeResult.decoded = true;
3123
+ decodeResult.decoder.decodeLevel = "partial";
3124
+ } else {
3125
+ if (options.debug) {
3126
+ console.log(`Decoder: Unknown H1 message: ${message.text}`);
3127
+ }
3128
+ ResultFormatter.unknown(decodeResult, message.text);
2818
3129
  decodeResult.decoded = false;
2819
3130
  decodeResult.decoder.decodeLevel = "none";
2820
3131
  }
@@ -2845,25 +3156,18 @@ var Label_HX = class extends DecoderPlugin {
2845
3156
  let londir = parts[4].substring(0, 1);
2846
3157
  let londeg = Number(parts[4].substring(1, 4));
2847
3158
  let lonmin = Number(parts[4].substring(4, 8));
2848
- decodeResult.raw.position = {
3159
+ let pos = {
2849
3160
  latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
2850
3161
  longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
2851
3162
  };
2852
- decodeResult.remaining.text = parts.slice(5).join(" ");
3163
+ ResultFormatter.unknownArr(decodeResult, parts.slice(5), " ");
3164
+ ResultFormatter.position(decodeResult, pos);
2853
3165
  } else if (parts[2] === "43") {
2854
3166
  ResultFormatter.departureAirport(decodeResult, parts[3]);
2855
- decodeResult.remaining.text = parts.slice(4).join(" ");
3167
+ ResultFormatter.unknownArr(decodeResult, parts.slice(4), " ");
2856
3168
  } else {
2857
3169
  decodeResult.decoded = false;
2858
3170
  }
2859
- if (decodeResult.raw.position) {
2860
- decodeResult.formatted.items.push({
2861
- type: "aircraft_position",
2862
- code: "POS",
2863
- label: "Aircraft Position",
2864
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
2865
- });
2866
- }
2867
3171
  if (decodeResult.decoded) {
2868
3172
  if (!decodeResult.remaining.text)
2869
3173
  decodeResult.decoder.decodeLevel = "full";
@@ -2893,7 +3197,7 @@ var Label_SQ = class extends DecoderPlugin {
2893
3197
  if (decodeResult.raw.version === "2") {
2894
3198
  const regex = /0(\d)X(?<org>\w)(?<iata>\w\w\w)(?<icao>\w\w\w\w)(?<station>\d)(?<lat>\d+)(?<latd>[NS])(?<lng>\d+)(?<lngd>[EW])V(?<vfreq>\d+)\/.*/;
2895
3199
  const result = message.text.match(regex);
2896
- if (result && result.length >= 8) {
3200
+ if (result?.groups && result.length >= 8) {
2897
3201
  decodeResult.raw.groundStation = {
2898
3202
  number: result.groups.station,
2899
3203
  iataCode: result.groups.iata,
@@ -2903,7 +3207,7 @@ var Label_SQ = class extends DecoderPlugin {
2903
3207
  longitude: Number(result.groups.lng) / 100 * (result.groups.lngd === "W" ? -1 : 1)
2904
3208
  }
2905
3209
  };
2906
- decodeResult.raw.vdlFrequency = result.groups.vfreq / 1e3;
3210
+ decodeResult.raw.vdlFrequency = Number(result.groups.vfreq) / 1e3;
2907
3211
  }
2908
3212
  }
2909
3213
  decodeResult.formatted.description = "Ground Station Squitter";
@@ -2994,31 +3298,11 @@ var Label_QR = class extends DecoderPlugin {
2994
3298
  decode(message, options = {}) {
2995
3299
  const decodeResult = this.defaultResult();
2996
3300
  decodeResult.decoder.name = this.name;
2997
- decodeResult.raw.origin = message.text.substring(0, 4);
2998
- decodeResult.raw.destination = message.text.substring(4, 8);
2999
- decodeResult.raw.wheels_on = message.text.substring(8, 12);
3000
- decodeResult.remaining.text = message.text.substring(12);
3001
3301
  decodeResult.formatted.description = "ON Report";
3002
- decodeResult.formatted.items = [
3003
- {
3004
- type: "origin",
3005
- code: "ORG",
3006
- label: "Origin",
3007
- value: decodeResult.raw.origin
3008
- },
3009
- {
3010
- type: "destination",
3011
- code: "DST",
3012
- label: "Destination",
3013
- value: decodeResult.raw.destination
3014
- },
3015
- {
3016
- type: "wheels_on",
3017
- code: "WON",
3018
- label: "Wheels ON",
3019
- value: decodeResult.raw.wheels_on
3020
- }
3021
- ];
3302
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3303
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3304
+ ResultFormatter.on(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3305
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
3022
3306
  decodeResult.decoded = true;
3023
3307
  if (!decodeResult.remaining.text)
3024
3308
  decodeResult.decoder.decodeLevel = "full";
@@ -3039,31 +3323,11 @@ var Label_QP = class extends DecoderPlugin {
3039
3323
  decode(message, options = {}) {
3040
3324
  const decodeResult = this.defaultResult();
3041
3325
  decodeResult.decoder.name = this.name;
3042
- decodeResult.raw.origin = message.text.substring(0, 4);
3043
- decodeResult.raw.destination = message.text.substring(4, 8);
3044
- decodeResult.raw.gate_out = message.text.substring(8, 12);
3045
- decodeResult.remaining.text = message.text.substring(12);
3046
3326
  decodeResult.formatted.description = "OUT Report";
3047
- decodeResult.formatted.items = [
3048
- {
3049
- type: "origin",
3050
- code: "ORG",
3051
- label: "Origin",
3052
- value: decodeResult.raw.origin
3053
- },
3054
- {
3055
- type: "destination",
3056
- code: "DST",
3057
- label: "Destination",
3058
- value: decodeResult.raw.destination
3059
- },
3060
- {
3061
- type: "gate_out",
3062
- code: "GOUT",
3063
- label: "Gate OUT",
3064
- value: decodeResult.raw.gate_out
3065
- }
3066
- ];
3327
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3328
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3329
+ ResultFormatter.out(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3330
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
3067
3331
  decodeResult.decoded = true;
3068
3332
  if (!decodeResult.remaining.text)
3069
3333
  decodeResult.decoder.decodeLevel = "full";
@@ -3084,31 +3348,11 @@ var Label_QS = class extends DecoderPlugin {
3084
3348
  decode(message, options = {}) {
3085
3349
  const decodeResult = this.defaultResult();
3086
3350
  decodeResult.decoder.name = this.name;
3087
- decodeResult.raw.origin = message.text.substring(0, 4);
3088
- decodeResult.raw.destination = message.text.substring(4, 8);
3089
- decodeResult.raw.gate_in = message.text.substring(8, 12);
3090
- decodeResult.remaining.text = message.text.substring(12);
3091
3351
  decodeResult.formatted.description = "IN Report";
3092
- decodeResult.formatted.items = [
3093
- {
3094
- type: "origin",
3095
- code: "ORG",
3096
- label: "Origin",
3097
- value: decodeResult.raw.origin
3098
- },
3099
- {
3100
- type: "destination",
3101
- code: "DST",
3102
- label: "Destination",
3103
- value: decodeResult.raw.destination
3104
- },
3105
- {
3106
- type: "gate_in",
3107
- code: "GIN",
3108
- label: "Gate IN",
3109
- value: decodeResult.raw.gate_in
3110
- }
3111
- ];
3352
+ ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3353
+ ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3354
+ ResultFormatter.in(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3355
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
3112
3356
  decodeResult.decoded = true;
3113
3357
  if (!decodeResult.remaining.text)
3114
3358
  decodeResult.decoder.decodeLevel = "full";
@@ -3133,43 +3377,30 @@ var Label_QQ = class extends DecoderPlugin {
3133
3377
  decodeResult.formatted.description = "OFF Report";
3134
3378
  ResultFormatter.departureAirport(decodeResult, message.text.substring(0, 4));
3135
3379
  ResultFormatter.arrivalAirport(decodeResult, message.text.substring(4, 8));
3136
- decodeResult.raw.wheels_off = message.text.substring(8, 12);
3137
3380
  if (message.text.substring(12, 19) === "\r\n001FE") {
3138
3381
  decodeResult.raw.day_of_month = message.text.substring(19, 21);
3139
- decodeResult.raw.wheels_off = message.text.substring(21, 27);
3382
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(21, 27)));
3140
3383
  let latdir = message.text.substring(27, 28);
3141
3384
  let latdeg = Number(message.text.substring(28, 30));
3142
3385
  let latmin = Number(message.text.substring(30, 34));
3143
3386
  let londir = message.text.substring(34, 35);
3144
3387
  let londeg = Number(message.text.substring(35, 38));
3145
3388
  let lonmin = Number(message.text.substring(38, 42));
3146
- decodeResult.raw.position = {
3389
+ let pos = {
3147
3390
  latitude: (latdeg + latmin / 60) * (latdir === "N" ? 1 : -1),
3148
3391
  longitude: (londeg + lonmin / 60) * (londir === "E" ? 1 : -1)
3149
3392
  };
3150
- decodeResult.remaining.text = message.text.substring(42, 45);
3393
+ ResultFormatter.unknown(decodeResult, message.text.substring(42, 45));
3394
+ ResultFormatter.position(decodeResult, pos);
3151
3395
  if (decodeResult.remaining.text !== "---") {
3152
- ResultFormatter.groundspeed(decodeResult, message.text.substring(45, 48));
3396
+ ResultFormatter.groundspeed(decodeResult, Number(message.text.substring(45, 48)));
3153
3397
  } else {
3154
3398
  ResultFormatter.unknown(decodeResult, message.text.substring(45, 48));
3155
3399
  }
3156
3400
  ResultFormatter.unknown(decodeResult, message.text.substring(48));
3157
3401
  } else {
3158
- decodeResult.remaining.text = message.text.substring(12);
3159
- }
3160
- decodeResult.formatted.items.push({
3161
- type: "wheels_off",
3162
- code: "WOFF",
3163
- label: "Wheels OFF",
3164
- value: decodeResult.raw.wheels_off
3165
- });
3166
- if (decodeResult.raw.position) {
3167
- decodeResult.formatted.items.push({
3168
- type: "aircraft_position",
3169
- code: "POS",
3170
- label: "Aircraft Position",
3171
- value: CoordinateUtils.coordinateString(decodeResult.raw.position)
3172
- });
3402
+ ResultFormatter.off(decodeResult, DateTimeUtils.convertHHMMSSToTod(message.text.substring(8, 12) + "00"));
3403
+ ResultFormatter.unknown(decodeResult, message.text.substring(12));
3173
3404
  }
3174
3405
  decodeResult.decoded = true;
3175
3406
  if (!decodeResult.remaining.text)
@@ -4001,8 +4232,14 @@ var MessageDecoder = class {
4001
4232
  this.registerPlugin(new Label_15(this));
4002
4233
  this.registerPlugin(new Label_15_FST(this));
4003
4234
  this.registerPlugin(new Label_16_N_Space(this));
4235
+ this.registerPlugin(new Label_1L_3Line(this));
4236
+ this.registerPlugin(new Label_1L_070(this));
4237
+ this.registerPlugin(new Label_1L_660(this));
4238
+ this.registerPlugin(new Label_1L_Slash(this));
4004
4239
  this.registerPlugin(new Label_20_POS(this));
4005
4240
  this.registerPlugin(new Label_21_POS(this));
4241
+ this.registerPlugin(new Label_22_OFF(this));
4242
+ this.registerPlugin(new Label_22_POS(this));
4006
4243
  this.registerPlugin(new Label_24_Slash(this));
4007
4244
  this.registerPlugin(new Label_30_Slash_EA(this));
4008
4245
  this.registerPlugin(new Label_44_ETA(this));
@@ -4015,12 +4252,14 @@ var MessageDecoder = class {
4015
4252
  this.registerPlugin(new Label_4A_DIS(this));
4016
4253
  this.registerPlugin(new Label_4A_DOOR(this));
4017
4254
  this.registerPlugin(new Label_4A_Slash_01(this));
4255
+ this.registerPlugin(new Label_4J_POS(this));
4018
4256
  this.registerPlugin(new Label_4N(this));
4019
4257
  this.registerPlugin(new Label_B6_Forwardslash(this));
4020
4258
  this.registerPlugin(new Label_H1_FLR(this));
4021
4259
  this.registerPlugin(new Label_H1_OHMA(this));
4022
4260
  this.registerPlugin(new Label_H1_WRN(this));
4023
4261
  this.registerPlugin(new Label_H1(this));
4262
+ this.registerPlugin(new Label_H1_StarPOS(this));
4024
4263
  this.registerPlugin(new Label_HX(this));
4025
4264
  this.registerPlugin(new Label_80(this));
4026
4265
  this.registerPlugin(new Label_83(this));